diff --git a/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch b/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch index 4d645a201..85f0a3b46 100644 --- a/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch +++ b/Moose Development/LDT External Tools/Moose DOCUMENTATION Generate.launch @@ -3,7 +3,6 @@ - - - + + diff --git a/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch b/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch index c55f6dd26..ffc89c77d 100644 --- a/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch +++ b/Moose Development/LDT External Tools/Moose LOADER Generate Dynamic Moose.lua.launch @@ -3,7 +3,7 @@ - + diff --git a/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch b/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch index 121638ba4..b8a402dc5 100644 --- a/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch +++ b/Moose Development/LDT External Tools/Moose LOADER Generate Static Moose.lua.launch @@ -3,7 +3,7 @@ - + diff --git a/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch b/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch index d959c8bf5..570f68b6e 100644 --- a/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch +++ b/Moose Development/LDT External Tools/Moose UPDATE ALL MOOSE Demonstration Missions.launch @@ -4,6 +4,5 @@ - - + diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index e047c76d1..018f2eb02 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -219,9 +219,9 @@ local _ClassID = 0 BASE = { ClassName = "BASE", ClassID = 0, - _Private = {}, Events = {}, - States = {} + States = {}, + _ = {}, } --- The Formation Class @@ -360,7 +360,7 @@ do -- Event Handling -- @param #BASE self -- @return #number The @{Event} processing Priority. function BASE:GetEventPriority() - return self._Private.EventPriority or 5 + return self._.EventPriority or 5 end --- Set the Class @{Event} processing Priority. @@ -370,7 +370,7 @@ do -- Event Handling -- @param #number EventPriority The @{Event} processing Priority. -- @return self function BASE:SetEventPriority( EventPriority ) - self._Private.EventPriority = EventPriority + self._.EventPriority = EventPriority end --- Remove all subscribed events diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 04f162690..0b3a3df6c 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -46,6 +46,7 @@ DATABASE = { Templates = { Units = {}, Groups = {}, + Statics = {}, ClientsByName = {}, ClientsByID = {}, }, @@ -318,7 +319,7 @@ function DATABASE:Spawn( SpawnTemplate ) SpawnTemplate.CountryID = nil SpawnTemplate.CategoryID = nil - self:_RegisterTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID ) + self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID ) self:T3( SpawnTemplate ) coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate ) @@ -354,7 +355,7 @@ end -- @param #DATABASE self -- @param #table GroupTemplate -- @return #DATABASE self -function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID ) +function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID ) local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name) @@ -432,6 +433,54 @@ function DATABASE:GetGroupTemplate( GroupName ) return GroupTemplate end +--- Private method that registers new Static Templates within the DATABASE Object. +-- @param #DATABASE self +-- @param #table GroupTemplate +-- @return #DATABASE self +function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID ) + + local TraceTable = {} + + local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name) + + self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {} + + StaticTemplate.CategoryID = CategoryID + StaticTemplate.CoalitionID = CoalitionID + StaticTemplate.CountryID = CountryID + + self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateName + self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate + self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1] + self.Templates.Statics[StaticTemplateName].CategoryID = CategoryID + self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID + self.Templates.Statics[StaticTemplateName].CountryID = CountryID + + + TraceTable[#TraceTable+1] = "Static" + TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].GroupName + + TraceTable[#TraceTable+1] = "Coalition" + TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID + TraceTable[#TraceTable+1] = "Category" + TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CategoryID + TraceTable[#TraceTable+1] = "Country" + TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CountryID + + self:E( TraceTable ) +end + + +--- @param #DATABASE self +function DATABASE:GetStaticUnitTemplate( StaticName ) + local StaticTemplate = self.Templates.Statics[StaticName].UnitTemplate + StaticTemplate.SpawnCoalitionID = self.Templates.Statics[StaticName].CoalitionID + StaticTemplate.SpawnCategoryID = self.Templates.Statics[StaticName].CategoryID + StaticTemplate.SpawnCountryID = self.Templates.Statics[StaticName].CountryID + return StaticTemplate +end + + function DATABASE:GetGroupNameFromUnitName( UnitName ) return self.Templates.Units[UnitName].GroupName end @@ -798,6 +847,7 @@ function DATABASE:OnEventDeleteCargo( EventData ) end +--- @param #DATABASE self function DATABASE:_RegisterTemplates() self:F2() @@ -853,11 +903,18 @@ function DATABASE:_RegisterTemplates() --self.Units[coa_name][countryName][category] = {} - for group_num, GroupTemplate in pairs(obj_type_data.group) do + for group_num, Template in pairs(obj_type_data.group) do - if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group - self:_RegisterTemplate( - GroupTemplate, + if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group + self:_RegisterGroupTemplate( + Template, + CoalitionSide, + _DATABASECategory[string.lower(CategoryName)], + CountryID + ) + else + self:_RegisterStaticTemplate( + Template, CoalitionSide, _DATABASECategory[string.lower(CategoryName)], CountryID diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 7234188a9..9891aa5fd 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -235,7 +235,7 @@ EVENTS = { -- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event: -- -- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event. --- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ +-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ -- -- @type EVENTDATA -- @field #number id The identifier of the event. @@ -280,116 +280,139 @@ EVENTS = { local _EVENTMETA = { [world.event.S_EVENT_SHOT] = { Order = 1, + Side = "I", Event = "OnEventShot", Text = "S_EVENT_SHOT" }, [world.event.S_EVENT_HIT] = { Order = 1, + Side = "T", Event = "OnEventHit", Text = "S_EVENT_HIT" }, [world.event.S_EVENT_TAKEOFF] = { Order = 1, + Side = "I", Event = "OnEventTakeoff", Text = "S_EVENT_TAKEOFF" }, [world.event.S_EVENT_LAND] = { Order = 1, + Side = "I", Event = "OnEventLand", Text = "S_EVENT_LAND" }, [world.event.S_EVENT_CRASH] = { Order = -1, + Side = "I", Event = "OnEventCrash", Text = "S_EVENT_CRASH" }, [world.event.S_EVENT_EJECTION] = { Order = 1, + Side = "I", Event = "OnEventEjection", Text = "S_EVENT_EJECTION" }, [world.event.S_EVENT_REFUELING] = { Order = 1, + Side = "I", Event = "OnEventRefueling", Text = "S_EVENT_REFUELING" }, [world.event.S_EVENT_DEAD] = { Order = -1, + Side = "I", Event = "OnEventDead", Text = "S_EVENT_DEAD" }, [world.event.S_EVENT_PILOT_DEAD] = { Order = 1, + Side = "I", Event = "OnEventPilotDead", Text = "S_EVENT_PILOT_DEAD" }, [world.event.S_EVENT_BASE_CAPTURED] = { Order = 1, + Side = "I", Event = "OnEventBaseCaptured", Text = "S_EVENT_BASE_CAPTURED" }, [world.event.S_EVENT_MISSION_START] = { Order = 1, + Side = "N", Event = "OnEventMissionStart", Text = "S_EVENT_MISSION_START" }, [world.event.S_EVENT_MISSION_END] = { Order = 1, + Side = "N", Event = "OnEventMissionEnd", Text = "S_EVENT_MISSION_END" }, [world.event.S_EVENT_TOOK_CONTROL] = { Order = 1, + Side = "N", Event = "OnEventTookControl", Text = "S_EVENT_TOOK_CONTROL" }, [world.event.S_EVENT_REFUELING_STOP] = { Order = 1, + Side = "I", Event = "OnEventRefuelingStop", Text = "S_EVENT_REFUELING_STOP" }, [world.event.S_EVENT_BIRTH] = { Order = 1, + Side = "I", Event = "OnEventBirth", Text = "S_EVENT_BIRTH" }, [world.event.S_EVENT_HUMAN_FAILURE] = { Order = 1, + Side = "I", Event = "OnEventHumanFailure", Text = "S_EVENT_HUMAN_FAILURE" }, [world.event.S_EVENT_ENGINE_STARTUP] = { Order = 1, + Side = "I", Event = "OnEventEngineStartup", Text = "S_EVENT_ENGINE_STARTUP" }, [world.event.S_EVENT_ENGINE_SHUTDOWN] = { Order = 1, + Side = "I", Event = "OnEventEngineShutdown", Text = "S_EVENT_ENGINE_SHUTDOWN" }, [world.event.S_EVENT_PLAYER_ENTER_UNIT] = { Order = 1, + Side = "I", Event = "OnEventPlayerEnterUnit", Text = "S_EVENT_PLAYER_ENTER_UNIT" }, [world.event.S_EVENT_PLAYER_LEAVE_UNIT] = { Order = -1, + Side = "I", Event = "OnEventPlayerLeaveUnit", Text = "S_EVENT_PLAYER_LEAVE_UNIT" }, [world.event.S_EVENT_PLAYER_COMMENT] = { Order = 1, + Side = "I", Event = "OnEventPlayerComment", Text = "S_EVENT_PLAYER_COMMENT" }, [world.event.S_EVENT_SHOOTING_START] = { Order = 1, + Side = "I", Event = "OnEventShootingStart", Text = "S_EVENT_SHOOTING_START" }, [world.event.S_EVENT_SHOOTING_END] = { Order = 1, + Side = "I", Event = "OnEventShootingEnd", Text = "S_EVENT_SHOOTING_END" }, @@ -417,13 +440,6 @@ function EVENT:New() return self end -function EVENT:EventText( EventID ) - - local EventText = _EVENTMETA[EventID].Text - - return EventText -end - --- Initializes the Events structure for the event -- @param #EVENT self @@ -435,7 +451,7 @@ function EVENT:Init( EventID, EventClass ) if not self.Events[EventID] then -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. - self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) + self.Events[EventID] = {} end -- Each event has a subtable of EventClasses, ordered by EventPriority. @@ -445,53 +461,56 @@ function EVENT:Init( EventID, EventClass ) end if not self.Events[EventID][EventPriority][EventClass] then - self.Events[EventID][EventPriority][EventClass] = setmetatable( {}, { __mode = "v" } ) + self.Events[EventID][EventPriority][EventClass] = {} end return self.Events[EventID][EventPriority][EventClass] end ---- Removes an Events entry +--- Removes a subscription -- @param #EVENT self -- @param Core.Base#BASE EventClass The self instance of the class for which the event is. -- @param Dcs.DCSWorld#world.event EventID -- @return #EVENT.Events function EVENT:Remove( EventClass, EventID ) - self:F3( { EventClass, _EVENTMETA[EventID].Text } ) - local EventClass = EventClass + self:E( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } ) + local EventPriority = EventClass:GetEventPriority() + + self.EventsDead = self.EventsDead or {} + self.EventsDead[EventID] = self.EventsDead[EventID] or {} + self.EventsDead[EventID][EventPriority] = self.EventsDead[EventID][EventPriority] or {} + self.EventsDead[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass] + self.Events[EventID][EventPriority][EventClass] = nil + end ---- Removes an Events entry for a UNIT. +--- Resets subscriptions -- @param #EVENT self --- @param #string UnitName The name of the UNIT. -- @param Core.Base#BASE EventClass The self instance of the class for which the event is. -- @param Dcs.DCSWorld#world.event EventID -- @return #EVENT.Events -function EVENT:RemoveForUnit( UnitName, EventClass, EventID ) - self:F3( { EventClass, _EVENTMETA[EventID].Text } ) +function EVENT:Reset( EventObject ) - local EventClass = EventClass - local EventPriority = EventClass:GetEventPriority() - local Event = self.Events[EventID][EventPriority][EventClass] - Event.EventUnit[UnitName] = nil + self:E( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } ) + + local EventPriority = EventObject:GetEventPriority() + for EventID, EventData in pairs( self.Events ) do + if self.EventsDead then + if self.EventsDead[EventID] then + if self.EventsDead[EventID][EventPriority] then + if self.EventsDead[EventID][EventPriority][EventObject] then + self.Events[EventID][EventPriority][EventObject] = self.EventsDead[EventID][EventPriority][EventObject] + end + end + end + end + end end ---- Removes an Events entry for a GROUP. --- @param #EVENT self --- @param #string GroupName The name of the GROUP. --- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param Dcs.DCSWorld#world.event EventID --- @return #EVENT.Events -function EVENT:RemoveForGroup( GroupName, EventClass, EventID ) - self:F3( { EventClass, _EVENTMETA[EventID].Text } ) - local EventClass = EventClass - local EventPriority = EventClass:GetEventPriority() - local Event = self.Events[EventID][EventPriority][EventClass] - Event.EventGroup[GroupName] = nil -end + --- Clears all event subscriptions for a @{Base#BASE} derived object. -- @param #EVENT self @@ -535,7 +554,6 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID ) local EventData = self:Init( EventID, EventClass ) EventData.EventFunction = EventFunction - EventData.EventClass = EventClass return self end @@ -552,12 +570,8 @@ function EVENT:OnEventForUnit( UnitName, EventFunction, EventClass, EventID ) self:F2( UnitName ) local EventData = self:Init( EventID, EventClass ) - if not EventData.EventUnit then - EventData.EventUnit = {} - end - EventData.EventUnit[UnitName] = {} - EventData.EventUnit[UnitName].EventFunction = EventFunction - EventData.EventUnit[UnitName].EventClass = EventClass + EventData.EventUnit = true + EventData.EventFunction = EventFunction return self end @@ -572,12 +586,8 @@ function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID ) self:F2( GroupName ) local Event = self:Init( EventID, EventClass ) - if not Event.EventGroup then - Event.EventGroup = {} - end - Event.EventGroup[GroupName] = {} - Event.EventGroup[GroupName].EventFunction = EventFunction - Event.EventGroup[GroupName].EventClass = EventClass + Event.EventGroup = true + Event.EventFunction = EventFunction return self end @@ -736,10 +746,10 @@ function EVENT:onEvent( Event ) return errmsg end - self:E( _EVENTMETA[Event.id].Text, Event ) + + local EventMeta = _EVENTMETA[Event.id] if self and self.Events and self.Events[Event.id] then - if Event.initiator then @@ -849,12 +859,12 @@ function EVENT:onEvent( Event ) Event.CargoName = Event.cargo.Name end - local PriorityOrder = _EVENTMETA[Event.id].Order + local PriorityOrder = EventMeta.Order local PriorityBegin = PriorityOrder == -1 and 5 or 1 local PriorityEnd = PriorityOrder == -1 and 1 or 5 if Event.IniObjectCategory ~= 3 then - self:E( { _EVENTMETA[Event.id].Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } ) + self:E( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } ) end for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do @@ -864,187 +874,144 @@ function EVENT:onEvent( Event ) -- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do + self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } ) + Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName ) -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. - if ( Event.IniDCSUnitName and EventData.EventUnit and EventData.EventUnit[Event.IniDCSUnitName] ) or - ( Event.TgtDCSUnitName and EventData.EventUnit and EventData.EventUnit[Event.TgtDCSUnitName] ) then + if EventData.EventUnit then - if EventData.EventUnit[Event.IniDCSUnitName] then - - -- First test if a EventFunction is Set, otherwise search for the default function - if EventData.EventUnit[Event.IniDCSUnitName].EventFunction then + -- So now the EventClass must be a UNIT class!!! We check if it is still "Alive". + if EventClass:IsAlive() or + Event.id == EVENTS.Crash or + Event.id == EVENTS.Dead then - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) - end - - local Result, Value = xpcall( - function() - return EventData.EventUnit[Event.IniDCSUnitName].EventFunction( EventClass, Event ) - end, ErrorHandler ) - - else - - -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. - local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] - if EventFunction and type( EventFunction ) == "function" then - - -- Now call the default event function. + local UnitName = EventClass:GetName() + + if ( EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName ) or + ( EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName ) then + + -- First test if a EventFunction is Set, otherwise search for the default function + if EventData.EventFunction then + if Event.IniObjectCategory ~= 3 then - self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) end - + local Result, Value = xpcall( function() - return EventFunction( EventClass, Event ) + return EventData.EventFunction( EventClass, Event ) end, ErrorHandler ) - end - end - end - - if EventData.EventUnit[Event.TgtDCSUnitName] then - - -- First test if a EventFunction is Set, otherwise search for the default function - if EventData.EventUnit[Event.TgtDCSUnitName].EventFunction then - - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.TgtUnitName, EventPriority } ) - end - - local Result, Value = xpcall( - function() - return EventData.EventUnit[Event.TgtDCSUnitName].EventFunction( EventClass, Event ) - end, ErrorHandler ) - - else - - -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. - local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] - if EventFunction and type( EventFunction ) == "function" then - - -- Now call the default event function. - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ EventMeta.Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event ) + end, ErrorHandler ) end - - local Result, Value = xpcall( - function() - return EventFunction( EventClass, Event ) - end, ErrorHandler ) end end - end - + else + -- The EventClass is not alive anymore, we remove it from the EventHandlers... + self:Remove( EventClass, Event.id ) + end else -- If the EventData is for a GROUP, the call directly the EventClass EventFunction for the UNIT in that GROUP. - if ( Event.IniDCSUnitName and Event.IniDCSGroupName and Event.IniGroupName and EventData.EventGroup and EventData.EventGroup[Event.IniGroupName] ) or - ( Event.TgtDCSUnitName and Event.TgtDCSGroupName and Event.TgtGroupName and EventData.EventGroup and EventData.EventGroup[Event.TgtGroupName] ) then + if EventData.EventGroup then - if EventData.EventGroup[Event.IniGroupName] then - -- First test if a EventFunction is Set, otherwise search for the default function - if EventData.EventGroup[Event.IniGroupName].EventFunction then + -- So now the EventClass must be a GROUP class!!! We check if it is still "Alive". + if EventClass:IsAlive() or + Event.id == EVENTS.Crash or + Event.id == EVENTS.Dead then - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) - end - - local Result, Value = xpcall( - function() - return EventData.EventGroup[Event.IniGroupName].EventFunction( EventClass, Event ) - end, ErrorHandler ) - - else - - -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. - local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] - if EventFunction and type( EventFunction ) == "function" then - - -- Now call the default event function. - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) - end - - local Result, Value = xpcall( - function() - return EventFunction( EventClass, Event ) - end, ErrorHandler ) - end - end - end + -- We can get the name of the EventClass, which is now always a GROUP object. + local GroupName = EventClass:GetName() + + if ( EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName ) or + ( EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName ) then - if EventData.EventGroup[Event.TgtGroupName] then - if EventData.EventGroup[Event.TgtGroupName].EventFunction then - - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.TgtUnitName, EventPriority } ) - end - - local Result, Value = xpcall( - function() - return EventData.EventGroup[Event.TgtGroupName].EventFunction( EventClass, Event ) - end, ErrorHandler ) - - else - - -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. - local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] - if EventFunction and type( EventFunction ) == "function" then - - -- Now call the default event function. - if Event.IniObjectCategory ~= 3 then - self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) - end - - local Result, Value = xpcall( - function() - return EventFunction( EventClass, Event ) - end, ErrorHandler ) - end - end - end - - else - - -- If the EventData is not bound to a specific unit, then call the EventClass EventFunction. - -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. - if ( ( Event.IniDCSUnit or Event.WeaponUNIT) and not EventData.EventUnit ) or - Event.Cargo then - - if EventClass == EventData.EventClass then - -- First test if a EventFunction is Set, otherwise search for the default function if EventData.EventFunction then - - -- There is an EventFunction defined, so call the EventFunction. + if Event.IniObjectCategory ~= 3 then - self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) - end + self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) + end + local Result, Value = xpcall( function() return EventData.EventFunction( EventClass, Event ) end, ErrorHandler ) + else - + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. - local EventFunction = EventClass[ _EVENTMETA[Event.id].Event ] + local EventFunction = EventClass[ EventMeta.Event ] if EventFunction and type( EventFunction ) == "function" then -- Now call the default event function. if Event.IniObjectCategory ~= 3 then - self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + self:E( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) end - + local Result, Value = xpcall( function() - local Result, Value = EventFunction( EventClass, Event ) - return Result, Value + return EventFunction( EventClass, Event ) end, ErrorHandler ) end end end + else + -- The EventClass is not alive anymore, we remove it from the EventHandlers... + self:Remove( EventClass, Event.id ) + end + else + + -- If the EventData is not bound to a specific unit, then call the EventClass EventFunction. + -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. + if not EventData.EventUnit then + + -- First test if a EventFunction is Set, otherwise search for the default function + if EventData.EventFunction then + + -- There is an EventFunction defined, so call the EventFunction. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + local Result, Value = xpcall( + function() + return EventData.EventFunction( EventClass, Event ) + end, ErrorHandler ) + else + + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. + local EventFunction = EventClass[ EventMeta.Event ] + if EventFunction and type( EventFunction ) == "function" then + + -- Now call the default event function. + if Event.IniObjectCategory ~= 3 then + self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + end + + local Result, Value = xpcall( + function() + local Result, Value = EventFunction( EventClass, Event ) + return Result, Value + end, ErrorHandler ) + end + end + end end end @@ -1052,7 +1019,7 @@ function EVENT:onEvent( Event ) end end else - self:E( { _EVENTMETA[Event.id].Text, Event } ) + self:E( { EventMeta.Text, Event } ) end Event = nil diff --git a/Moose Development/Moose/Core/Radio.lua b/Moose Development/Moose/Core/Radio.lua index 38735de28..890474ed3 100644 --- a/Moose Development/Moose/Core/Radio.lua +++ b/Moose Development/Moose/Core/Radio.lua @@ -1,6 +1,6 @@ --- **Core** - The RADIO class is responsible for **transmitting radio communications**. -- --- --- bitmap +-- ![Banner Image](..\Presentations\RADIO\Dia1.JPG) -- -- === -- @@ -27,19 +27,20 @@ -- -- === -- --- ### Authors: Hugues "Grey_Echo" Bousquet +-- ### Author: Hugues "Grey_Echo" Bousquet -- -- @module Radio + --- # 1) RADIO class, extends @{Base#BASE} -- -- ## 1.1) RADIO usage -- -- There are 3 steps to a successful radio transmission. -- --- * First, you need to **"add" a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function, +-- * First, you need to **"add a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function, -- * Then, you will **set the relevant parameters** to the transmission (see below), --- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{Positionable#POSITIONABLE.Broadcast}() function. +-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function. -- -- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Group#GROUP} or any other @{Positionable#POSITIONABLE} -- @@ -53,7 +54,7 @@ -- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration, -- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call -- --- Additional Methods to set relevant parameters if the transmiter is any other @{Wrapper.Positionable#POSITIONABLE} +-- Additional Methods to set relevant parameters if the transmiter is any other @{Positionable#POSITIONABLE} -- -- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts -- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call @@ -68,7 +69,7 @@ -- * Note that if the transmission has a subtitle, it will be readable, regardless of the quality of the transmission. -- -- @type RADIO --- @field Wrapper.Positionable#POSITIONABLE Positionable The transmiter +-- @field Positionable#POSITIONABLE Positionable The transmiter -- @field #string FileName Name of the sound file -- @field #number Frequency Frequency of the transmission in Hz -- @field #number Modulation Modulation of the transmission (either radio.modulation.AM or radio.modulation.FM) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 3b4c5e237..d6e7c9caa 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1374,7 +1374,7 @@ function SET_UNIT:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ... --- @param Core.Zone#ZONE_BASE ZoneObject -- @param Wrapper.Unit#UNIT UnitObject function( ZoneObject, UnitObject ) - if UnitObject:IsCompletelyInZone( ZoneObject ) then + if UnitObject:IsInZone( ZoneObject ) then return true else return false diff --git a/Moose Development/Moose/Core/SpawnStatic.lua b/Moose Development/Moose/Core/SpawnStatic.lua new file mode 100644 index 000000000..ed2493c8c --- /dev/null +++ b/Moose Development/Moose/Core/SpawnStatic.lua @@ -0,0 +1,177 @@ +--- **Core** -- Spawn dynamically new STATICs in your missions. +-- +-- ![Banner Image](..\Presentations\SPAWNSTATIC\Dia1.JPG) +-- +-- ==== +-- +-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [SPAWNSTATIC Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPS - Spawning Statics) +-- +-- ### [SPAWNSTATIC Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPS%20-%20Spawning%20Statics) +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [SPAWNSTATIC YouTube Channel]() +-- +-- ==== +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- ### Authors: +-- +-- * **FlightControl**: Design & Programming +-- +-- @module SpawnStatic + + + +--- @type SPAWNSTATIC +-- @extends Core.Base#BASE + + +--- # SPAWNSTATIC class, extends @{Base#BASE} +-- +-- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s. +-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), +-- SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy" +-- these properties to create a new static object and place it at the desired coordinate. +-- +-- New spawned @{Static}s get **the same name** as the name of the template Static, +-- or gets the given name when a new name is provided at the Spawn method. +-- By default, spawned @{Static}s will follow a naming convention at run-time: +-- +-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, +-- and _nnn_ is a **counter from 0 to 99999**. +-- +-- +-- ## SPAWNSTATIC construction methods +-- +-- Create a new SPAWNSTATIC object with the @{#SPAWNSTATIC.NewFromStatic}(): +-- +-- * @{#SPAWNSTATIC.NewFromStatic}(): Creates a new SPAWNSTATIC object given a name that is used as the base of the naming of each spawned Static. +-- +-- ## **Spawn** methods +-- +-- Groups can be spawned at different times and methods: +-- +-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(): Spawn a new group from a POINT_VEC2 coordinate. +-- (The group will be spawned at land height ). +-- * @{#SPAWNSTATIC.SpawnFromZone}(): Spawn a new group in a @{Zone}. +-- +-- @field #SPAWNSTATIC SPAWNSTATIC +-- +SPAWNSTATIC = { + ClassName = "SPAWNSTATIC", +} + + +--- @type SPAWNSTATIC.SpawnZoneTable +-- @list SpawnZone + + +--- Creates the main object to spawn a @{Static} defined in the ME. +-- @param #SPAWNSTATIC self +-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. +-- @return #SPAWNSTATIC +function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) + local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC + self:F( { SpawnTemplatePrefix } ) + + local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix ) + if TemplateStatic then + self.SpawnTemplatePrefix = SpawnTemplatePrefix + self.CountryID = CountryID + self.SpawnIndex = 0 + else + error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) + end + + self:SetEventPriority( 5 ) + + return self +end + +--- Creates the main object to spawn a @{Static} based on a type name. +-- @param #SPAWNSTATIC self +-- @param #string SpawnTypeName is the name of the type. +-- @return #SPAWNSTATIC +function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, CountryID ) + local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC + self:F( { SpawnTypeName } ) + + self.SpawnTypeName = SpawnTypeName + self.CountryID = CountryID + self.SpawnIndex = 0 + + self:SetEventPriority( 5 ) + + return self +end + + +--- Creates a new @{Static} from a POINT_VEC2. +-- @param #SPAWNSTATIC self +-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static. +-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360. +-- @param #string (optional) The name of the new static. +-- @return #SPAWNSTATIC +function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) + self:F( { PointVec2, Heading, NewName } ) + + local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID] + + local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix ) + + StaticTemplate.x = PointVec2:GetLat() + StaticTemplate.y = PointVec2:GetLon() + + StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex ) + StaticTemplate.heading = ( Heading / 180 ) * math.pi + + StaticTemplate.CountryID = nil + StaticTemplate.CoalitionID = nil + StaticTemplate.CategoryID = nil + + local Static = coalition.addStaticObject( self.CountryID, StaticTemplate ) + + self.SpawnIndex = self.SpawnIndex + 1 + + return Static +end + +--- Creates a new @{Static} from a @{Zone}. +-- @param #SPAWNSTATIC self +-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static. +-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360. +-- @param #string (optional) The name of the new static. +-- @return #SPAWNSTATIC +function SPAWNSTATIC:SpawnFromZone( Zone, Heading, NewName ) + self:F( { Zone, Heading, NewName } ) + + local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName ) + + return Static +end + diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 15d3efd4c..004d93c59 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -7,8 +7,25 @@ -- DETECTION classes facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnassance Units). -- DETECTION uses the in-built detection capabilities of DCS World, but adds new functionalities. -- --- Please watch this [youtube video](https://youtu.be/C7p81dUwP-E) that explains the detection concepts. +-- Find the DETECTION classes documentation further in this document in the globals section. -- +-- ==== +-- +-- # Demo Missions +-- +-- ### [DETECTION Demo Missions and Source Code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/DET%20-%20Detection) +-- +-- ### [DETECTION Demo Missions, only for Beta Testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/DET%20-%20Detection) +-- +-- ### [ALL Demo Missions pack of the Latest Release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [DETECTION YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3Cf5jpI6BS0sBOVWK__tji) +-- +-- ==== -- -- ### Contributions: -- @@ -23,16 +40,24 @@ do -- DETECTION_BASE - --- # 1) DETECTION_BASE class, extends @{Fsm#FSM} + --- @type DETECTION_BASE + -- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. + -- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. + -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. + -- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. + -- @field #number DetectionRun + -- @extends Core.Fsm#FSM + + --- DETECTION_BASE class, extends @{Fsm#FSM} -- -- The DETECTION_BASE class defines the core functions to administer detected objects. -- The DETECTION_BASE class will detect objects within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s). -- - -- ## 1.1) DETECTION_BASE constructor + -- ## DETECTION_BASE constructor -- -- Construct a new DETECTION_BASE instance using the @{#DETECTION_BASE.New}() method. -- - -- ## 1.2) DETECTION_BASE initialization + -- ## Initialization -- -- By default, detection will return detected objects with all the detection sensors available. -- However, you can ask how the objects were found with specific detection methods. @@ -48,7 +73,29 @@ do -- DETECTION_BASE -- * @{#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. -- * @{#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. -- - -- ## 1.3) DETECTION_BASE derived classes group the detected units into a DetectedItems[] list + -- ## **Filter** detected units based on **category of the unit** + -- + -- Filter the detected units based on Unit.Category using the method @{#DETECTION_BASE.FilterCategories}(). + -- The different values of Unit.Category can be: + -- + -- * Unit.Category.AIRPLANE + -- * Unit.Category.GROUND_UNIT + -- * Unit.Category.HELICOPTER + -- * Unit.Category.SHIP + -- * Unit.Category.STRUCTURE + -- + -- Multiple Unit.Category entries can be given as a table and then these will be evaluated as an OR expression. + -- + -- Example to filter a single category (Unit.Category.AIRPLANE). + -- + -- DetectionObject:FilterCategories( Unit.Category.AIRPLANE ) + -- + -- Example to filter multiple categories (Unit.Category.AIRPLANE, Unit.Category.HELICOPTER). Note the {}. + -- + -- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) + -- + -- + -- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list -- -- DETECTION_BASE derived classes build a list called DetectedItems[], which is essentially a first later -- of grouping of detected units. Each DetectedItem within the DetectedItems[] list contains @@ -67,7 +114,7 @@ do -- DETECTION_BASE -- * A DetectedSet from the DetectedItems[] list can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedSet}( DetectedItemIndex ). -- This method retrieves the Set from a DetectedItem element from the DetectedItem list (DetectedItems[ DetectedItemIndex ].Set ). -- - -- ## 1.4) Apply additional Filters to fine-tune the detected objects + -- ## **Visual filters** to fine-tune the probability of the detected objects -- -- By default, DCS World will return any object that is in LOS and within "visual reach", or detectable through one of the electronic detection means. -- That being said, the DCS World detection algorithm can sometimes be unrealistic. @@ -88,7 +135,8 @@ do -- DETECTION_BASE -- I advise however, that, when you first use the DETECTION derived classes, that you don't use these filters. -- Only when you experience unrealistic behaviour in your missions, these filters could be applied. -- - -- ### 1.4.1 ) Distance visual detection probability + -- + -- ### Distance visual detection probability -- -- Upon a **visual** detection, the further away a detected object is, the less likely it is to be detected properly. -- Also, the speed of accurate detection plays a role. @@ -102,7 +150,7 @@ do -- DETECTION_BASE -- -- Use the method @{Detection#DETECTION_BASE.SetDistanceProbability}() to set the probability factor upon a 10 km distance. -- - -- ### 1.4.2 ) Alpha Angle visual detection probability + -- ### Alpha Angle visual detection probability -- -- Upon a **visual** detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly. -- A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct. @@ -114,7 +162,7 @@ do -- DETECTION_BASE -- -- Use the method @{Detection#DETECTION_BASE.SetAlphaAngleProbability}() to set the probability factor if 0°. -- - -- ### 1.4.3 ) Cloudy Zones detection probability + -- ### Cloudy Zones detection probability -- -- Upon a **visual** detection, the more a detected unit is within a cloudy zone, the less likely the detected unit is to be detected successfully. -- The Cloudy Zones work with the ZONE_BASE derived classes. The mission designer can define within the mission @@ -129,12 +177,12 @@ do -- DETECTION_BASE -- Typically, this kind of filter would be applied for very specific areas were a detection needs to be very realisting for -- AI not to detect so easily targets within a forrest or village rich area. -- - -- ## 1.5 ) Accept / Reject detected units + -- ## Accept / Reject detected units -- -- DETECTION_BASE can accept or reject successful detections based on the location of the detected object, -- if it is located in range or located inside or outside of specific zones. -- - -- ### 1.5.1 ) Detection acceptance of within range limit + -- ### Detection acceptance of within range limit -- -- A range can be set that will limit a successful detection for a unit. -- Use the method @{Detection#DETECTION_BASE.SetAcceptRange}() to apply a range in meters till where detected units will be accepted. @@ -151,7 +199,7 @@ do -- DETECTION_BASE -- Detection:Start() -- -- - -- ### 1.5.2 ) Detection acceptance if within zone(s). + -- ### Detection acceptance if within zone(s). -- -- Specific ZONE_BASE object(s) can be given as a parameter, which will only accept a detection if the unit is within the specified ZONE_BASE object(s). -- Use the method @{Detection#DETECTION_BASE.SetAcceptZones}() will accept detected units if they are within the specified zones. @@ -171,7 +219,7 @@ do -- DETECTION_BASE -- -- Start the Detection. -- Detection:Start() -- - -- ### 1.5.3 ) Detection rejectance if within zone(s). + -- ### Detection rejectance if within zone(s). -- -- Specific ZONE_BASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONE_BASE object(s). -- Use the method @{Detection#DETECTION_BASE.SetRejectZones}() will reject detected units if they are within the specified zones. @@ -192,29 +240,24 @@ do -- DETECTION_BASE -- -- Start the Detection. -- Detection:Start() -- - -- ## 1.6) DETECTION_BASE is a Finite State Machine + -- ## DETECTION_BASE is a Finite State Machine -- -- Various Events and State Transitions can be tailored using DETECTION_BASE. -- - -- ### 1.6.1) DETECTION_BASE States + -- ### DETECTION_BASE States -- -- * **Detecting**: The detection is running. -- * **Stopped**: The detection is stopped. -- - -- ### 1.6.2) DETECTION_BASE Events + -- ### DETECTION_BASE Events -- -- * **Start**: Start the detection process. -- * **Detect**: Detect new units. -- * **Detected**: New units have been detected. -- * **Stop**: Stop the detection process. + -- + -- @field #DETECTION_BASE DETECTION_BASE -- - -- @type DETECTION_BASE - -- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. - -- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. - -- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. - -- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. - -- @field #number DetectionRun - -- @extends Core.Fsm#FSM DETECTION_BASE = { ClassName = "DETECTION_BASE", DetectionSetGroup = nil, @@ -267,11 +310,19 @@ do -- DETECTION_BASE self.DetectionInterval = 30 self:InitDetectVisual( true ) - self:InitDetectOptical( false ) - self:InitDetectRadar( false ) - self:InitDetectRWR( false ) - self:InitDetectIRST( false ) - self:InitDetectDLINK( false ) + self:InitDetectOptical( true ) + self:InitDetectRadar( true ) + self:InitDetectRWR( true ) + self:InitDetectIRST( true ) + self:InitDetectDLINK( true ) + + self:FilterCategories( { + Unit.Category.AIRPLANE, + Unit.Category.GROUND_UNIT, + Unit.Category.HELICOPTER, + Unit.Category.SHIP, + Unit.Category.STRUCTURE + } ) -- Create FSM transitions. @@ -498,9 +549,8 @@ do -- DETECTION_BASE for DetectionObjectID, Detection in pairs( DetectedTargets ) do local DetectedObject = Detection.object -- Dcs.DCSWrapper.Object#Object - self:T2( DetectedObject ) - if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then + if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then -- and ( DetectedObject:getCategory() == Object.Category.UNIT or DetectedObject:getCategory() == Object.Category.STATIC ) then local DetectionAccepted = true @@ -515,10 +565,14 @@ do -- DETECTION_BASE ( DetectedObjectVec3.y - DetectionGroupVec3.y )^2 + ( DetectedObjectVec3.z - DetectionGroupVec3.z )^2 ) ^ 0.5 / 1000 + + local DetectedUnitCategory = DetectedObject:getDesc().category - self:T( { "Detected Target", DetectionGroupName, DetectedObjectName, Distance } ) - + self:T( { "Detected Target:", DetectionGroupName, DetectedObjectName, Distance, DetectedUnitCategory, DetectedCategory } ) + -- Calculate Acceptance + + DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false if self.AcceptRange and Distance > self.AcceptRange then DetectionAccepted = false @@ -625,10 +679,10 @@ do -- DETECTION_BASE end if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then - self:__Detect( self.DetectionInterval ) - self:T( "--> Create Detection Sets" ) self:CreateDetectionSets() + + self:__Detect( self.DetectionInterval ) end end @@ -645,6 +699,8 @@ do -- DETECTION_BASE function DETECTION_BASE:InitDetectVisual( DetectVisual ) self.DetectVisual = DetectVisual + + return self end --- Detect Optical. @@ -655,6 +711,8 @@ do -- DETECTION_BASE self:F2() self.DetectOptical = DetectOptical + + return self end --- Detect Radar. @@ -665,6 +723,8 @@ do -- DETECTION_BASE self:F2() self.DetectRadar = DetectRadar + + return self end --- Detect IRST. @@ -675,6 +735,8 @@ do -- DETECTION_BASE self:F2() self.DetectIRST = DetectIRST + + return self end --- Detect RWR. @@ -685,6 +747,8 @@ do -- DETECTION_BASE self:F2() self.DetectRWR = DetectRWR + + return self end --- Detect DLINK. @@ -695,9 +759,52 @@ do -- DETECTION_BASE self:F2() self.DetectDLINK = DetectDLINK + + return self end end + + do -- Filter methods + + --- Filter the detected units based on Unit.Category + -- The different values of Unit.Category can be: + -- + -- * Unit.Category.AIRPLANE + -- * Unit.Category.GROUND_UNIT + -- * Unit.Category.HELICOPTER + -- * Unit.Category.SHIP + -- * Unit.Category.STRUCTURE + -- + -- Multiple Unit.Category entries can be given as a table and then these will be evaluated as an OR expression. + -- + -- Example to filter a single category (Unit.Category.AIRPLANE). + -- + -- DetectionObject:FilterCategories( Unit.Category.AIRPLANE ) + -- + -- Example to filter multiple categories (Unit.Category.AIRPLANE, Unit.Category.HELICOPTER). Note the {}. + -- + -- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) + -- + -- @param #DETECTION_BASE self + -- @param #list FilterCategories The Categories entries + -- @return #DETECTION_BASE self + function DETECTION_BASE:FilterCategories( FilterCategories ) + self:F2() + + self._.FilterCategories = {} + if type( FilterCategories ) == "table" then + for CategoryID, Category in pairs( FilterCategories ) do + self._.FilterCategories[Category] = Category + end + else + self._.FilterCategories[FilterCategories] = FilterCategories + end + return self + + end + + end do diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index 55cdcbbdd..fc3473d59 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -1,112 +1,26 @@ ---- Single-Player:**Yes** / Multi-Player:**Yes** / AI:**Yes** / Human:**No** / Types:**All** -- --- **Spawn groups of units dynamically in your missions.** +--- **Functional** -- Spawn dynamically new GROUPs in your missions. -- -- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG) -- --- === +-- ==== -- --- # 1) @{#SPAWN} class, extends @{Base#BASE} +-- The documentation of the SPAWN class can be found further in this document. -- --- The @{#SPAWN} class allows to spawn dynamically new groups, based on pre-defined initialization settings, modifying the behaviour when groups are spawned. --- For each group to be spawned, within the mission editor, a group has to be created with the "late activation flag" set. We call this group the *"Spawn Template"* of the SPAWN object. --- A reference to this Spawn Template needs to be provided when constructing the SPAWN object, by indicating the name of the group within the mission editor in the constructor methods. +-- ==== -- --- Within the SPAWN object, there is an internal index that keeps track of which group from the internal group list was spawned. --- When new groups get spawned by using the SPAWN methods (see below), it will be validated whether the Limits (@{#SPAWN.Limit}) of the SPAWN object are not reached. --- When all is valid, a new group will be created by the spawning methods, and the internal index will be increased with 1. +-- # Demo Missions -- --- Regarding the name of new spawned groups, a _SpawnPrefix_ will be assigned for each new group created. --- If you want to have the Spawn Template name to be used as the _SpawnPrefix_ name, use the @{#SPAWN.New} constructor. --- However, when the @{#SPAWN.NewWithAlias} constructor was used, the Alias name will define the _SpawnPrefix_ name. --- Groups will follow the following naming structure when spawned at run-time: +-- ### [SPAWN Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning) -- --- 1. Spawned groups will have the name _SpawnPrefix_#ggg, where ggg is a counter from 0 to 999. --- 2. Spawned units will have the name _SpawnPrefix_#ggg-uu, where uu is a counter from 0 to 99 for each new spawned unit belonging to the group. --- --- Some additional notes that need to be remembered: --- --- * Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the @{#SPAWN} module. --- * It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use. --- * When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore. --- --- ## 1.1) SPAWN construction methods --- --- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods: --- --- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition). --- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition), and gives each spawned @{Group} an different name. +-- ### [SPAWN Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPA%20-%20Spawning) -- --- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. --- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. --- So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient. --- --- ## 1.2) SPAWN initialization methods +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) -- --- A spawn object will behave differently based on the usage of **initialization** methods, which all start with the **Init** prefix: +-- ==== -- --- * @{#SPAWN.InitKeepUnitNames}(): Keeps the unit names as defined within the mission editor, but note that anything after a # mark is ignored, and any spaces before and after the resulting name are removed. IMPORTANT! This method MUST be the first used after :New !!! --- * @{#SPAWN.InitLimit}(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. --- * @{#SPAWN.InitRandomizeRoute}(): Randomize the routes of spawned groups, and for air groups also optionally the height. --- * @{#SPAWN.InitRandomizeTemplate}(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined. --- * @{#SPAWN.InitUnControlled}(): Spawn plane groups uncontrolled. --- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a batallion in an array. --- * @{#SPAWN.InitRepeat}(): Re-spawn groups when they land at the home base. Similar methods are @{#SPAWN.InitRepeatOnLanding} and @{#SPAWN.InitRepeatOnEngineShutDown}. --- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. --- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius. --- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor. --- * @{#SPAWN.InitAIOn}(): Turns the AI On when spawning the new @{Group} object. --- * @{#SPAWN.InitAIOff}(): Turns the AI Off when spawning the new @{Group} object. --- * @{#SPAWN.InitAIOnOff}(): Turns the AI On or Off when spawning the new @{Group} object. +-- # YouTube Channel -- --- ## 1.3) SPAWN spawning methods --- --- Groups can be spawned at different times and methods: --- --- * @{#SPAWN.Spawn}(): Spawn one new group based on the last spawned index. --- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index. --- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. You can use @{#SPAWN.SpawnScheduleStart}() and @{#SPAWN.SpawnScheduleStop}() to start and stop the schedule respectively. --- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air). --- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ). --- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}. --- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}. --- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. --- --- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. --- You can use the @{GROUP} object to do further actions with the DCSGroup. --- --- ## 1.4) Retrieve alive GROUPs spawned by the SPAWN object --- --- The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. --- Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. --- SPAWN provides methods to iterate through that internal GROUP object reference table: --- --- * @{#SPAWN.GetFirstAliveGroup}(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found. --- * @{#SPAWN.GetNextAliveGroup}(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found. --- * @{#SPAWN.GetLastAliveGroup}(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found. --- --- You can use the methods @{#SPAWN.GetFirstAliveGroup}() and sequently @{#SPAWN.GetNextAliveGroup}() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. --- The method @{#SPAWN.GetGroupFromIndex}() will return the GROUP object reference from the given Index, dead or alive... --- --- ## 1.5) SPAWN object cleaning --- --- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. --- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, --- and it may occur that no new groups are or can be spawned as limits are reached. --- To prevent this, a @{#SPAWN.InitCleanUp}() initialization method has been defined that will silently monitor the status of each spawned group. --- Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. --- There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... --- In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. --- This models AI that has succesfully returned to their airbase, to restart their combat activities. --- Check the @{#SPAWN.InitCleanUp}() for further info. --- --- ## 1.6) Catch the @{Group} spawn event in a callback function! --- --- When using the SpawnScheduled method, new @{Group}s are created following the schedule timing parameters. --- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. --- To SPAWN class supports this functionality through the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method, which takes a function as a parameter that you can define locally. --- Whenever a new @{Group} is spawned, the given function is called, and the @{Group} that was just spawned, is given as a parameter. --- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Group} object. --- A coding example is provided at the description of the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method. +-- ### [SPAWN YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL) -- -- ==== -- @@ -119,44 +33,34 @@ -- -- Hereby the change log: -- +-- 2017-04-08: SPAWN:**InitDelayOnOff( DelayOnOff )** added. +-- 2017-04-08: SPAWN:**InitDelayOn()** added. +-- 2017-04-08: SPAWN:**InitDelayOff()** added. +-- -- 2017-03-14: SPAWN:**InitKeepUnitNames()** added. --- 2017-03-14: SPAWN:**InitRandomizePosition( RandomizePosition, OuterRadious, InnerRadius )** added. +-- 2017-03-14: SPAWN:**InitRandomizePosition( RandomizePosition, OuterRadious, InnerRadius )** added. -- --- 2017-02-04: SPAWN:InitUnControlled( **UnControlled** ) replaces SPAWN:InitUnControlled(). +-- 2017-02-04: SPAWN:InitUnControlled( **UnControlled** ) replaces SPAWN:InitUnControlled(). -- --- 2017-01-24: SPAWN:**InitAIOnOff( AIOnOff )** added. --- --- 2017-01-24: SPAWN:**InitAIOn()** added. --- --- 2017-01-24: SPAWN:**InitAIOff()** added. --- --- 2016-08-15: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ). +-- 2017-01-24: SPAWN:**InitAIOnOff( AIOnOff )** added. +-- 2017-01-24: SPAWN:**InitAIOn()** added. +-- 2017-01-24: SPAWN:**InitAIOff()** added. -- +-- 2016-08-15: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ). -- 2016-08-15: SPAWN:**InitRandomizeZones( SpawnZones )** added. -- --- 2016-08-14: SPAWN:**OnSpawnGroup**( SpawnCallBackFunction, ... ) replaces SPAWN:_SpawnFunction_( SpawnCallBackFunction, ... ). --- --- 2016-08-14: SPAWN.SpawnInZone( Zone, __RandomizeGroup__, SpawnIndex ) replaces SpawnInZone( Zone, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). --- --- 2016-08-14: SPAWN.SpawnFromVec3( Vec3, SpawnIndex ) replaces SpawnFromVec3( Vec3, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- 2016-08-14: SPAWN.SpawnFromVec2( Vec2, SpawnIndex ) replaces SpawnFromVec2( Vec2, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromUnit( SpawnUnit, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromStatic( SpawnStatic, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- 2016-08-14: SPAWN.**InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius )** added: --- --- 2016-08-14: SPAWN.**Init**Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) replaces SPAWN._Limit_( SpawnMaxUnitsAlive, SpawnMaxGroups ): --- --- 2016-08-14: SPAWN.**Init**Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) replaces SPAWN._Array_( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ). --- --- 2016-08-14: SPAWN.**Init**RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) replaces SPAWN._RandomizeRoute_( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ). --- --- 2016-08-14: SPAWN.**Init**RandomizeTemplate( SpawnTemplatePrefixTable ) replaces SPAWN._RandomizeTemplate_( SpawnTemplatePrefixTable ). --- --- 2016-08-14: SPAWN.**Init**UnControlled() replaces SPAWN._UnControlled_(). +-- 2016-08-14: SPAWN:**OnSpawnGroup**( SpawnCallBackFunction, ... ) replaces SPAWN:_SpawnFunction_( SpawnCallBackFunction, ... ). +-- 2016-08-14: SPAWN.SpawnInZone( Zone, __RandomizeGroup__, SpawnIndex ) replaces SpawnInZone( Zone, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). +-- 2016-08-14: SPAWN.SpawnFromVec3( Vec3, SpawnIndex ) replaces SpawnFromVec3( Vec3, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). +-- 2016-08-14: SPAWN.SpawnFromVec2( Vec2, SpawnIndex ) replaces SpawnFromVec2( Vec2, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). +-- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromUnit( SpawnUnit, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). +-- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromStatic( SpawnStatic, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). +-- 2016-08-14: SPAWN.**InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius )** added. +-- 2016-08-14: SPAWN.**Init**Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) replaces SPAWN._Limit_( SpawnMaxUnitsAlive, SpawnMaxGroups ). +-- 2016-08-14: SPAWN.**Init**Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) replaces SPAWN._Array_( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ). +-- 2016-08-14: SPAWN.**Init**RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) replaces SPAWN._RandomizeRoute_( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ). +-- 2016-08-14: SPAWN.**Init**RandomizeTemplate( SpawnTemplatePrefixTable ) replaces SPAWN._RandomizeTemplate_( SpawnTemplatePrefixTable ). +-- 2016-08-14: SPAWN.**Init**UnControlled() replaces SPAWN._UnControlled_(). -- -- === -- @@ -177,7 +81,6 @@ --- SPAWN Class -- @type SPAWN --- @extends Core.Base#BASE -- @field ClassName -- @field #string SpawnTemplatePrefix -- @field #string SpawnAliasPrefix @@ -186,6 +89,214 @@ -- @field #number SpawnIndex -- @field #number MaxAliveGroups -- @field #SPAWN.SpawnZoneTable SpawnZoneTable +-- @extends Core.Base#BASE + + +--- # SPAWN class, extends @{Base#BASE} +-- +-- The SPAWN class allows to spawn dynamically new groups. +-- Each SPAWN object needs to be have a related **template group** setup in the Mission Editor (ME), +-- which is a normal group with the **Late Activation** flag set. +-- This template group will never be activated in your mission. +-- SPAWN uses that **template group** to reference to all the characteristics +-- (air, ground, livery, unit composition, formation, skill level etc) of each new group to be spawned. +-- +-- Therefore, when creating a SPAWN object, the @{#SPAWN.New} and @{#SPAWN.NewWithAlias} require +-- **the name of the template group** to be given as a string to those constructor methods. +-- +-- Initialization settings can be applied on the SPAWN object, +-- which modify the behaviour or the way groups are spawned. +-- These initialization methods have the prefix **Init**. +-- There are also spawn methods with the prefix **Spawn** and will spawn new groups in various ways. +-- +-- ### IMPORTANT! The methods with prefix **Init** must be used before any methods with prefix **Spawn** method are used, or unexpected results may appear!!! +-- +-- Because SPAWN can spawn multiple groups of a template group, +-- SPAWN has an **internal index** that keeps track +-- which was the latest group that was spawned. +-- +-- **Limits** can be set on how many groups can be spawn in each SPAWN object, +-- using the method @{#SPAWN.InitLimit}. SPAWN has 2 kind of limits: +-- +-- * The maximum amount of @{Unit}s that can be **alive** at the same time... +-- * The maximum amount of @{Group}s that can be **spawned**... This is more of a **resource**-type of limit. +-- +-- When new groups get spawned using the **Spawn** methods, +-- it will be evaluated whether any limits have been reached. +-- When no spawn limit is reached, a new group will be created by the spawning methods, +-- and the internal index will be increased with 1. +-- +-- These limits ensure that your mission does not accidentally get flooded with spawned groups. +-- Additionally, it also guarantees that independent of the group composition, +-- at any time, the most optimal amount of groups are alive in your mission. +-- For example, if your template group has a group composition of 10 units, and you specify a limit of 100 units alive at the same time, +-- with unlimited resources = :InitLimit( 100, 0 ) and 10 groups are alive, but two groups have only one unit alive in the group, +-- then a sequent Spawn(Scheduled) will allow a new group to be spawned!!! +-- +-- ### IMPORTANT!! If a limit has been reached, it is possible that a **Spawn** method returns **nil**, meaning, no @{Group} had been spawned!!! +-- +-- Spawned groups get **the same name** as the name of the template group. +-- Spawned units in those groups keep _by default_ **the same name** as the name of the template group. +-- However, because multiple groups and units are created from the template group, +-- a suffix is added to each spawned group and unit. +-- +-- Newly spawned groups will get the following naming structure at run-time: +-- +-- 1. Spawned groups will have the name _GroupName_#_nnn_, where _GroupName_ is the name of the **template group**, +-- and _nnn_ is a **counter from 0 to 999**. +-- 2. Spawned units will have the name _GroupName_#_nnn_-_uu_, +-- where _uu_ is a **counter from 0 to 99** for each new spawned unit belonging to the group. +-- +-- That being said, there is a way to keep the same unit names! +-- The method @{#SPAWN.InitKeepUnitNames}() will keep the same unit names as defined within the template group, thus: +-- +-- 3. Spawned units will have the name _UnitName_#_nnn_-_uu_, +-- where _UnitName_ is the **unit name as defined in the template group*, +-- and _uu_ is a **counter from 0 to 99** for each new spawned unit belonging to the group. +-- +-- Some **additional notes that need to be considered!!**: +-- +-- * templates are actually groups defined within the mission editor, with the flag "Late Activation" set. +-- As such, these groups are never used within the mission, but are used by the @{#SPAWN} module. +-- * It is important to defined BEFORE you spawn new groups, +-- a proper initialization of the SPAWN instance is done with the options you want to use. +-- * When designing a mission, NEVER name groups using a "#" within the name of the group Spawn template(s), +-- or the SPAWN module logic won't work anymore. +-- +-- ## SPAWN construction methods +-- +-- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods: +-- +-- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition). +-- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition), and gives each spawned @{Group} an different name. +-- +-- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. +-- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. +-- So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient. +-- +-- ## SPAWN **Init**ialization methods +-- +-- A spawn object will behave differently based on the usage of **initialization** methods, which all start with the **Init** prefix: +-- +-- ### Unit Names +-- +-- * @{#SPAWN.InitKeepUnitNames}(): Keeps the unit names as defined within the mission editor, but note that anything after a # mark is ignored, and any spaces before and after the resulting name are removed. IMPORTANT! This method MUST be the first used after :New !!! +-- +-- ### Route randomization +-- +-- * @{#SPAWN.InitRandomizeRoute}(): Randomize the routes of spawned groups, and for air groups also optionally the height. +-- +-- ### Group composition randomization +-- +-- * @{#SPAWN.InitRandomizeTemplate}(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined. +-- +-- ### Uncontrolled +-- +-- * @{#SPAWN.InitUnControlled}(): Spawn plane groups uncontrolled. +-- +-- ### Array formation +-- +-- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a batallion in an array. +-- +-- ### Position randomization +-- +-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens. +-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius. +-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor. +-- +-- ### Enable / Disable AI when spawning a new @{Group} +-- +-- * @{#SPAWN.InitAIOn}(): Turns the AI On when spawning the new @{Group} object. +-- * @{#SPAWN.InitAIOff}(): Turns the AI Off when spawning the new @{Group} object. +-- * @{#SPAWN.InitAIOnOff}(): Turns the AI On or Off when spawning the new @{Group} object. +-- +-- ### Limit scheduled spawning +-- +-- * @{#SPAWN.InitLimit}(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. +-- +-- ### Delay initial scheduled spawn +-- +-- * @{#SPAWN.InitDelayOnOff}(): Turns the inital delay On/Off when scheduled spawning the first @{Group} object. +-- * @{#SPAWN.InitDelayOn}(): Turns the inital delay On when scheduled spawning the first @{Group} object. +-- * @{#SPAWN.InitDelayOff}(): Turns the inital delay Off when scheduled spawning the first @{Group} object. +-- +-- ### Repeat spawned @{Group}s upon landing +-- +-- * @{#SPAWN.InitRepeat}() or @{#SPAWN.InitRepeatOnLanding}(): This method is used to re-spawn automatically the same group after it has landed. +-- * @{#SPAWN.InitRepeatOnEngineShutDown}(): This method is used to re-spawn automatically the same group after it has landed and it shuts down the engines at the ramp. +-- +-- +-- ## SPAWN **Spawn** methods +-- +-- Groups can be spawned at different times and methods: +-- +-- ### **Single** spawning methods +-- +-- * @{#SPAWN.Spawn}(): Spawn one new group based on the last spawned index. +-- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index. +-- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air). +-- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ). +-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}. +-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}. +-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. +-- +-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. +-- You can use the @{GROUP} object to do further actions with the DCSGroup. +-- +-- ### **Scheduled** spawning methods +-- +-- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. +-- * @{#SPAWN.SpawnScheduledStart}(): Start or continue to spawn groups at scheduled time intervals. +-- * @{#SPAWN.SpawnScheduledStop}(): Stop the spawning of groups at scheduled time intervals. +-- +-- +-- +-- ## Retrieve alive GROUPs spawned by the SPAWN object +-- +-- The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. +-- Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. +-- SPAWN provides methods to iterate through that internal GROUP object reference table: +-- +-- * @{#SPAWN.GetFirstAliveGroup}(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found. +-- * @{#SPAWN.GetNextAliveGroup}(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found. +-- * @{#SPAWN.GetLastAliveGroup}(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found. +-- +-- You can use the methods @{#SPAWN.GetFirstAliveGroup}() and sequently @{#SPAWN.GetNextAliveGroup}() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. +-- The method @{#SPAWN.GetGroupFromIndex}() will return the GROUP object reference from the given Index, dead or alive... +-- +-- ## Spawned cleaning of inactive groups +-- +-- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. +-- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, +-- and it may occur that no new groups are or can be spawned as limits are reached. +-- To prevent this, a @{#SPAWN.InitCleanUp}() initialization method has been defined that will silently monitor the status of each spawned group. +-- Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. +-- There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... +-- In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. +-- This models AI that has succesfully returned to their airbase, to restart their combat activities. +-- Check the @{#SPAWN.InitCleanUp}() for further info. +-- +-- ## Catch the @{Group} Spawn Event in a callback function! +-- +-- When using the @{#SPAWN.SpawnScheduled)() method, new @{Group}s are created following the spawn time interval parameters. +-- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. +-- The SPAWN class supports this functionality through the method @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ), +-- which takes a function as a parameter that you can define locally. +-- Whenever a new @{Group} is spawned, the given function is called, and the @{Group} that was just spawned, is given as a parameter. +-- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Group} object. +-- A coding example is provided at the description of the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method. +-- +-- ## Delay the initial spawning +-- +-- When using the @{#SPAWN.SpawnScheduled)() method, the default behaviour of this method will be that it will spawn the initial (first) @{Group} +-- immediately when :SpawnScheduled() is initiated. The methods @{#SPAWN.InitDelayOnOff}() and @{#SPAWN.InitDelayOn}() can be used to +-- activate a delay before the first @{Group} is spawned. For completeness, a method @{#SPAWN.InitDelayOff}() is also available, that +-- can be used to switch off the initial delay. Because there is no delay by default, this method would only be used when a +-- @{#SPAWN.SpawnScheduledStop}() ; @{#SPAWN.SpawnScheduledStart}() sequence would have been used. +-- +-- +-- @field #SPAWN SPAWN +-- SPAWN = { ClassName = "SPAWN", SpawnTemplatePrefix = nil, @@ -227,6 +338,7 @@ function SPAWN:New( SpawnTemplatePrefix ) self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -270,6 +382,7 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) self.AIOnOff = true -- The AI is on by default when spawning a group. self.SpawnUnControlled = false self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. + self.DelayOnOff = false -- No intial delay when spawning the first group. self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -626,6 +739,36 @@ do -- AI methods end -- AI methods +do -- Delay methods + --- Turns the Delay On or Off for the first @{Group} scheduled spawning. + -- The default value is that for scheduled spawning, there is an initial delay when spawning the first @{Group}. + -- @param #SPAWN self + -- @param #boolean DelayOnOff A value of true sets the Delay On, a value of false sets the Delay Off. + -- @return #SPAWN The SPAWN object + function SPAWN:InitDelayOnOff( DelayOnOff ) + + self.DelayOnOff = DelayOnOff + return self + end + + --- Turns the Delay On for the @{Group} when spawning. + -- @param #SPAWN self + -- @return #SPAWN The SPAWN object + function SPAWN:InitDelayOn() + + return self:InitDelayOnOff( true ) + end + + --- Turns the Delay Off for the @{Group} when spawning. + -- @param #SPAWN self + -- @return #SPAWN The SPAWN object + function SPAWN:InitDelayOff() + + return self:InitDelayOnOff( false ) + end + +end -- Delay methods + --- Will spawn a group based on the internal index. -- Note: Uses @{DATABASE} module defined in MOOSE. -- @param #SPAWN self @@ -669,6 +812,8 @@ function SPAWN:ReSpawn( SpawnIndex ) SpawnGroup:ReSpawnFunction() end + SpawnGroup:ResetEvents() + return SpawnGroup end @@ -787,7 +932,11 @@ function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation ) self:F( { SpawnTime, SpawnTimeVariation } ) if SpawnTime ~= nil and SpawnTimeVariation ~= nil then - self.SpawnScheduler = SCHEDULER:New( self, self._Scheduler, {}, 1, SpawnTime, SpawnTimeVariation ) + local InitialDelay = 0 + if self.DelayOnOff == true then + InitialDelay = math.random( SpawnTime - SpawnTime * SpawnTimeVariation, SpawnTime + SpawnTime * SpawnTimeVariation ) + end + self.SpawnScheduler = SCHEDULER:New( self, self._Scheduler, {}, InitialDelay, SpawnTime, SpawnTimeVariation ) end return self @@ -795,17 +944,23 @@ end --- Will re-start the spawning scheduler. -- Note: This method is only required to be called when the schedule was stopped. +-- @param #SPAWN self +-- @return #SPAWN function SPAWN:SpawnScheduleStart() self:F( { self.SpawnTemplatePrefix } ) self.SpawnScheduler:Start() + return self end --- Will stop the scheduled spawning scheduler. +-- @param #SPAWN self +-- @return #SPAWN function SPAWN:SpawnScheduleStop() self:F( { self.SpawnTemplatePrefix } ) self.SpawnScheduler:Stop() + return self end @@ -926,7 +1081,7 @@ end function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex ) self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } ) - if HostUnit and HostUnit:IsAlive() then -- and HostUnit:getUnit(1):inAir() == false then + if HostUnit and HostUnit:IsAlive() ~= nil then -- and HostUnit:getUnit(1):inAir() == false then return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex ) end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index f1c70aca6..554c31ea6 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -834,6 +834,9 @@ function GROUP:Respawn( Template ) self:Destroy() _DATABASE:Spawn( Template ) + + self:ResetEvents() + end --- Returns the group template from the @{DATABASE} (_DATABASE object). @@ -1077,7 +1080,21 @@ do -- Event Handling -- @return #GROUP function GROUP:UnHandleEvent( Event ) - self:EventDispatcher():RemoveForGroup( self:GetName(), self, Event ) + self:EventDispatcher():Remove( self, Event ) + + return self + end + + --- Reset the subscriptions. + -- @param #GROUP self + -- @return #GROUP + function GROUP:ResetEvents() + + self:EventDispatcher():Reset( self ) + + for UnitID, UnitData in pairs( self:GetUnits() ) do + UnitData:ResetEvents() + end return self end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 68be9a981..cd4762652 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -990,5 +990,16 @@ do -- Event Handling return self end + + --- Reset the subscriptions. + -- @param #UNIT self + -- @return #UNIT + function UNIT:ResetEvents() + + self:EventDispatcher():Reset( self ) + + return self + end + end \ No newline at end of file diff --git a/Moose Mission Setup/Moose.files b/Moose Mission Setup/Moose.files index fac9aa46b..b8084a749 100644 --- a/Moose Mission Setup/Moose.files +++ b/Moose Mission Setup/Moose.files @@ -13,6 +13,7 @@ Core/Point.lua Core/Message.lua Core/Fsm.lua Core/Radio.lua +Core/SpawnStatic.lua Wrapper/Object.lua Wrapper/Identifiable.lua diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 3b2b611ed..e69de29bb 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,31 +0,0 @@ -env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170328_0728' ) - -local base = _G - -Include = {} - -Include.File = function( IncludeFile ) - if not Include.Files[ IncludeFile ] then - Include.Files[IncludeFile] = IncludeFile - env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath ) - local f = assert( base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" ) ) - if f == nil then - error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) - else - env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath ) - return f() - end - end -end - -Include.ProgramPath = "Scripts/Moose/" - -env.info( "Include.ProgramPath = " .. Include.ProgramPath) - -Include.Files = {} - -Include.File( "Moose" ) - -BASE:TraceOnOff( true ) -env.info( '*** MOOSE INCLUDE END *** ' ) diff --git a/Utils/lua/5.1/bin/lua.exe b/Utils/lua/5.1/bin/lua.exe deleted file mode 100644 index d8566c515..000000000 Binary files a/Utils/lua/5.1/bin/lua.exe and /dev/null differ diff --git a/Utils/lua/5.1/bin/lua51.dll b/Utils/lua/5.1/bin/lua51.dll deleted file mode 100644 index 36418f3f3..000000000 Binary files a/Utils/lua/5.1/bin/lua51.dll and /dev/null differ diff --git a/Utils/lua/5.1/bin/luac.exe b/Utils/lua/5.1/bin/luac.exe deleted file mode 100644 index 9c64f9926..000000000 Binary files a/Utils/lua/5.1/bin/luac.exe and /dev/null differ diff --git a/Utils/lua/5.1/bin/luadocumentor.bat b/Utils/lua/5.1/bin/luadocumentor.bat deleted file mode 100644 index 3d449219a..000000000 --- a/Utils/lua/5.1/bin/luadocumentor.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -"C:\Program Files\lua\5.1\bin\lua.exe" -e "package.path=\"C:\\Users\\svenv\\AppData\\Roaming/luarocks/share/lua/5.1/?.lua;C:\\Users\\svenv\\AppData\\Roaming/luarocks/share/lua/5.1/?/init.lua;c:\\program files\\lua\\5.1\\/share/lua/5.1/?.lua;c:\\program files\\lua\\5.1\\/share/lua/5.1/?/init.lua;C:\\Program Files (x86)\\LuaRocks\\lua\\?.lua;\"..package.path; package.cpath=\"C:\\Users\\svenv\\AppData\\Roaming/luarocks/lib/lua/5.1/?.dll;c:\\program files\\lua\\5.1\\/lib/lua/5.1/?.dll;\"..package.cpath" -e "local k,l,_=pcall(require,\"luarocks.loader\") _=k and l.add_context(\"luadocumentor\",\"0.1.5-1\")" "c:\program files\lua\5.1\\lib\luarocks\rocks\luadocumentor\0.1.5-1\bin\luadocumentor" %* -exit /b %ERRORLEVEL% diff --git a/Utils/lua/5.1/lib/liblua.a b/Utils/lua/5.1/lib/liblua.a deleted file mode 100644 index f4d65be64..000000000 Binary files a/Utils/lua/5.1/lib/liblua.a and /dev/null differ diff --git a/Utils/lua/5.1/lib/lua/5.1/checks.dll b/Utils/lua/5.1/lib/lua/5.1/checks.dll deleted file mode 100644 index 98254c4f4..000000000 Binary files a/Utils/lua/5.1/lib/lua/5.1/checks.dll and /dev/null differ diff --git a/Utils/lua/5.1/lib/lua/5.1/lfs.dll b/Utils/lua/5.1/lib/lua/5.1/lfs.dll deleted file mode 100644 index 6e73ea2c2..000000000 Binary files a/Utils/lua/5.1/lib/lua/5.1/lfs.dll and /dev/null differ diff --git a/Utils/lua/5.1/man/man1/lua.1 b/Utils/lua/5.1/man/man1/lua.1 deleted file mode 100644 index 24809cc6c..000000000 --- a/Utils/lua/5.1/man/man1/lua.1 +++ /dev/null @@ -1,163 +0,0 @@ -.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ -.TH LUA 1 "$Date: 2006/01/06 16:03:34 $" -.SH NAME -lua \- Lua interpreter -.SH SYNOPSIS -.B lua -[ -.I options -] -[ -.I script -[ -.I args -] -] -.SH DESCRIPTION -.B lua -is the stand-alone Lua interpreter. -It loads and executes Lua programs, -either in textual source form or -in precompiled binary form. -(Precompiled binaries are output by -.BR luac , -the Lua compiler.) -.B lua -can be used as a batch interpreter and also interactively. -.LP -The given -.I options -(see below) -are executed and then -the Lua program in file -.I script -is loaded and executed. -The given -.I args -are available to -.I script -as strings in a global table named -.BR arg . -If these arguments contain spaces or other characters special to the shell, -then they should be quoted -(but note that the quotes will be removed by the shell). -The arguments in -.B arg -start at 0, -which contains the string -.RI ' script '. -The index of the last argument is stored in -.BR arg.n . -The arguments given in the command line before -.IR script , -including the name of the interpreter, -are available in negative indices in -.BR arg . -.LP -At the very start, -before even handling the command line, -.B lua -executes the contents of the environment variable -.BR LUA_INIT , -if it is defined. -If the value of -.B LUA_INIT -is of the form -.RI '@ filename ', -then -.I filename -is executed. -Otherwise, the string is assumed to be a Lua statement and is executed. -.LP -Options start with -.B '\-' -and are described below. -You can use -.B "'\--'" -to signal the end of options. -.LP -If no arguments are given, -then -.B "\-v \-i" -is assumed when the standard input is a terminal; -otherwise, -.B "\-" -is assumed. -.LP -In interactive mode, -.B lua -prompts the user, -reads lines from the standard input, -and executes them as they are read. -If a line does not contain a complete statement, -then a secondary prompt is displayed and -lines are read until a complete statement is formed or -a syntax error is found. -So, one way to interrupt the reading of an incomplete statement is -to force a syntax error: -adding a -.B ';' -in the middle of a statement is a sure way of forcing a syntax error -(except inside multiline strings and comments; these must be closed explicitly). -If a line starts with -.BR '=' , -then -.B lua -displays the values of all the expressions in the remainder of the -line. The expressions must be separated by commas. -The primary prompt is the value of the global variable -.BR _PROMPT , -if this value is a string; -otherwise, the default prompt is used. -Similarly, the secondary prompt is the value of the global variable -.BR _PROMPT2 . -So, -to change the prompts, -set the corresponding variable to a string of your choice. -You can do that after calling the interpreter -or on the command line -(but in this case you have to be careful with quotes -if the prompt string contains a space; otherwise you may confuse the shell.) -The default prompts are "> " and ">> ". -.SH OPTIONS -.TP -.B \- -load and execute the standard input as a file, -that is, -not interactively, -even when the standard input is a terminal. -.TP -.BI \-e " stat" -execute statement -.IR stat . -You need to quote -.I stat -if it contains spaces, quotes, -or other characters special to the shell. -.TP -.B \-i -enter interactive mode after -.I script -is executed. -.TP -.BI \-l " name" -call -.BI require(' name ') -before executing -.IR script . -Typically used to load libraries. -.TP -.B \-v -show version information. -.SH "SEE ALSO" -.BR luac (1) -.br -http://www.lua.org/ -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -R. Ierusalimschy, -L. H. de Figueiredo, -and -W. Celes -.\" EOF diff --git a/Utils/lua/5.1/man/man1/luac.1 b/Utils/lua/5.1/man/man1/luac.1 deleted file mode 100644 index d8146782d..000000000 --- a/Utils/lua/5.1/man/man1/luac.1 +++ /dev/null @@ -1,136 +0,0 @@ -.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ -.TH LUAC 1 "$Date: 2006/01/06 16:03:34 $" -.SH NAME -luac \- Lua compiler -.SH SYNOPSIS -.B luac -[ -.I options -] [ -.I filenames -] -.SH DESCRIPTION -.B luac -is the Lua compiler. -It translates programs written in the Lua programming language -into binary files that can be later loaded and executed. -.LP -The main advantages of precompiling chunks are: -faster loading, -protecting source code from accidental user changes, -and -off-line syntax checking. -.LP -Pre-compiling does not imply faster execution -because in Lua chunks are always compiled into bytecodes before being executed. -.B luac -simply allows those bytecodes to be saved in a file for later execution. -.LP -Pre-compiled chunks are not necessarily smaller than the corresponding source. -The main goal in pre-compiling is faster loading. -.LP -The binary files created by -.B luac -are portable only among architectures with the same word size and byte order. -.LP -.B luac -produces a single output file containing the bytecodes -for all source files given. -By default, -the output file is named -.BR luac.out , -but you can change this with the -.B \-o -option. -.LP -In the command line, -you can mix -text files containing Lua source and -binary files containing precompiled chunks. -This is useful to combine several precompiled chunks, -even from different (but compatible) platforms, -into a single precompiled chunk. -.LP -You can use -.B "'\-'" -to indicate the standard input as a source file -and -.B "'\--'" -to signal the end of options -(that is, -all remaining arguments will be treated as files even if they start with -.BR "'\-'" ). -.LP -The internal format of the binary files produced by -.B luac -is likely to change when a new version of Lua is released. -So, -save the source files of all Lua programs that you precompile. -.LP -.SH OPTIONS -Options must be separate. -.TP -.B \-l -produce a listing of the compiled bytecode for Lua's virtual machine. -Listing bytecodes is useful to learn about Lua's virtual machine. -If no files are given, then -.B luac -loads -.B luac.out -and lists its contents. -.TP -.BI \-o " file" -output to -.IR file , -instead of the default -.BR luac.out . -(You can use -.B "'\-'" -for standard output, -but not on platforms that open standard output in text mode.) -The output file may be a source file because -all files are loaded before the output file is written. -Be careful not to overwrite precious files. -.TP -.B \-p -load files but do not generate any output file. -Used mainly for syntax checking and for testing precompiled chunks: -corrupted files will probably generate errors when loaded. -Lua always performs a thorough integrity test on precompiled chunks. -Bytecode that passes this test is completely safe, -in the sense that it will not break the interpreter. -However, -there is no guarantee that such code does anything sensible. -(None can be given, because the halting problem is unsolvable.) -If no files are given, then -.B luac -loads -.B luac.out -and tests its contents. -No messages are displayed if the file passes the integrity test. -.TP -.B \-s -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running a stripped chunk, -then the error messages may not contain the full information they usually do. -For instance, -line numbers and names of local variables are lost. -.TP -.B \-v -show version information. -.SH FILES -.TP 15 -.B luac.out -default output file -.SH "SEE ALSO" -.BR lua (1) -.br -http://www.lua.org/ -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -L. H. de Figueiredo, -R. Ierusalimschy and -W. Celes -.\" EOF diff --git a/Utils/luadocumentor.bat b/Utils/luadocumentor.bat new file mode 100644 index 000000000..8f28e39a8 --- /dev/null +++ b/Utils/luadocumentor.bat @@ -0,0 +1,3 @@ +@echo off +"./luarocks/lua5.1" -e "package.path=\"./luarocks/systree/share/lua/5.1/?.lua;./luarocks/systree/share/lua/5.1/?/init.lua;./luarocks/systree/share/lua/5.1/?.lua;./luarocks/systree/share/lua/5.1/?/init.lua;./luarocks/lua/?.lua;\"..package.path; package.cpath=\"./luarocks/lib/lua/5.1/?.dll;./luarocks/systree/lib/lua/5.1/?.dll;\"..package.cpath" -e "local k,l,_=pcall(require,\"luarocks.loader\") _=k and l.add_context(\"luadocumentor\",\"0.1.5-1\")" "./luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/bin/luadocumentor" -f doc -d "../docs/Documentation" -s "../docs/Stylesheet/stylesheet.css" "../Moose Development/Moose" %* +exit /b %ERRORLEVEL% \ No newline at end of file diff --git a/Utils/luarocks/Microsoft.VC80.CRT.manifest b/Utils/luarocks/Microsoft.VC80.CRT.manifest new file mode 100644 index 000000000..6a8a0e239 --- /dev/null +++ b/Utils/luarocks/Microsoft.VC80.CRT.manifest @@ -0,0 +1,8 @@ + + + + + n9On8FItNsK/DmT8UQxu6jYDtWQ= + 0KJ/VTwP4OUHx98HlIW2AdW1kuY= + YJuB+9Os2oxW4mY+2oC/r8lICZE= + \ No newline at end of file diff --git a/Utils/luarocks/bin2c5.1.exe b/Utils/luarocks/bin2c5.1.exe new file mode 100644 index 000000000..ca81d4b61 Binary files /dev/null and b/Utils/luarocks/bin2c5.1.exe differ diff --git a/Utils/luarocks/config-5.1.lua b/Utils/luarocks/config-5.1.lua new file mode 100644 index 000000000..cf02193f5 --- /dev/null +++ b/Utils/luarocks/config-5.1.lua @@ -0,0 +1,14 @@ +rocks_trees = { + home..[[/luarocks]], + { name = [[user]], + root = home..[[/luarocks]], + }, + { name = [[system]], + root = [[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\systree]], + }, +} +variables = { + MSVCRT = 'MSVCR80', + LUALIB = 'lua5.1.lib' +} +verbose = false -- set to 'true' to enable verbose output diff --git a/Utils/lua/5.1/include/lauxlib.h b/Utils/luarocks/include/lauxlib.h similarity index 100% rename from Utils/lua/5.1/include/lauxlib.h rename to Utils/luarocks/include/lauxlib.h diff --git a/Utils/lua/5.1/include/lua.h b/Utils/luarocks/include/lua.h similarity index 98% rename from Utils/lua/5.1/include/lua.h rename to Utils/luarocks/include/lua.h index a4b73e743..e4bdfd3b9 100644 --- a/Utils/lua/5.1/include/lua.h +++ b/Utils/luarocks/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.218.1.7 2012/01/13 20:36:20 roberto Exp $ +** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,9 +17,9 @@ #define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.5" +#define LUA_RELEASE "Lua 5.1.4" #define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2012 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -362,7 +362,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2012 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/Utils/lua/5.1/include/lua.hpp b/Utils/luarocks/include/lua.hpp similarity index 100% rename from Utils/lua/5.1/include/lua.hpp rename to Utils/luarocks/include/lua.hpp diff --git a/Utils/lua/5.1/include/luaconf.h b/Utils/luarocks/include/luaconf.h similarity index 98% rename from Utils/lua/5.1/include/luaconf.h rename to Utils/luarocks/include/luaconf.h index e2cb26163..5e7b98be6 100644 --- a/Utils/lua/5.1/include/luaconf.h +++ b/Utils/luarocks/include/luaconf.h @@ -91,7 +91,7 @@ ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" #define LUA_CPATH_DEFAULT \ - ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" + ".\\?.dll;" ".\\?51.dll;" LUA_CDIR"?.dll;" LUA_CDIR"?51.dll;" LUA_CDIR"clibs\\?.dll;" LUA_CDIR"clibs\\?51.dll;" LUA_CDIR"loadall.dll;" LUA_CDIR"clibs\\loadall.dll" #else #define LUA_ROOT "/usr/local/" @@ -101,7 +101,7 @@ "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" #define LUA_CPATH_DEFAULT \ - "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" + "./?.so;" "./lib?51.so;" LUA_CDIR"?.so;" LUA_CDIR"lib?51.so;" LUA_CDIR"loadall.so" #endif diff --git a/Utils/lua/5.1/include/lualib.h b/Utils/luarocks/include/lualib.h similarity index 100% rename from Utils/lua/5.1/include/lualib.h rename to Utils/luarocks/include/lualib.h diff --git a/Utils/luarocks/lua.ico b/Utils/luarocks/lua.ico new file mode 100644 index 000000000..56dc4fe15 Binary files /dev/null and b/Utils/luarocks/lua.ico differ diff --git a/Utils/luarocks/lua/luarocks/add.lua b/Utils/luarocks/lua/luarocks/add.lua new file mode 100644 index 000000000..f37d334d3 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/add.lua @@ -0,0 +1,122 @@ + +--- Module implementing the luarocks-admin "add" command. +-- Adds a rock or rockspec to a rocks server. +local add = {} +package.loaded["luarocks.add"] = add + +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local index = require("luarocks.index") +local fs = require("luarocks.fs") +local cache = require("luarocks.cache") + +util.add_run_function(add) +add.help_summary = "Add a rock or rockspec to a rocks server." +add.help_arguments = "[--server=] [--no-refresh] {|...}" +add.help = [[ +Arguments are local files, which may be rockspecs or rocks. +The flag --server indicates which server to use. +If not given, the default server set in the upload_server variable +from the configuration file is used instead. +The flag --no-refresh indicates the local cache should not be refreshed +prior to generation of the updated manifest. +]] + +local function add_files_to_server(refresh, rockfiles, server, upload_server) + assert(type(refresh) == "boolean" or not refresh) + assert(type(rockfiles) == "table") + assert(type(server) == "string") + assert(type(upload_server) == "table" or not upload_server) + + local download_url, login_url = cache.get_server_urls(server, upload_server) + local at = fs.current_dir() + local refresh_fn = refresh and cache.refresh_local_cache or cache.split_server_url + + local local_cache, protocol, server_path, user, password = refresh_fn(server, download_url, cfg.upload_user, cfg.upload_password) + if not local_cache then + return nil, protocol + end + if protocol == "file" then + return nil, "Server "..server.." is not recognized, check your configuration." + end + + if not login_url then + login_url = protocol.."://"..server_path + end + + local ok, err = fs.change_dir(at) + if not ok then return nil, err end + + local files = {} + for _, rockfile in ipairs(rockfiles) do + if fs.exists(rockfile) then + util.printout("Copying file "..rockfile.." to "..local_cache.."...") + local absolute = fs.absolute_name(rockfile) + fs.copy(absolute, local_cache, cfg.perm_read) + table.insert(files, dir.base_name(absolute)) + else + util.printerr("File "..rockfile.." not found") + end + end + if #files == 0 then + return nil, "No files found" + end + + local ok, err = fs.change_dir(local_cache) + if not ok then return nil, err end + + util.printout("Updating manifest...") + manif.make_manifest(local_cache, "one", true) + + manif.zip_manifests() + + util.printout("Updating index.html...") + index.make_index(local_cache) + + local login_info = "" + if user then login_info = " -u "..user end + if password then login_info = login_info..":"..password end + if not login_url:match("/$") then + login_url = login_url .. "/" + end + + table.insert(files, "index.html") + table.insert(files, "manifest") + for ver in util.lua_versions() do + table.insert(files, "manifest-"..ver) + table.insert(files, "manifest-"..ver..".zip") + end + + -- TODO abstract away explicit 'curl' call + + local cmd + if protocol == "rsync" then + local srv, path = server_path:match("([^/]+)(/.+)") + cmd = cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/" + elseif upload_server and upload_server.sftp then + local part1, part2 = upload_server.sftp:match("^([^/]*)/(.*)$") + cmd = cfg.variables.SCP.." "..table.concat(files, " ").." "..user.."@"..part1..":/"..part2 + else + cmd = cfg.variables.CURL.." "..login_info.." -T '{"..table.concat(files, ",").."}' "..login_url + end + + util.printout(cmd) + fs.execute(cmd) + + return true +end + +function add.command(flags, ...) + local files = {...} + if #files < 1 then + return nil, "Argument missing. "..util.see_help("add", "luarocks-admin") + end + local server, server_table = cache.get_upload_server(flags["server"]) + if not server then return nil, server_table end + return add_files_to_server(not flags["no-refresh"], files, server, server_table) +end + + +return add diff --git a/Utils/luarocks/lua/luarocks/admin_remove.lua b/Utils/luarocks/lua/luarocks/admin_remove.lua new file mode 100644 index 000000000..621f13178 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/admin_remove.lua @@ -0,0 +1,92 @@ + +--- Module implementing the luarocks-admin "remove" command. +-- Removes a rock or rockspec from a rocks server. +local admin_remove = {} +package.loaded["luarocks.admin_remove"] = admin_remove + +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local index = require("luarocks.index") +local fs = require("luarocks.fs") +local cache = require("luarocks.cache") + +util.add_run_function(admin_remove) +admin_remove.help_summary = "Remove a rock or rockspec from a rocks server." +admin_remove.help_arguments = "[--server=] [--no-refresh] {|...}" +admin_remove.help = [[ +Arguments are local files, which may be rockspecs or rocks. +The flag --server indicates which server to use. +If not given, the default server set in the upload_server variable +from the configuration file is used instead. +The flag --no-refresh indicates the local cache should not be refreshed +prior to generation of the updated manifest. +]] + +local function remove_files_from_server(refresh, rockfiles, server, upload_server) + assert(type(refresh) == "boolean" or not refresh) + assert(type(rockfiles) == "table") + assert(type(server) == "string") + assert(type(upload_server) == "table" or not upload_server) + + local download_url, login_url = cache.get_server_urls(server, upload_server) + local at = fs.current_dir() + local refresh_fn = refresh and cache.refresh_local_cache or cache.split_server_url + + local local_cache, protocol, server_path, user, password = refresh_fn(server, download_url, cfg.upload_user, cfg.upload_password) + if not local_cache then + return nil, protocol + end + if protocol ~= "rsync" then + return nil, "This command requires 'rsync', check your configuration." + end + + local ok, err = fs.change_dir(at) + if not ok then return nil, err end + + local nr_files = 0 + for _, rockfile in ipairs(rockfiles) do + local basename = dir.base_name(rockfile) + local file = dir.path(local_cache, basename) + util.printout("Removing file "..file.."...") + fs.delete(file) + if not fs.exists(file) then + nr_files = nr_files + 1 + else + util.printerr("Failed removing "..file) + end + end + if nr_files == 0 then + return nil, "No files removed." + end + + local ok, err = fs.change_dir(local_cache) + if not ok then return nil, err end + + util.printout("Updating manifest...") + manif.make_manifest(local_cache, "one", true) + util.printout("Updating index.html...") + index.make_index(local_cache) + + local srv, path = server_path:match("([^/]+)(/.+)") + local cmd = cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." --delete -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/" + + util.printout(cmd) + fs.execute(cmd) + + return true +end + +function admin_remove.command(flags, ...) + local files = {...} + if #files < 1 then + return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin") + end + local server, server_table = cache.get_upload_server(flags["server"]) + if not server then return nil, server_table end + return remove_files_from_server(not flags["no-refresh"], files, server, server_table) +end + + +return admin_remove diff --git a/Utils/luarocks/lua/luarocks/build.lua b/Utils/luarocks/lua/luarocks/build.lua new file mode 100644 index 000000000..96b232ffb --- /dev/null +++ b/Utils/luarocks/lua/luarocks/build.lua @@ -0,0 +1,415 @@ + +--- Module implementing the LuaRocks "build" command. +-- Builds a rock, compiling its C parts if any. +local build = {} +package.loaded["luarocks.build"] = build + +local pack = require("luarocks.pack") +local path = require("luarocks.path") +local util = require("luarocks.util") +local repos = require("luarocks.repos") +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local deps = require("luarocks.deps") +local manif = require("luarocks.manif") +local remove = require("luarocks.remove") +local cfg = require("luarocks.cfg") + +util.add_run_function(build) +build.help_summary = "Build/compile a rock." +build.help_arguments = "[--pack-binary-rock] [--keep] {|| []}" +build.help = [[ +Build and install a rock, compiling its C parts if any. +Argument may be a rockspec file, a source rock file +or the name of a rock to be fetched from a repository. + +--pack-binary-rock Do not install rock. Instead, produce a .rock file + with the contents of compilation in the current + directory. + +--keep Do not remove previously installed versions of the + rock after building a new one. This behavior can + be made permanent by setting keep_other_versions=true + in the configuration file. + +--branch= Override the `source.branch` field in the loaded + rockspec. Allows to specify a different branch to + fetch. Particularly for SCM rocks. + +--only-deps Installs only the dependencies of the rock. + +]]..util.deps_mode_help() + +--- Install files to a given location. +-- Takes a table where the array part is a list of filenames to be copied. +-- In the hash part, other keys, if is_module_path is set, are identifiers +-- in Lua module format, to indicate which subdirectory the file should be +-- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo") +-- will copy src/bar.lua to boo/foo. +-- @param files table or nil: A table containing a list of files to copy in +-- the format described above. If nil is passed, this function is a no-op. +-- Directories should be delimited by forward slashes as in internet URLs. +-- @param location string: The base directory files should be copied to. +-- @param is_module_path boolean: True if string keys in files should be +-- interpreted as dotted module paths. +-- @param perms string: Permissions of the newly created files installed. +-- Directories are always created with the default permissions. +-- @return boolean or (nil, string): True if succeeded or +-- nil and an error message. +local function install_files(files, location, is_module_path, perms) + assert(type(files) == "table" or not files) + assert(type(location) == "string") + if files then + for k, file in pairs(files) do + local dest = location + local filename = dir.base_name(file) + if type(k) == "string" then + local modname = k + if is_module_path then + dest = dir.path(location, path.module_to_path(modname)) + local ok, err = fs.make_dir(dest) + if not ok then return nil, err end + if filename:match("%.lua$") then + local basename = modname:match("([^.]+)$") + filename = basename..".lua" + end + else + dest = dir.path(location, dir.dir_name(modname)) + local ok, err = fs.make_dir(dest) + if not ok then return nil, err end + filename = dir.base_name(modname) + end + else + local ok, err = fs.make_dir(dest) + if not ok then return nil, err end + end + local ok = fs.copy(dir.path(file), dir.path(dest, filename), perms) + if not ok then + return nil, "Failed copying "..file + end + end + end + return true +end + +--- Write to the current directory the contents of a table, +-- where each key is a file name and its value is the file content. +-- @param files table: The table of files to be written. +local function extract_from_rockspec(files) + for name, content in pairs(files) do + local fd = io.open(dir.path(fs.current_dir(), name), "w+") + fd:write(content) + fd:close() + end +end + +--- Applies patches inlined in the build.patches section +-- and extracts files inlined in the build.extra_files section +-- of a rockspec. +-- @param rockspec table: A rockspec table. +-- @return boolean or (nil, string): True if succeeded or +-- nil and an error message. +function build.apply_patches(rockspec) + assert(type(rockspec) == "table") + + local build_spec = rockspec.build + if build_spec.extra_files then + extract_from_rockspec(build_spec.extra_files) + end + if build_spec.patches then + extract_from_rockspec(build_spec.patches) + for patch, patchdata in util.sortedpairs(build_spec.patches) do + util.printout("Applying patch "..patch.."...") + local ok, err = fs.apply_patch(tostring(patch), patchdata) + if not ok then + return nil, "Failed applying patch "..patch + end + end + end + return true +end + +local function install_default_docs(name, version) + local patterns = { "readme", "license", "copying", ".*%.md" } + local dest = dir.path(path.install_dir(name, version), "doc") + local has_dir = false + for file in fs.dir() do + for _, pattern in ipairs(patterns) do + if file:lower():match("^"..pattern) then + if not has_dir then + fs.make_dir(dest) + has_dir = true + end + fs.copy(file, dest, cfg.perm_read) + break + end + end + end +end + +--- Build and install a rock given a rockspec. +-- @param rockspec_file string: local or remote filename of a rockspec. +-- @param need_to_fetch boolean: true if sources need to be fetched, +-- false if the rockspec was obtained from inside a source rock. +-- @param minimal_mode boolean: true if there's no need to fetch, +-- unpack or change dir (this is used by "luarocks make"). Implies +-- need_to_fetch = false. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for no trees. +-- @param build_only_deps boolean: true to build the listed dependencies only. +-- @return (string, string) or (nil, string, [string]): Name and version of +-- installed rock if succeeded or nil and an error message followed by an error code. +function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode, build_only_deps) + assert(type(rockspec_file) == "string") + assert(type(need_to_fetch) == "boolean") + + local rockspec, err, errcode = fetch.load_rockspec(rockspec_file) + if err then + return nil, err, errcode + elseif not rockspec.build then + return nil, "Rockspec error: build table not specified" + elseif not rockspec.build.type then + return nil, "Rockspec error: build type not specified" + end + + local ok + if not build_only_deps then + ok, err, errcode = deps.check_external_deps(rockspec, "build") + if err then + return nil, err, errcode + end + end + + if deps_mode == "none" then + util.printerr("Warning: skipping dependency checks.") + else + local ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) + if err then + return nil, err, errcode + end + end + + local name, version = rockspec.name, rockspec.version + if build_only_deps then + util.printout("Stopping after installing dependencies for " ..name.." "..version) + util.printout() + return name, version + end + + if repos.is_installed(name, version) then + repos.delete_version(name, version, deps_mode) + end + + if not minimal_mode then + local source_dir + if need_to_fetch then + ok, source_dir, errcode = fetch.fetch_sources(rockspec, true) + if not ok then + return nil, source_dir, errcode + end + local ok, err = fs.change_dir(source_dir) + if not ok then return nil, err end + elseif rockspec.source.file then + local ok, err = fs.unpack_archive(rockspec.source.file) + if not ok then + return nil, err + end + end + fs.change_dir(rockspec.source.dir) + end + + local dirs = { + lua = { name = path.lua_dir(name, version), is_module_path = true, perms = cfg.perm_read }, + lib = { name = path.lib_dir(name, version), is_module_path = true, perms = cfg.perm_exec }, + conf = { name = path.conf_dir(name, version), is_module_path = false, perms = cfg.perm_read }, + bin = { name = path.bin_dir(name, version), is_module_path = false, perms = cfg.perm_exec }, + } + + for _, d in pairs(dirs) do + local ok, err = fs.make_dir(d.name) + if not ok then return nil, err end + end + local rollback = util.schedule_function(function() + fs.delete(path.install_dir(name, version)) + fs.remove_dir_if_empty(path.versions_dir(name)) + end) + + local build_spec = rockspec.build + + if not minimal_mode then + ok, err = build.apply_patches(rockspec) + if err then + return nil, err + end + end + + if build_spec.type ~= "none" then + + -- Temporary compatibility + if build_spec.type == "module" then + util.printout("Do not use 'module' as a build type. Use 'builtin' instead.") + build_spec.type = "builtin" + end + + if cfg.accepted_build_types and util.array_contains(cfg.accepted_build_types, build_spec.type) then + return nil, "This rockspec uses the '"..build_spec.type.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration." + end + + local build_type + ok, build_type = pcall(require, "luarocks.build." .. build_spec.type) + if not ok or not type(build_type) == "table" then + return nil, "Failed initializing build back-end for build type '"..build_spec.type.."': "..build_type + end + + ok, err = build_type.run(rockspec) + if not ok then + return nil, "Build error: " .. err + end + end + + if build_spec.install then + for id, install_dir in pairs(dirs) do + ok, err = install_files(build_spec.install[id], install_dir.name, install_dir.is_module_path, install_dir.perms) + if not ok then + return nil, err + end + end + end + + local copy_directories = build_spec.copy_directories + local copying_default = false + if not copy_directories then + copy_directories = {"doc"} + copying_default = true + end + + local any_docs = false + for _, copy_dir in pairs(copy_directories) do + if fs.is_dir(copy_dir) then + local dest = dir.path(path.install_dir(name, version), copy_dir) + fs.make_dir(dest) + fs.copy_contents(copy_dir, dest) + any_docs = true + else + if not copying_default then + return nil, "Directory '"..copy_dir.."' not found" + end + end + end + + if not any_docs then + install_default_docs(name, version) + end + + for _, d in pairs(dirs) do + fs.remove_dir_if_empty(d.name) + end + + fs.pop_dir() + + fs.copy(rockspec.local_filename, path.rockspec_file(name, version), cfg.perm_read) + if need_to_fetch then + fs.pop_dir() + end + + ok, err = manif.make_rock_manifest(name, version) + if err then return nil, err end + + ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode) + if err then return nil, err end + + util.remove_scheduled_function(rollback) + rollback = util.schedule_function(function() + repos.delete_version(name, version, deps_mode) + end) + + ok, err = repos.run_hook(rockspec, "post_install") + if err then return nil, err end + + util.announce_install(rockspec) + util.remove_scheduled_function(rollback) + return name, version +end + +--- Build and install a rock. +-- @param rock_file string: local or remote filename of a rock. +-- @param need_to_fetch boolean: true if sources need to be fetched, +-- false if the rockspec was obtained from inside a source rock. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +-- @param build_only_deps boolean: true to build the listed dependencies only. +-- @return boolean or (nil, string, [string]): True if build was successful, +-- or false and an error message and an optional error code. +function build.build_rock(rock_file, need_to_fetch, deps_mode, build_only_deps) + assert(type(rock_file) == "string") + assert(type(need_to_fetch) == "boolean") + + local ok, err, errcode + local unpack_dir + unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file) + if not unpack_dir then + return nil, err, errcode + end + local rockspec_file = path.rockspec_name_from_rock(rock_file) + ok, err = fs.change_dir(unpack_dir) + if not ok then return nil, err end + ok, err, errcode = build.build_rockspec(rockspec_file, need_to_fetch, false, deps_mode, build_only_deps) + fs.pop_dir() + return ok, err, errcode +end + +local function do_build(name, version, deps_mode, build_only_deps) + if name:match("%.rockspec$") then + return build.build_rockspec(name, true, false, deps_mode, build_only_deps) + elseif name:match("%.src%.rock$") then + return build.build_rock(name, false, deps_mode, build_only_deps) + elseif name:match("%.all%.rock$") then + local install = require("luarocks.install") + local install_fun = build_only_deps and install.install_binary_rock_deps or install.install_binary_rock + return install_fun(name, deps_mode) + elseif name:match("%.rock$") then + return build.build_rock(name, true, deps_mode, build_only_deps) + elseif not name:match(dir.separator) then + local search = require("luarocks.search") + return search.act_on_src_or_rockspec(do_build, name:lower(), version, nil, deps_mode, build_only_deps) + end + return nil, "Don't know what to do with "..name +end + +--- Driver function for "build" command. +-- @param name string: A local or remote rockspec or rock file. +-- If a package name is given, forwards the request to "search" and, +-- if returned a result, installs the matching rock. +-- @param version string: When passing a package name, a version number may +-- also be given. +-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an +-- error message otherwise. exitcode is optionally returned. +function build.command(flags, name, version) + if type(name) ~= "string" then + return nil, "Argument missing. "..util.see_help("build") + end + assert(type(version) == "string" or not version) + + if flags["pack-binary-rock"] then + return pack.pack_binary_rock(name, version, do_build, name, version, deps.get_deps_mode(flags)) + else + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end + ok, err = do_build(name, version, deps.get_deps_mode(flags), flags["only-deps"]) + if not ok then return nil, err end + name, version = ok, err + + if (not flags["only-deps"]) and (not flags["keep"]) and not cfg.keep_other_versions then + local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) + if not ok then util.printerr(err) end + end + + manif.check_dependencies(nil, deps.get_deps_mode(flags)) + return name, version + end +end + +return build diff --git a/Utils/luarocks/lua/luarocks/cache.lua b/Utils/luarocks/lua/luarocks/cache.lua new file mode 100644 index 000000000..4a95f70e3 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/cache.lua @@ -0,0 +1,78 @@ + +--- Module handling the LuaRocks local cache. +-- Adds a rock or rockspec to a rocks server. +local cache = {} +package.loaded["luarocks.cache"] = cache + +local fs = require("luarocks.fs") +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +function cache.get_upload_server(server) + if not server then server = cfg.upload_server end + if not server then + return nil, "No server specified and no default configured with upload_server." + end + return server, cfg.upload_servers and cfg.upload_servers[server] +end + +function cache.get_server_urls(server, upload_server) + local download_url = server + local login_url = nil + if upload_server then + if upload_server.rsync then download_url = "rsync://"..upload_server.rsync + elseif upload_server.http then download_url = "http://"..upload_server.http + elseif upload_server.ftp then download_url = "ftp://"..upload_server.ftp + end + + if upload_server.ftp then login_url = "ftp://"..upload_server.ftp + elseif upload_server.sftp then login_url = "sftp://"..upload_server.sftp + end + end + return download_url, login_url +end + +function cache.split_server_url(server, url, user, password) + local protocol, server_path = dir.split_url(url) + if server_path:match("@") then + local credentials + credentials, server_path = server_path:match("([^@]*)@(.*)") + if credentials:match(":") then + user, password = credentials:match("([^:]*):(.*)") + else + user = credentials + end + end + local local_cache = cfg.local_cache .. "/" .. server + return local_cache, protocol, server_path, user, password +end + +function cache.refresh_local_cache(server, url, user, password) + local local_cache, protocol, server_path, user, password = cache.split_server_url(server, url, user, password) + local ok, err = fs.make_dir(local_cache) + if not ok then + return nil, "Failed creating local cache dir: "..err + end + fs.change_dir(local_cache) + if not ok then return nil, err end + util.printout("Refreshing cache "..local_cache.."...") + + -- TODO abstract away explicit 'wget' call + local ok = false + if protocol == "rsync" then + local srv, path = server_path:match("([^/]+)(/.+)") + ok = fs.execute(cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." -e ssh "..user.."@"..srv..":"..path.."/ "..local_cache.."/") + else + local login_info = "" + if user then login_info = " --user="..user end + if password then login_info = login_info .. " --password="..password end + ok = fs.execute(cfg.variables.WGET.." --no-cache -q -m -np -nd "..protocol.."://"..server_path..login_info) + end + if not ok then + return nil, "Failed downloading cache." + end + return local_cache, protocol, server_path, user, password +end + +return cache diff --git a/Utils/luarocks/lua/luarocks/cfg.lua b/Utils/luarocks/lua/luarocks/cfg.lua new file mode 100644 index 000000000..c997c1240 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/cfg.lua @@ -0,0 +1,760 @@ +--- Configuration for LuaRocks. +-- Tries to load the user's configuration file and +-- defines defaults for unset values. See the +-- config +-- file format documentation for details. +-- +-- End-users shouldn't edit this file. They can override any defaults +-- set in this file using their system-wide or user-specific configuration +-- files. Run `luarocks` with no arguments to see the locations of +-- these files in your platform. + +local rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION = + rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION + +--module("luarocks.cfg") +local cfg = {} +package.loaded["luarocks.cfg"] = cfg + +local util = require("luarocks.util") + +cfg.lua_version = _VERSION:match(" (5%.[123])$") or "5.1" +local version_suffix = cfg.lua_version:gsub("%.", "_") + +-- Load site-local global configurations +local ok, site_config = pcall(require, "luarocks.site_config_"..version_suffix) +if not ok then + ok, site_config = pcall(require, "luarocks.site_config") +end +if not ok then + io.stderr:write("Site-local luarocks/site_config.lua file not found. Incomplete installation?\n") + site_config = {} +end + +cfg.program_version = "2.4.2" +cfg.program_series = "2.4" +cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series +cfg.variables = {} +cfg.rocks_trees = {} +cfg.platforms = {} + +local persist = require("luarocks.persist") + +cfg.errorcodes = setmetatable({ + OK = 0, + UNSPECIFIED = 1, + PERMISSIONDENIED = 2, + CONFIGFILE = 3, + CRASH = 99 +},{ + __index = function(t, key) + local val = rawget(t, key) + if not val then + error("'"..tostring(key).."' is not a valid errorcode", 2) + end + return val + end +}) + + +local popen_ok, popen_result = pcall(io.popen, "") +if popen_ok then + if popen_result then + popen_result:close() + end +else + io.stderr:write("Your version of Lua does not support io.popen,\n") + io.stderr:write("which is required by LuaRocks. Please check your Lua installation.\n") + os.exit(cfg.errorcodes.UNSPECIFIED) +end + +-- System detection: + +-- A proper installation of LuaRocks will hardcode the system +-- and proc values with site_config.LUAROCKS_UNAME_S and site_config.LUAROCKS_UNAME_M, +-- so that this detection does not run every time. When it is +-- performed, we use the Unix way to identify the system, +-- even on Windows (assuming UnxUtils or Cygwin). +local system = site_config.LUAROCKS_UNAME_S or io.popen("uname -s"):read("*l") +local proc = site_config.LUAROCKS_UNAME_M or io.popen("uname -m"):read("*l") +if proc:match("i[%d]86") then + cfg.target_cpu = "x86" +elseif proc:match("amd64") or proc:match("x86_64") then + cfg.target_cpu = "x86_64" +elseif proc:match("Power Macintosh") then + cfg.target_cpu = "powerpc" + else + cfg.target_cpu = proc +end + +if system == "FreeBSD" then + cfg.platforms.unix = true + cfg.platforms.freebsd = true + cfg.platforms.bsd = true +elseif system == "OpenBSD" then + cfg.platforms.unix = true + cfg.platforms.openbsd = true + cfg.platforms.bsd = true +elseif system == "NetBSD" then + cfg.platforms.unix = true + cfg.platforms.netbsd = true + cfg.platforms.bsd = true +elseif system == "Darwin" then + cfg.platforms.unix = true + cfg.platforms.macosx = true + cfg.platforms.bsd = true +elseif system == "Linux" then + cfg.platforms.unix = true + cfg.platforms.linux = true +elseif system == "SunOS" then + cfg.platforms.unix = true + cfg.platforms.solaris = true +elseif system and system:match("^CYGWIN") then + cfg.platforms.unix = true + cfg.platforms.cygwin = true +elseif system and system:match("^MSYS") then + cfg.platforms.unix = true + cfg.platforms.msys = true + cfg.platforms.cygwin = true +elseif system and system:match("^Windows") then + cfg.platforms.windows = true + cfg.platforms.win32 = true +elseif system and system:match("^MINGW") then + cfg.platforms.windows = true + cfg.platforms.mingw32 = true + cfg.platforms.win32 = true +elseif system == "Haiku" then + cfg.platforms.unix = true + cfg.platforms.haiku = true +else + cfg.platforms.unix = true + -- Fall back to Unix in unknown systems. +end + +-- Set order for platform overrides. +-- More general platform identifiers should be listed first, +-- more specific ones later. +local platform_order = { + -- Unixes + "unix", + "bsd", + "solaris", + "netbsd", + "openbsd", + "freebsd", + "linux", + "macosx", + "cygwin", + "msys", + "haiku", + -- Windows + "win32", + "mingw32", + "windows", +} + +-- Path configuration: +local sys_config_file, home_config_file +local sys_config_file_default, home_config_file_default +local sys_config_dir, home_config_dir +local sys_config_ok, home_config_ok = false, false +local extra_luarocks_module_dir +sys_config_dir = site_config.LUAROCKS_SYSCONFDIR or site_config.LUAROCKS_PREFIX +if cfg.platforms.windows then + cfg.home = os.getenv("APPDATA") or "c:" + sys_config_dir = sys_config_dir or "c:/luarocks" + home_config_dir = cfg.home.."/luarocks" + cfg.home_tree = cfg.home.."/luarocks/" +else + cfg.home = os.getenv("HOME") or "" + sys_config_dir = sys_config_dir or "/etc/luarocks" + home_config_dir = cfg.home.."/.luarocks" + cfg.home_tree = (os.getenv("USER") ~= "root") and cfg.home.."/.luarocks/" +end + +-- Create global environment for the config files; +local env_for_config_file = function() + local e + e = { + home = cfg.home, + lua_version = cfg.lua_version, + platforms = util.make_shallow_copy(cfg.platforms), + processor = cfg.target_cpu, -- remains for compat reasons + target_cpu = cfg.target_cpu, -- replaces `processor` + os_getenv = os.getenv, + dump_env = function() + -- debug function, calling it from a config file will show all + -- available globals to that config file + print(util.show_table(e, "global environment")) + end, + } + return e +end + +-- Merge values from config files read into the `cfg` table +local merge_overrides = function(overrides) + -- remove some stuff we do not want to integrate + overrides.os_getenv = nil + overrides.dump_env = nil + -- remove tables to be copied verbatim instead of deeply merged + if overrides.rocks_trees then cfg.rocks_trees = nil end + if overrides.rocks_servers then cfg.rocks_servers = nil end + -- perform actual merge + util.deep_merge(cfg, overrides) +end + +-- load config file from a list until first succesful one. Info is +-- added to `cfg` module table, returns filepath of succesfully loaded +-- file or nil if it failed +local load_config_file = function(list) + for _, filepath in ipairs(list) do + local result, err, errcode = persist.load_into_table(filepath, env_for_config_file()) + if (not result) and errcode ~= "open" then + -- errcode is either "load" or "run"; bad config file, so error out + io.stderr:write(err.."\n") + os.exit(cfg.errorcodes.CONFIGFILE) + end + if result then + -- succes in loading and running, merge contents and exit + merge_overrides(result) + return filepath + end + end + return nil -- nothing was loaded +end + + +-- Load system configuration file +do + sys_config_file_default = sys_config_dir.."/config-"..cfg.lua_version..".lua" + sys_config_file = load_config_file({ + site_config.LUAROCKS_SYSCONFIG or sys_config_file_default, + sys_config_dir.."/config.lua", + }) + sys_config_ok = (sys_config_file ~= nil) +end + +-- Load user configuration file (if allowed) +if not site_config.LUAROCKS_FORCE_CONFIG then + + home_config_file_default = home_config_dir.."/config-"..cfg.lua_version..".lua" + + local config_env_var = "LUAROCKS_CONFIG_" .. version_suffix + local config_env_value = os.getenv(config_env_var) + if not config_env_value then + config_env_var = "LUAROCKS_CONFIG" + config_env_value = os.getenv(config_env_var) + end + + -- first try environment provided file, so we can explicitly warn when it is missing + if config_env_value then + local list = { config_env_value } + home_config_file = load_config_file(list) + home_config_ok = (home_config_file ~= nil) + if not home_config_ok then + io.stderr:write("Warning: could not load configuration file `"..config_env_value.."` given in environment variable "..config_env_var.."\n") + end + end + + -- try the alternative defaults if there was no environment specified file or it didn't work + if not home_config_ok then + local list = { + home_config_file_default, + home_config_dir.."/config.lua", + } + home_config_file = load_config_file(list) + home_config_ok = (home_config_file ~= nil) + end +end + + +if not next(cfg.rocks_trees) then + if cfg.home_tree then + table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree } ) + end + if site_config.LUAROCKS_ROCKS_TREE then + table.insert(cfg.rocks_trees, { name = "system", root = site_config.LUAROCKS_ROCKS_TREE } ) + end +end + +-- update platforms list; keyed -> array +do + -- if explicitly given by user, + if cfg.platforms[1] then + local is_windows = cfg.platforms.windows + -- Clear auto-detected values + for k, _ in pairs(cfg.platforms) do + if type(k) == "string" then + cfg.platforms[k] = nil + end + end + -- and set the ones given by the user. + for _, plat in ipairs(cfg.platforms) do + cfg.platforms[plat] = true + end + -- If no major platform family was set by the user, + if not (cfg.platforms.unix or cfg.platforms.windows) then + -- set some fallback defaults in case the user provides an incomplete configuration. + -- LuaRocks expects a set of defaults to be available. + -- This is used for setting defaults here only; the platform overrides + -- will use only the user's list. + if is_windows then + cfg.platforms.windows = true + table.insert(cfg.platforms, "windows") + else + cfg.platforms.unix = true + table.insert(cfg.platforms, "unix") + end + end + else + -- Sort detected platform defaults + local order = {} + for i, v in ipairs(platform_order) do + order[v] = i + end + local entries = {} + for k, v in pairs(cfg.platforms) do + if type(k) == "string" and v == true then + table.insert(entries, k) + end + end + table.sort(entries, function(a, b) return order[a] < order[b] end) + util.deep_merge(cfg.platforms, entries) + end +end + +-- Configure defaults: +local defaults = { + + local_by_default = false, + accept_unknown_fields = false, + fs_use_modules = true, + hooks_enabled = true, + deps_mode = "one", + check_certificates = false, + perm_read = "0644", + perm_exec = "0755", + + lua_modules_path = "/share/lua/"..cfg.lua_version, + lib_modules_path = "/lib/lua/"..cfg.lua_version, + rocks_subdir = site_config.LUAROCKS_ROCKS_SUBDIR or "/lib/luarocks/rocks", + + arch = "unknown", + lib_extension = "unknown", + obj_extension = "unknown", + link_lua_explicitly = false, + + rocks_servers = { + { + "https://luarocks.org", + "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/", + "http://luafr.org/moonrocks/", + "http://luarocks.logiceditor.com/rocks", + } + }, + disabled_servers = {}, + + upload = { + server = "https://luarocks.org", + tool_version = "1.0.0", + api_version = "1", + }, + + lua_extension = "lua", + lua_interpreter = site_config.LUA_INTERPRETER or "lua", + downloader = site_config.LUAROCKS_DOWNLOADER or "wget", + md5checker = site_config.LUAROCKS_MD5CHECKER or "md5sum", + connection_timeout = 30, -- 0 = no timeout + + variables = { + MAKE = "make", + CC = "cc", + LD = "ld", + + CVS = "cvs", + GIT = "git", + SSCM = "sscm", + SVN = "svn", + HG = "hg", + + RSYNC = "rsync", + WGET = "wget", + SCP = "scp", + CURL = "curl", + + PWD = "pwd", + MKDIR = "mkdir", + RMDIR = "rmdir", + CP = "cp", + LS = "ls", + RM = "rm", + FIND = "find", + TEST = "test", + CHMOD = "chmod", + MKTEMP = "mktemp", + + ZIP = "zip", + UNZIP = "unzip -n", + GUNZIP = "gunzip", + BUNZIP2 = "bunzip2", + TAR = "tar", + + MD5SUM = "md5sum", + OPENSSL = "openssl", + MD5 = "md5", + STAT = "stat", + TOUCH = "touch", + + CMAKE = "cmake", + SEVENZ = "7z", + + RSYNCFLAGS = "--exclude=.git -Oavz", + STATFLAG = "-c '%a'", + CURLNOCERTFLAG = "", + WGETNOCERTFLAG = "", + }, + + external_deps_subdirs = site_config.LUAROCKS_EXTERNAL_DEPS_SUBDIRS or { + bin = "bin", + lib = "lib", + include = "include" + }, + runtime_external_deps_subdirs = site_config.LUAROCKS_RUNTIME_EXTERNAL_DEPS_SUBDIRS or { + bin = "bin", + lib = "lib", + include = "include" + }, + + rocks_provided = {} +} + +if cfg.platforms.windows then + local full_prefix = (site_config.LUAROCKS_PREFIX or (os.getenv("PROGRAMFILES")..[[\LuaRocks]])) + extra_luarocks_module_dir = full_prefix.."/lua/?.lua" + + home_config_file = home_config_file and home_config_file:gsub("\\","/") + defaults.fs_use_modules = false + defaults.arch = "win32-"..cfg.target_cpu + defaults.lib_extension = "dll" + defaults.external_lib_extension = "dll" + defaults.obj_extension = "obj" + defaults.external_deps_dirs = { "c:/external/" } + defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR and site_config.LUA_BINDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/bin" + defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR and site_config.LUA_INCDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/include" + defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR and site_config.LUA_LIBDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/lib" + + defaults.makefile = "Makefile.win" + defaults.variables.MAKE = "nmake" + defaults.variables.CC = "cl" + defaults.variables.RC = "rc" + defaults.variables.WRAPPER = full_prefix.."\\rclauncher.c" + defaults.variables.LD = "link" + defaults.variables.MT = "mt" + defaults.variables.LUALIB = "lua"..cfg.lua_version..".lib" + defaults.variables.CFLAGS = "/nologo /MD /O2" + defaults.variables.LIBFLAG = "/nologo /dll" + + local bins = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", + "MKDIR", "MV", "PWD", "RMDIR", "TEST", "UNAME", "WGET" } + for _, var in ipairs(bins) do + if defaults.variables[var] then + defaults.variables[var] = full_prefix.."\\tools\\"..defaults.variables[var] + end + end + + defaults.external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "?.lib", "?.dll", "lib?.dll" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "?.dll", "lib?.dll" }, + include = { "?.h" } + } + defaults.export_path = "SET PATH=%s" + defaults.export_path_separator = ";" + defaults.export_lua_path = "SET LUA_PATH=%s" + defaults.export_lua_cpath = "SET LUA_CPATH=%s" + defaults.wrapper_suffix = ".bat" + + local localappdata = os.getenv("LOCALAPPDATA") + if not localappdata then + -- for Windows versions below Vista + localappdata = os.getenv("USERPROFILE").."/Local Settings/Application Data" + end + defaults.local_cache = localappdata.."/LuaRocks/Cache" + defaults.web_browser = "start" +end + +if cfg.platforms.mingw32 then + defaults.obj_extension = "o" + defaults.cmake_generator = "MinGW Makefiles" + defaults.variables.MAKE = "mingw32-make" + defaults.variables.CC = "mingw32-gcc" + defaults.variables.RC = "windres" + defaults.variables.LD = "mingw32-gcc" + defaults.variables.CFLAGS = "-O2" + defaults.variables.LIBFLAG = "-shared" + defaults.makefile = "Makefile" + defaults.external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + -- mingw lookup list from http://stackoverflow.com/a/15853231/1793220 + -- ...should we keep ?.lib at the end? It's not in the above list. + lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "cyg?.dll", "?.dll", "lib?.dll" }, + include = { "?.h" } + } + +end + +if cfg.platforms.unix then + defaults.lib_extension = "so" + defaults.external_lib_extension = "so" + defaults.obj_extension = "o" + defaults.external_deps_dirs = { "/usr/local", "/usr" } + defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR or "/usr/local/bin" + defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR or "/usr/local/include" + defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR or "/usr/local/lib" + defaults.variables.CFLAGS = "-O2" + defaults.cmake_generator = "Unix Makefiles" + defaults.variables.CC = "gcc" + defaults.variables.LD = "gcc" + defaults.gcc_rpath = true + defaults.variables.LIBFLAG = "-shared" + defaults.external_deps_patterns = { + bin = { "?" }, + lib = { "lib?.a", "lib?.so", "lib?.so.*" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?" }, + lib = { "lib?.so", "lib?.so.*" }, + include = { "?.h" } + } + defaults.export_path = "export PATH='%s'" + defaults.export_path_separator = ":" + defaults.export_lua_path = "export LUA_PATH='%s'" + defaults.export_lua_cpath = "export LUA_CPATH='%s'" + defaults.wrapper_suffix = "" + defaults.local_cache = cfg.home.."/.cache/luarocks" + if not defaults.variables.CFLAGS:match("-fPIC") then + defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC" + end + defaults.web_browser = "xdg-open" +end + +if cfg.platforms.cygwin then + defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds + defaults.arch = "cygwin-"..cfg.target_cpu + defaults.cmake_generator = "Unix Makefiles" + defaults.variables.CC = "echo -llua | xargs gcc" + defaults.variables.LD = "echo -llua | xargs gcc" + defaults.variables.LIBFLAG = "-shared" + defaults.link_lua_explicitly = true +end + +if cfg.platforms.msys then + -- msys is basically cygwin made out of mingw, meaning the subsytem is unixish + -- enough, yet we can freely mix with native win32 + defaults.external_deps_patterns = { + bin = { "?.exe", "?.bat", "?" }, + lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a", + "lib?.a", "lib?.dll", "?.dll", "?.lib" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "lib?.so", "?.dll", "lib?.dll" }, + include = { "?.h" } + } +end + + +if cfg.platforms.bsd then + defaults.variables.MAKE = "gmake" + defaults.variables.STATFLAG = "-f '%OLp'" +end + +if cfg.platforms.macosx then + defaults.variables.MAKE = "make" + defaults.external_lib_extension = "dylib" + defaults.arch = "macosx-"..cfg.target_cpu + defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load" + defaults.variables.STAT = "/usr/bin/stat" + defaults.variables.STATFLAG = "-f '%A'" + local version = io.popen("sw_vers -productVersion"):read("*l") + version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3 + if version >= 10 then + version = 8 + elseif version >= 5 then + version = 5 + else + defaults.gcc_rpath = false + end + defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET=10."..version.." gcc" + defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET=10."..version.." gcc" + defaults.web_browser = "open" +end + +if cfg.platforms.linux then + defaults.arch = "linux-"..cfg.target_cpu +end + +if cfg.platforms.freebsd then + defaults.arch = "freebsd-"..cfg.target_cpu + defaults.gcc_rpath = false + defaults.variables.CC = "cc" + defaults.variables.LD = "cc" +end + +if cfg.platforms.openbsd then + defaults.arch = "openbsd-"..cfg.target_cpu +end + +if cfg.platforms.netbsd then + defaults.arch = "netbsd-"..cfg.target_cpu +end + +if cfg.platforms.solaris then + defaults.arch = "solaris-"..cfg.target_cpu + --defaults.platforms = {"unix", "solaris"} + defaults.variables.MAKE = "gmake" +end + +-- Expose some more values detected by LuaRocks for use by rockspec authors. +defaults.variables.LIB_EXTENSION = defaults.lib_extension +defaults.variables.OBJ_EXTENSION = defaults.obj_extension +defaults.variables.LUAROCKS_PREFIX = site_config.LUAROCKS_PREFIX +defaults.variables.LUA = site_config.LUA_DIR_SET and (defaults.variables.LUA_BINDIR.."/"..defaults.lua_interpreter) or defaults.lua_interpreter + +-- Add built-in modules to rocks_provided +defaults.rocks_provided["lua"] = cfg.lua_version.."-1" + +if bit32 then -- Lua 5.2+ + defaults.rocks_provided["bit32"] = cfg.lua_version.."-1" +end + +if utf8 then -- Lua 5.3+ + defaults.rocks_provided["utf8"] = cfg.lua_version.."-1" +end + +if package.loaded.jit then + -- LuaJIT + local lj_version = package.loaded.jit.version:match("LuaJIT (.*)"):gsub("%-","") + --defaults.rocks_provided["luajit"] = lj_version.."-1" + defaults.rocks_provided["luabitop"] = lj_version.."-1" +end + +-- Use defaults: + +-- Populate some arrays with values from their 'defaults' counterparts +-- if they were not already set by user. +for _, entry in ipairs({"variables", "rocks_provided"}) do + if not cfg[entry] then + cfg[entry] = {} + end + for k,v in pairs(defaults[entry]) do + if not cfg[entry][k] then + cfg[entry][k] = v + end + end +end + +-- For values not set in the config file, use values from the 'defaults' table. +local cfg_mt = { + __index = function(t, k) + local default = defaults[k] + if default then + rawset(t, k, default) + end + return default + end +} +setmetatable(cfg, cfg_mt) + +if not cfg.check_certificates then + cfg.variables.CURLNOCERTFLAG = "-k" + cfg.variables.WGETNOCERTFLAG = "--no-check-certificate" +end + +function cfg.make_paths_from_tree(tree) + local lua_path, lib_path, bin_path + if type(tree) == "string" then + lua_path = tree..cfg.lua_modules_path + lib_path = tree..cfg.lib_modules_path + bin_path = tree.."/bin" + else + lua_path = tree.lua_dir or tree.root..cfg.lua_modules_path + lib_path = tree.lib_dir or tree.root..cfg.lib_modules_path + bin_path = tree.bin_dir or tree.root.."/bin" + end + return lua_path, lib_path, bin_path +end + +function cfg.package_paths(current) + local new_path, new_cpath, new_bin = {}, {}, {} + local function add_tree_to_paths(tree) + local lua_path, lib_path, bin_path = cfg.make_paths_from_tree(tree) + table.insert(new_path, lua_path.."/?.lua") + table.insert(new_path, lua_path.."/?/init.lua") + table.insert(new_cpath, lib_path.."/?."..cfg.lib_extension) + table.insert(new_bin, bin_path) + end + if current then + add_tree_to_paths(current) + end + for _,tree in ipairs(cfg.rocks_trees) do + add_tree_to_paths(tree) + end + if extra_luarocks_module_dir then + table.insert(new_path, extra_luarocks_module_dir) + end + return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator) +end + +function cfg.init_package_paths() + local lr_path, lr_cpath, lr_bin = cfg.package_paths() + package.path = util.remove_path_dupes(package.path .. ";" .. lr_path, ";") + package.cpath = util.remove_path_dupes(package.cpath .. ";" .. lr_cpath, ";") +end + +function cfg.which_config() + local ret = { + system = { + file = sys_config_file or sys_config_file_default, + ok = sys_config_ok, + }, + user = { + file = home_config_file or home_config_file_default, + ok = home_config_ok, + } + } + ret.nearest = (ret.user.ok and ret.user.file) or ret.system.file + return ret +end + +cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch + +cfg.http_proxy = os.getenv("http_proxy") +cfg.https_proxy = os.getenv("https_proxy") +cfg.no_proxy = os.getenv("no_proxy") + +--- Check if platform was detected +-- @param query string: The platform name to check. +-- @return boolean: true if LuaRocks is currently running on queried platform. +function cfg.is_platform(query) + assert(type(query) == "string") + + for _, platform in ipairs(cfg.platforms) do + if platform == query then + return true + end + end +end + +return cfg diff --git a/Utils/luarocks/lua/luarocks/command_line.lua b/Utils/luarocks/lua/luarocks/command_line.lua new file mode 100644 index 000000000..ecf3a61b1 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/command_line.lua @@ -0,0 +1,199 @@ + +--- Functions for command-line scripts. +local command_line = {} + +local unpack = unpack or table.unpack + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local path = require("luarocks.path") +local dir = require("luarocks.dir") +local deps = require("luarocks.deps") +local fs = require("luarocks.fs") + +local program = util.this_program("luarocks") + +local function error_handler(err) + return debug.traceback("LuaRocks "..cfg.program_version.. + " bug (please report at https://github.com/keplerproject/luarocks/issues).\n"..err, 2) +end + +--- Display an error message and exit. +-- @param message string: The error message. +-- @param exitcode number: the exitcode to use +local function die(message, exitcode) + assert(type(message) == "string") + util.printerr("\nError: "..message) + + local ok, err = xpcall(util.run_scheduled_functions, error_handler) + if not ok then + util.printerr("\nError: "..err) + exitcode = cfg.errorcodes.CRASH + end + + os.exit(exitcode or cfg.errorcodes.UNSPECIFIED) +end + +local function replace_tree(flags, tree) + tree = dir.normalize(tree) + flags["tree"] = tree + path.use_tree(tree) +end + +--- Main command-line processor. +-- Parses input arguments and calls the appropriate driver function +-- to execute the action requested on the command-line, forwarding +-- to it any additional arguments passed by the user. +-- Uses the global table "commands", which contains +-- the loaded modules representing commands. +-- @param ... string: Arguments given on the command-line. +function command_line.run_command(...) + local args = {...} + local cmdline_vars = {} + for i = #args, 1, -1 do + local arg = args[i] + if arg:match("^[^-][^=]*=") then + local var, val = arg:match("^([A-Z_][A-Z0-9_]*)=(.*)") + if val then + cmdline_vars[var] = val + table.remove(args, i) + else + die("Invalid assignment: "..arg) + end + end + end + local nonflags = { util.parse_flags(unpack(args)) } + local flags = table.remove(nonflags, 1) + if flags.ERROR then + die(flags.ERROR.." See --help.") + end + + if flags["from"] then flags["server"] = flags["from"] end + if flags["only-from"] then flags["only-server"] = flags["only-from"] end + if flags["only-sources-from"] then flags["only-sources"] = flags["only-sources-from"] end + if flags["to"] then flags["tree"] = flags["to"] end + if flags["nodeps"] then + flags["deps-mode"] = "none" + end + + cfg.flags = flags + + local command + + if flags["verbose"] then -- setting it in the config file will kick-in earlier in the process + cfg.verbose = true + fs.verbose() + end + + if flags["timeout"] then -- setting it in the config file will kick-in earlier in the process + local timeout = tonumber(flags["timeout"]) + if timeout then + cfg.connection_timeout = timeout + else + die "Argument error: --timeout expects a numeric argument." + end + end + + if flags["version"] then + util.printout(program.." "..cfg.program_version) + util.printout(program_description) + util.printout() + os.exit(cfg.errorcodes.OK) + elseif flags["help"] or #nonflags == 0 then + command = "help" + else + command = table.remove(nonflags, 1) + end + command = command:gsub("-", "_") + + if cfg.local_by_default then + flags["local"] = true + end + + if flags["deps-mode"] and not deps.check_deps_mode_flag(flags["deps-mode"]) then + die("Invalid entry for --deps-mode.") + end + + if flags["branch"] then + cfg.branch = flags["branch"] + end + + if flags["tree"] then + local named = false + for _, tree in ipairs(cfg.rocks_trees) do + if type(tree) == "table" and flags["tree"] == tree.name then + if not tree.root then + die("Configuration error: tree '"..tree.name.."' has no 'root' field.") + end + replace_tree(flags, tree.root) + named = true + break + end + end + if not named then + local root_dir = fs.absolute_name(flags["tree"]) + replace_tree(flags, root_dir) + end + elseif flags["local"] then + if not cfg.home_tree then + die("The --local flag is meant for operating in a user's home directory.\n".. + "You are running as a superuser, which is intended for system-wide operation.\n".. + "To force using the superuser's home, use --tree explicitly.") + end + replace_tree(flags, cfg.home_tree) + else + local trees = cfg.rocks_trees + path.use_tree(trees[#trees]) + end + + if type(cfg.root_dir) == "string" then + cfg.root_dir = cfg.root_dir:gsub("/+$", "") + else + cfg.root_dir.root = cfg.root_dir.root:gsub("/+$", "") + end + cfg.rocks_dir = cfg.rocks_dir:gsub("/+$", "") + cfg.deploy_bin_dir = cfg.deploy_bin_dir:gsub("/+$", "") + cfg.deploy_lua_dir = cfg.deploy_lua_dir:gsub("/+$", "") + cfg.deploy_lib_dir = cfg.deploy_lib_dir:gsub("/+$", "") + + cfg.variables.ROCKS_TREE = cfg.rocks_dir + cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir + + if flags["server"] then + local protocol, path = dir.split_url(flags["server"]) + table.insert(cfg.rocks_servers, 1, protocol.."://"..path) + end + + if flags["only-server"] then + cfg.rocks_servers = { flags["only-server"] } + end + + if flags["only-sources"] then + cfg.only_sources_from = flags["only-sources"] + end + + if command ~= "help" then + for k, v in pairs(cmdline_vars) do + cfg.variables[k] = v + end + end + + if not fs.current_dir() or fs.current_dir() == "" then + die("Current directory does not exist. Please run LuaRocks from an existing directory.") + end + + if commands[command] then + local cmd = require(commands[command]) + local call_ok, ok, err, exitcode = xpcall(function() return cmd.command(flags, unpack(nonflags)) end, error_handler) + if not call_ok then + die(ok, cfg.errorcodes.CRASH) + elseif not ok then + die(err, exitcode) + end + else + die("Unknown command: "..command) + end + util.run_scheduled_functions() +end + +return command_line diff --git a/Utils/luarocks/lua/luarocks/config_cmd.lua b/Utils/luarocks/lua/luarocks/config_cmd.lua new file mode 100644 index 000000000..fe3cc637d --- /dev/null +++ b/Utils/luarocks/lua/luarocks/config_cmd.lua @@ -0,0 +1,72 @@ +--- Module implementing the LuaRocks "config" command. +-- Queries information about the LuaRocks configuration. +local config_cmd = {} + +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") + +util.add_run_function(config_cmd) +config_cmd.help_summary = "Query information about the LuaRocks configuration." +config_cmd.help_arguments = "" +config_cmd.help = [[ +--lua-incdir Path to Lua header files. + +--lua-libdir Path to Lua library files. + +--lua-ver Lua version (in major.minor format). e.g. 5.1 + +--system-config Location of the system config file. + +--user-config Location of the user config file. + +--rock-trees Rocks trees in use. First the user tree, then the system tree. +]] + +local function config_file(conf) + print(dir.normalize(conf.file)) + if conf.ok then + return true + else + return nil, "file not found" + end +end + +--- Driver function for "config" command. +-- @return boolean: True if succeeded, nil on errors. +function config_cmd.command(flags) + if flags["lua-incdir"] then + print(cfg.variables.LUA_INCDIR) + return true + end + if flags["lua-libdir"] then + print(cfg.variables.LUA_LIBDIR) + return true + end + if flags["lua-ver"] then + print(cfg.lua_version) + return true + end + local conf = cfg.which_config() + if flags["system-config"] then + return config_file(conf.system) + end + if flags["user-config"] then + return config_file(conf.user) + end + if flags["rock-trees"] then + for _, tree in ipairs(cfg.rocks_trees) do + if type(tree) == "string" then + util.printout(dir.normalize(tree)) + else + local name = tree.name and "\t"..tree.name or "" + util.printout(dir.normalize(tree.root)..name) + end + end + return true + end + + return nil, "Please provide a flag for querying configuration values. "..util.see_help("config") +end + +return config_cmd diff --git a/Utils/luarocks/lua/luarocks/deps.lua b/Utils/luarocks/lua/luarocks/deps.lua new file mode 100644 index 000000000..dcebec9b2 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/deps.lua @@ -0,0 +1,752 @@ + +--- Dependency handling functions. +-- Dependencies are represented in LuaRocks through strings with +-- a package name followed by a comma-separated list of constraints. +-- Each constraint consists of an operator and a version number. +-- In this string format, version numbers are represented as +-- naturally as possible, like they are used by upstream projects +-- (e.g. "2.0beta3"). Internally, LuaRocks converts them to a purely +-- numeric representation, allowing comparison following some +-- "common sense" heuristics. The precise specification of the +-- comparison criteria is the source code of this module, but the +-- test/test_deps.lua file included with LuaRocks provides some +-- insights on what these criteria are. +local deps = {} +package.loaded["luarocks.deps"] = deps + +local cfg = require("luarocks.cfg") +local manif_core = require("luarocks.manif_core") +local path = require("luarocks.path") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +local operators = { + ["=="] = "==", + ["~="] = "~=", + [">"] = ">", + ["<"] = "<", + [">="] = ">=", + ["<="] = "<=", + ["~>"] = "~>", + -- plus some convenience translations + [""] = "==", + ["="] = "==", + ["!="] = "~=" +} + +local deltas = { + scm = 1100, + cvs = 1000, + rc = -1000, + pre = -10000, + beta = -100000, + alpha = -1000000 +} + +local version_mt = { + --- Equality comparison for versions. + -- All version numbers must be equal. + -- If both versions have revision numbers, they must be equal; + -- otherwise the revision number is ignored. + -- @param v1 table: version table to compare. + -- @param v2 table: version table to compare. + -- @return boolean: true if they are considered equivalent. + __eq = function(v1, v2) + if #v1 ~= #v2 then + return false + end + for i = 1, #v1 do + if v1[i] ~= v2[i] then + return false + end + end + if v1.revision and v2.revision then + return (v1.revision == v2.revision) + end + return true + end, + --- Size comparison for versions. + -- All version numbers are compared. + -- If both versions have revision numbers, they are compared; + -- otherwise the revision number is ignored. + -- @param v1 table: version table to compare. + -- @param v2 table: version table to compare. + -- @return boolean: true if v1 is considered lower than v2. + __lt = function(v1, v2) + for i = 1, math.max(#v1, #v2) do + local v1i, v2i = v1[i] or 0, v2[i] or 0 + if v1i ~= v2i then + return (v1i < v2i) + end + end + if v1.revision and v2.revision then + return (v1.revision < v2.revision) + end + return false + end +} + +local version_cache = {} +setmetatable(version_cache, { + __mode = "kv" +}) + +--- Parse a version string, converting to table format. +-- A version table contains all components of the version string +-- converted to numeric format, stored in the array part of the table. +-- If the version contains a revision, it is stored numerically +-- in the 'revision' field. The original string representation of +-- the string is preserved in the 'string' field. +-- Returned version tables use a metatable +-- allowing later comparison through relational operators. +-- @param vstring string: A version number in string format. +-- @return table or nil: A version table or nil +-- if the input string contains invalid characters. +function deps.parse_version(vstring) + if not vstring then return nil end + assert(type(vstring) == "string") + + local cached = version_cache[vstring] + if cached then + return cached + end + + local version = {} + local i = 1 + + local function add_token(number) + version[i] = version[i] and version[i] + number/100000 or number + i = i + 1 + end + + -- trim leading and trailing spaces + vstring = vstring:match("^%s*(.*)%s*$") + version.string = vstring + -- store revision separately if any + local main, revision = vstring:match("(.*)%-(%d+)$") + if revision then + vstring = main + version.revision = tonumber(revision) + end + while #vstring > 0 do + -- extract a number + local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)") + if token then + add_token(tonumber(token)) + else + -- extract a word + token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)") + if not token then + util.printerr("Warning: version number '"..vstring.."' could not be parsed.") + version[i] = 0 + break + end + version[i] = deltas[token] or (token:byte() / 1000) + end + vstring = rest + end + setmetatable(version, version_mt) + version_cache[vstring] = version + return version +end + +--- Utility function to compare version numbers given as strings. +-- @param a string: one version. +-- @param b string: another version. +-- @return boolean: True if a > b. +function deps.compare_versions(a, b) + return deps.parse_version(a) > deps.parse_version(b) +end + +--- Consumes a constraint from a string, converting it to table format. +-- For example, a string ">= 1.0, > 2.0" is converted to a table in the +-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned +-- back to the caller. +-- @param input string: A list of constraints in string format. +-- @return (table, string) or nil: A table representing the same +-- constraints and the string with the unused input, or nil if the +-- input string is invalid. +local function parse_constraint(input) + assert(type(input) == "string") + + local no_upgrade, op, version, rest = input:match("^(@?)([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)") + local _op = operators[op] + version = deps.parse_version(version) + if not _op then + return nil, "Encountered bad constraint operator: '"..tostring(op).."' in '"..input.."'" + end + if not version then + return nil, "Could not parse version from constraint: '"..input.."'" + end + return { op = _op, version = version, no_upgrade = no_upgrade=="@" and true or nil }, rest +end + +--- Convert a list of constraints from string to table format. +-- For example, a string ">= 1.0, < 2.0" is converted to a table in the format +-- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}. +-- Version tables use a metatable allowing later comparison through +-- relational operators. +-- @param input string: A list of constraints in string format. +-- @return table or nil: A table representing the same constraints, +-- or nil if the input string is invalid. +function deps.parse_constraints(input) + assert(type(input) == "string") + + local constraints, constraint, oinput = {}, nil, input + while #input > 0 do + constraint, input = parse_constraint(input) + if constraint then + table.insert(constraints, constraint) + else + return nil, "Failed to parse constraint '"..tostring(oinput).."' with error: ".. input + end + end + return constraints +end + +--- Convert a dependency from string to table format. +-- For example, a string "foo >= 1.0, < 2.0" +-- is converted to a table in the format +-- {name = "foo", constraints = {{op = ">=", version={1,0}}, +-- {op = "<", version={2,0}}}}. Version tables use a metatable +-- allowing later comparison through relational operators. +-- @param dep string: A dependency in string format +-- as entered in rockspec files. +-- @return table or nil: A table representing the same dependency relation, +-- or nil if the input string is invalid. +function deps.parse_dep(dep) + assert(type(dep) == "string") + + local name, rest = dep:match("^%s*([a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*(.*)") + if not name then return nil, "failed to extract dependency name from '"..tostring(dep).."'" end + local constraints, err = deps.parse_constraints(rest) + if not constraints then return nil, err end + return { name = name, constraints = constraints } +end + +--- Convert a version table to a string. +-- @param v table: The version table +-- @param internal boolean or nil: Whether to display versions in their +-- internal representation format or how they were specified. +-- @return string: The dependency information pretty-printed as a string. +function deps.show_version(v, internal) + assert(type(v) == "table") + assert(type(internal) == "boolean" or not internal) + + return (internal + and table.concat(v, ":")..(v.revision and tostring(v.revision) or "") + or v.string) +end + +--- Convert a dependency in table format to a string. +-- @param dep table: The dependency in table format +-- @param internal boolean or nil: Whether to display versions in their +-- internal representation format or how they were specified. +-- @return string: The dependency information pretty-printed as a string. +function deps.show_dep(dep, internal) + assert(type(dep) == "table") + assert(type(internal) == "boolean" or not internal) + + if #dep.constraints > 0 then + local pretty = {} + for _, c in ipairs(dep.constraints) do + table.insert(pretty, c.op .. " " .. deps.show_version(c.version, internal)) + end + return dep.name.." "..table.concat(pretty, ", ") + else + return dep.name + end +end + +--- A more lenient check for equivalence between versions. +-- This returns true if the requested components of a version +-- match and ignore the ones that were not given. For example, +-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match. +-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2" +-- doesn't. +-- @param version string or table: Version to be tested; may be +-- in string format or already parsed into a table. +-- @param requested string or table: Version requested; may be +-- in string format or already parsed into a table. +-- @return boolean: True if the tested version matches the requested +-- version, false otherwise. +local function partial_match(version, requested) + assert(type(version) == "string" or type(version) == "table") + assert(type(requested) == "string" or type(version) == "table") + + if type(version) ~= "table" then version = deps.parse_version(version) end + if type(requested) ~= "table" then requested = deps.parse_version(requested) end + if not version or not requested then return false end + + for i, ri in ipairs(requested) do + local vi = version[i] or 0 + if ri ~= vi then return false end + end + if requested.revision then + return requested.revision == version.revision + end + return true +end + +--- Check if a version satisfies a set of constraints. +-- @param version table: A version in table format +-- @param constraints table: An array of constraints in table format. +-- @return boolean: True if version satisfies all constraints, +-- false otherwise. +function deps.match_constraints(version, constraints) + assert(type(version) == "table") + assert(type(constraints) == "table") + local ok = true + setmetatable(version, version_mt) + for _, constr in pairs(constraints) do + if type(constr.version) == "string" then + constr.version = deps.parse_version(constr.version) + end + local constr_version, constr_op = constr.version, constr.op + setmetatable(constr_version, version_mt) + if constr_op == "==" then ok = version == constr_version + elseif constr_op == "~=" then ok = version ~= constr_version + elseif constr_op == ">" then ok = version > constr_version + elseif constr_op == "<" then ok = version < constr_version + elseif constr_op == ">=" then ok = version >= constr_version + elseif constr_op == "<=" then ok = version <= constr_version + elseif constr_op == "~>" then ok = partial_match(version, constr_version) + end + if not ok then break end + end + return ok +end + +--- Attempt to match a dependency to an installed rock. +-- @param dep table: A dependency parsed in table format. +-- @param blacklist table: Versions that can't be accepted. Table where keys +-- are program versions and values are 'true'. +-- @return string or nil: latest installed version of the rock matching the dependency +-- or nil if it could not be matched. +local function match_dep(dep, blacklist, deps_mode) + assert(type(dep) == "table") + + local versions + if cfg.rocks_provided[dep.name] then + -- provided rocks have higher priority than manifest's rocks + versions = { cfg.rocks_provided[dep.name] } + else + versions = manif_core.get_versions(dep.name, deps_mode) + end + + local latest_version + for _, vstring in ipairs(versions) do + if not blacklist or not blacklist[vstring] then + local version = deps.parse_version(vstring) + if deps.match_constraints(version, dep.constraints) then + if not latest_version or version > latest_version then + latest_version = version + end + end + end + end + + return latest_version and latest_version.string +end + +--- Attempt to match dependencies of a rockspec to installed rocks. +-- @param rockspec table: The rockspec loaded as a table. +-- @param blacklist table or nil: Program versions to not use as valid matches. +-- Table where keys are program names and values are tables where keys +-- are program versions and values are 'true'. +-- @return table, table, table: A table where keys are dependencies parsed +-- in table format and values are tables containing fields 'name' and +-- version' representing matches; a table of missing dependencies +-- parsed as tables; and a table of "no-upgrade" missing dependencies +-- (to be used in plugin modules so that a plugin does not force upgrade of +-- its parent application). +function deps.match_deps(rockspec, blacklist, deps_mode) + assert(type(rockspec) == "table") + assert(type(blacklist) == "table" or not blacklist) + local matched, missing, no_upgrade = {}, {}, {} + + for _, dep in ipairs(rockspec.dependencies) do + local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode) + if found then + if not cfg.rocks_provided[dep.name] then + matched[dep] = {name = dep.name, version = found} + end + else + if dep.constraints[1] and dep.constraints[1].no_upgrade then + no_upgrade[dep.name] = dep + else + missing[dep.name] = dep + end + end + end + return matched, missing, no_upgrade +end + +--- Return a set of values of a table. +-- @param tbl table: The input table. +-- @return table: The array of keys. +local function values_set(tbl) + local set = {} + for _, v in pairs(tbl) do + set[v] = true + end + return set +end + +local function rock_status(name, deps_mode) + local search = require("luarocks.search") + local installed = match_dep(search.make_query(name), nil, deps_mode) + local installation_type = cfg.rocks_provided[name] and "provided by VM" or "installed" + return installed and installed.." "..installation_type or "not installed" +end + +--- Check depenendencies of a package and report any missing ones. +-- @param name string: package name. +-- @param version string: package version. +-- @param dependencies table: array of dependencies. +-- @param deps_mode string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +function deps.report_missing_dependencies(name, version, dependencies, deps_mode) + local first_missing_dep = true + + for _, dep in ipairs(dependencies) do + if not match_dep(dep, nil, deps_mode) then + if first_missing_dep then + util.printout(("Missing dependencies for %s %s:"):format(name, version)) + first_missing_dep = false + end + + util.printout((" %s (%s)"):format(deps.show_dep(dep), rock_status(dep.name, deps_mode))) + end + end +end + +--- Check dependencies of a rock and attempt to install any missing ones. +-- Packages are installed using the LuaRocks "install" command. +-- Aborts the program if a dependency could not be fulfilled. +-- @param rockspec table: A rockspec in table format. +-- @return boolean or (nil, string, [string]): True if no errors occurred, or +-- nil and an error message if any test failed, followed by an optional +-- error code. +function deps.fulfill_dependencies(rockspec, deps_mode) + + local search = require("luarocks.search") + local install = require("luarocks.install") + + if rockspec.supported_platforms then + if not deps.platforms_set then + deps.platforms_set = values_set(cfg.platforms) + end + local supported = nil + for _, plat in pairs(rockspec.supported_platforms) do + local neg, plat = plat:match("^(!?)(.*)") + if neg == "!" then + if deps.platforms_set[plat] then + return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." + end + else + if deps.platforms_set[plat] then + supported = true + else + if supported == nil then + supported = false + end + end + end + end + if supported == false then + local plats = table.concat(cfg.platforms, ", ") + return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms." + end + end + + deps.report_missing_dependencies(rockspec.name, rockspec.version, rockspec.dependencies, deps_mode) + + local first_missing_dep = true + + for _, dep in ipairs(rockspec.dependencies) do + if not match_dep(dep, nil, deps_mode) then + if first_missing_dep then + util.printout() + first_missing_dep = false + end + + util.printout(("%s %s depends on %s (%s)"):format( + rockspec.name, rockspec.version, deps.show_dep(dep), rock_status(dep.name, deps_mode))) + + if dep.constraints[1] and dep.constraints[1].no_upgrade then + util.printerr("This version of "..rockspec.name.." is designed for use with") + util.printerr(deps.show_dep(dep)..", but is configured to avoid upgrading it") + util.printerr("automatically. Please upgrade "..dep.name.." with") + util.printerr(" luarocks install "..dep.name) + util.printerr("or choose an older version of "..rockspec.name.." with") + util.printerr(" luarocks search "..rockspec.name) + return nil, "Failed matching dependencies" + end + + local url, search_err = search.find_suitable_rock(dep) + if not url then + return nil, "Could not satisfy dependency "..deps.show_dep(dep)..": "..search_err + end + util.printout("Installing "..url) + local ok, install_err, errcode = install.command({deps_mode = deps_mode}, url) + if not ok then + return nil, "Failed installing dependency: "..url.." - "..install_err, errcode + end + end + end + + return true +end + +--- If filename matches a pattern, return the capture. +-- For example, given "libfoo.so" and "lib?.so" is a pattern, +-- returns "foo" (which can then be used to build names +-- based on other patterns. +-- @param file string: a filename +-- @param pattern string: a pattern, where ? is to be matched by the filename. +-- @return string The pattern, if found, or nil. +local function deconstruct_pattern(file, pattern) + local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$" + return (file:match(depattern)) +end + +--- Construct all possible patterns for a name and add to the files array. +-- Run through the patterns array replacing all occurrences of "?" +-- with the given file name and store them in the files array. +-- @param file string A raw name (e.g. "foo") +-- @param array of string An array of patterns with "?" as the wildcard +-- (e.g. {"?.so", "lib?.so"}) +-- @param files The array of constructed names +local function add_all_patterns(file, patterns, files) + for _, pattern in ipairs(patterns) do + table.insert(files, (pattern:gsub("?", file))) + end +end + +--- Set up path-related variables for external dependencies. +-- For each key in the external_dependencies table in the +-- rockspec file, four variables are created: _DIR, _BINDIR, +-- _INCDIR and _LIBDIR. These are not overwritten +-- if already set (e.g. by the LuaRocks config file or through the +-- command-line). Values in the external_dependencies table +-- are tables that may contain a "header" or a "library" field, +-- with filenames to be tested for existence. +-- @param rockspec table: The rockspec table. +-- @param mode string: if "build" is given, checks all files; +-- if "install" is given, do not scan for headers. +-- @return boolean or (nil, string): True if no errors occurred, or +-- nil and an error message if any test failed. +function deps.check_external_deps(rockspec, mode) + assert(type(rockspec) == "table") + + local fs = require("luarocks.fs") + + local vars = rockspec.variables + local patterns = cfg.external_deps_patterns + local subdirs = cfg.external_deps_subdirs + if mode == "install" then + patterns = cfg.runtime_external_deps_patterns + subdirs = cfg.runtime_external_deps_subdirs + end + if rockspec.external_dependencies then + for name, ext_files in util.sortedpairs(rockspec.external_dependencies) do + local ok = true + local failed_files = {program = {}, header = {}, library = {}} + local failed_dirname + local failed_testfile + for _, extdir in ipairs(cfg.external_deps_dirs) do + ok = true + local prefix = vars[name.."_DIR"] + local dirs = { + BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin }, + INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include }, + LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib } + } + if mode == "install" then + dirs.INCDIR = nil + end + if not prefix then + prefix = extdir + end + if type(prefix) == "table" then + if prefix.bin then + dirs.BINDIR.subdir = prefix.bin + end + if prefix.include then + if dirs.INCDIR then + dirs.INCDIR.subdir = prefix.include + end + end + if prefix.lib then + dirs.LIBDIR.subdir = prefix.lib + end + prefix = prefix.prefix + end + for dirname, dirdata in util.sortedpairs(dirs) do + local paths + local path_var_value = vars[name.."_"..dirname] + if path_var_value then + paths = { path_var_value } + elseif type(dirdata.subdir) == "table" then + paths = {} + for i,v in ipairs(dirdata.subdir) do + paths[i] = dir.path(prefix, v) + end + else + paths = { dir.path(prefix, dirdata.subdir) } + end + dirdata.dir = paths[1] + local file = ext_files[dirdata.testfile] + if file then + local files = {} + if not file:match("%.") then + add_all_patterns(file, dirdata.pattern, files) + else + for _, pattern in ipairs(dirdata.pattern) do + local matched = deconstruct_pattern(file, pattern) + if matched then + add_all_patterns(matched, dirdata.pattern, files) + end + end + table.insert(files, file) + end + local found = false + for _, f in ipairs(files) do + + -- small convenience hack + if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then + f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension) + end + + local pattern + if f:match("%*") then + pattern = f:gsub("%.", "%%."):gsub("%*", ".*") + f = "matching "..f + end + + for _, d in ipairs(paths) do + if pattern then + for entry in fs.dir(d) do + if entry:match(pattern) then + found = true + break + end + end + else + found = fs.is_file(dir.path(d, f)) + end + if found then + dirdata.dir = d + break + else + table.insert(failed_files[dirdata.testfile], f.." in "..d) + end + end + if found then + break + end + end + if not found then + ok = false + failed_dirname = dirname + failed_testfile = dirdata.testfile + break + end + end + end + if ok then + for dirname, dirdata in pairs(dirs) do + vars[name.."_"..dirname] = dirdata.dir + end + vars[name.."_DIR"] = prefix + break + end + end + if not ok then + local lines = {"Could not find "..failed_testfile.." file for "..name} + + local failed_paths = {} + for _, failed_file in ipairs(failed_files[failed_testfile]) do + if not failed_paths[failed_file] then + failed_paths[failed_file] = true + table.insert(lines, " No file "..failed_file) + end + end + + table.insert(lines, "You may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..failed_dirname.." to the luarocks command.") + table.insert(lines, "Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local") + + return nil, table.concat(lines, "\n"), "dependency" + end + end + end + return true +end + +--- Recursively add satisfied dependencies of a package to a table, +-- to build a transitive closure of all dependent packages. +-- Additionally ensures that `dependencies` table of the manifest is up-to-date. +-- @param results table: The results table being built, maps package names to versions. +-- @param manifest table: The manifest table containing dependencies. +-- @param name string: Package name. +-- @param version string: Package version. +function deps.scan_deps(results, manifest, name, version, deps_mode) + assert(type(results) == "table") + assert(type(manifest) == "table") + assert(type(name) == "string") + assert(type(version) == "string") + + local fetch = require("luarocks.fetch") + + if results[name] then + return + end + if not manifest.dependencies then manifest.dependencies = {} end + local dependencies = manifest.dependencies + if not dependencies[name] then dependencies[name] = {} end + local dependencies_name = dependencies[name] + local deplist = dependencies_name[version] + local rockspec, err + if not deplist then + rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false) + if not rockspec then + util.printerr("Couldn't load rockspec for "..name.." "..version..": "..err) + return + end + dependencies_name[version] = rockspec.dependencies + else + rockspec = { dependencies = deplist } + end + local matched = deps.match_deps(rockspec, nil, deps_mode) + results[name] = version + for _, match in pairs(matched) do + deps.scan_deps(results, manifest, match.name, match.version, deps_mode) + end +end + +local valid_deps_modes = { + one = true, + order = true, + all = true, + none = true, +} + +function deps.check_deps_mode_flag(flag) + return valid_deps_modes[flag] +end + +function deps.get_deps_mode(flags) + if flags["deps-mode"] then + return flags["deps-mode"] + else + return cfg.deps_mode + end +end + +function deps.deps_mode_to_flag(deps_mode) + return "--deps-mode="..deps_mode +end + +return deps diff --git a/Utils/luarocks/lua/luarocks/dir.lua b/Utils/luarocks/lua/luarocks/dir.lua new file mode 100644 index 000000000..f72ebd6c1 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/dir.lua @@ -0,0 +1,74 @@ + +--- Generic utilities for handling pathnames. +local dir = {} +package.loaded["luarocks.dir"] = dir + +dir.separator = "/" + +--- Strip the path off a path+filename. +-- @param pathname string: A path+name, such as "/a/b/c" +-- or "\a\b\c". +-- @return string: The filename without its path, such as "c". +function dir.base_name(pathname) + assert(type(pathname) == "string") + + local base = pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)") + return base or pathname +end + +--- Strip the name off a path+filename. +-- @param pathname string: A path+name, such as "/a/b/c". +-- @return string: The filename without its path, such as "/a/b". +-- For entries such as "/a/b/", "/a" is returned. If there are +-- no directory separators in input, "" is returned. +function dir.dir_name(pathname) + assert(type(pathname) == "string") + return (pathname:gsub("/*$", ""):match("(.*)[/]+[^/]*")) or "" +end + +--- Describe a path in a cross-platform way. +-- Use this function to avoid platform-specific directory +-- separators in other modules. Removes trailing slashes from +-- each component given, to avoid repeated separators. +-- Separators inside strings are kept, to handle URLs containing +-- protocols. +-- @param ... strings representing directories +-- @return string: a string with a platform-specific representation +-- of the path. +function dir.path(...) + local t = {...} + while t[1] == "" do + table.remove(t, 1) + end + return (table.concat(t, "/"):gsub("([^:])/+", "%1/"):gsub("^/+", "/"):gsub("/*$", "")) +end + +--- Split protocol and path from an URL or local pathname. +-- URLs should be in the "protocol://path" format. +-- For local pathnames, "file" is returned as the protocol. +-- @param url string: an URL or a local pathname. +-- @return string, string: the protocol, and the pathname without the protocol. +function dir.split_url(url) + assert(type(url) == "string") + + local protocol, pathname = url:match("^([^:]*)://(.*)") + if not protocol then + protocol = "file" + pathname = url + end + return protocol, pathname +end + +--- Normalize a url or local path. +-- URLs should be in the "protocol://path" format. System independent +-- forward slashes are used, removing trailing and double slashes +-- @param url string: an URL or a local pathname. +-- @return string: Normalized result. +function dir.normalize(name) + local protocol, pathname = dir.split_url(name) + pathname = pathname:gsub("\\", "/"):gsub("(.)/*$", "%1"):gsub("//", "/") + if protocol ~= "file" then pathname = protocol .."://"..pathname end + return pathname +end + +return dir diff --git a/Utils/luarocks/lua/luarocks/doc.lua b/Utils/luarocks/lua/luarocks/doc.lua new file mode 100644 index 000000000..423ebe027 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/doc.lua @@ -0,0 +1,157 @@ + +--- Module implementing the LuaRocks "doc" command. +-- Shows documentation for an installed rock. +local doc = {} +package.loaded["luarocks.doc"] = doc + +local util = require("luarocks.util") +local search = require("luarocks.search") +local path = require("luarocks.path") +local dir = require("luarocks.dir") +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local download = require("luarocks.download") + +util.add_run_function(doc) +doc.help_summary = "Show documentation for an installed rock." + +doc.help = [[ + is an existing package name. +Without any flags, tries to load the documentation +using a series of heuristics. +With these flags, return only the desired information: + +--home Open the home page of project. +--list List documentation files only. + +For more information about a rock, see the 'show' command. +]] + +local function show_homepage(homepage, name, version) + if not homepage then + return nil, "No 'homepage' field in rockspec for "..name.." "..version + end + util.printout("Opening "..homepage.." ...") + fs.browser(homepage) + return true +end + +local function try_to_open_homepage(name, version) + local temp_dir, err = fs.make_temp_dir("doc-"..name.."-"..(version or "")) + if not temp_dir then + return nil, "Failed creating temporary directory: "..err + end + util.schedule_function(fs.delete, temp_dir) + local ok, err = fs.change_dir(temp_dir) + if not ok then return nil, err end + local filename, err = download.download("rockspec", name, version) + if not filename then return nil, err end + local rockspec, err = fetch.load_local_rockspec(filename) + if not rockspec then return nil, err end + fs.pop_dir() + local descript = rockspec.description or {} + if not descript.homepage then return nil, "No homepage defined for "..name end + return show_homepage(descript.homepage, name, version) +end + +--- Driver function for "doc" command. +-- @param name or nil: an existing package name. +-- @param version string or nil: a version may also be passed. +-- @return boolean: True if succeeded, nil on errors. +function doc.command(flags, name, version) + if not name then + return nil, "Argument missing. "..util.see_help("doc") + end + + name = name:lower() + + local iname, iversion, repo = search.pick_installed_rock(name, version, flags["tree"]) + if not iname then + util.printout(name..(version and " "..version or "").." is not installed. Looking for it in the rocks servers...") + return try_to_open_homepage(name, version) + end + name, version = iname, iversion + + local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version, repo)) + if not rockspec then return nil,err end + local descript = rockspec.description or {} + + if flags["home"] then + return show_homepage(descript.homepage, name, version) + end + + local directory = path.install_dir(name,version,repo) + + local docdir + local directories = { "doc", "docs" } + for _, d in ipairs(directories) do + local dirname = dir.path(directory, d) + if fs.is_dir(dirname) then + docdir = dirname + break + end + end + if not docdir then + if descript.homepage and not flags["list"] then + util.printout("Local documentation directory not found -- opening "..descript.homepage.." ...") + fs.browser(descript.homepage) + return true + end + return nil, "Documentation directory not found for "..name.." "..version + end + + docdir = dir.normalize(docdir):gsub("/+", "/") + local files = fs.find(docdir) + local htmlpatt = "%.html?$" + local extensions = { htmlpatt, "%.md$", "%.txt$", "%.textile$", "" } + local basenames = { "index", "readme", "manual" } + + local porcelain = flags["porcelain"] + if #files > 0 then + util.title("Documentation files for "..name.." "..version, porcelain) + if porcelain then + for _, file in ipairs(files) do + util.printout(docdir.."/"..file) + end + else + util.printout(docdir.."/") + for _, file in ipairs(files) do + util.printout("\t"..file) + end + end + end + + if flags["list"] then + return true + end + + for _, extension in ipairs(extensions) do + for _, basename in ipairs(basenames) do + local filename = basename..extension + local found + for _, file in ipairs(files) do + if file:lower():match(filename) and ((not found) or #file < #found) then + found = file + end + end + if found then + local pathname = dir.path(docdir, found) + util.printout() + util.printout("Opening "..pathname.." ...") + util.printout() + local ok = fs.browser(pathname) + if not ok and not pathname:match(htmlpatt) then + local fd = io.open(pathname, "r") + util.printout(fd:read("*a")) + fd:close() + end + return true + end + end + end + + return true +end + + +return doc diff --git a/Utils/luarocks/lua/luarocks/download.lua b/Utils/luarocks/lua/luarocks/download.lua new file mode 100644 index 000000000..e434cdbb2 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/download.lua @@ -0,0 +1,109 @@ + +--- Module implementing the luarocks "download" command. +-- Download a rock from the repository. +local download = {} +package.loaded["luarocks.download"] = download + +local util = require("luarocks.util") +local path = require("luarocks.path") +local fetch = require("luarocks.fetch") +local search = require("luarocks.search") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +util.add_run_function(download) +download.help_summary = "Download a specific rock file from a rocks server." +download.help_arguments = "[--all] [--arch= | --source | --rockspec] [ []]" + +download.help = [[ +--all Download all files if there are multiple matches. +--source Download .src.rock if available. +--rockspec Download .rockspec if available. +--arch= Download rock for a specific architecture. +]] + +local function get_file(filename) + local protocol, pathname = dir.split_url(filename) + if protocol == "file" then + local ok, err = fs.copy(pathname, fs.current_dir(), cfg.perm_read) + if ok then + return pathname + else + return nil, err + end + else + return fetch.fetch_url(filename) + end +end + +function download.download(arch, name, version, all) + local query = search.make_query(name, version) + if arch then query.arch = arch end + local search_err + + if all then + if name == "" then query.exact_name = false end + local results = search.search_repos(query) + local has_result = false + local all_ok = true + local any_err = "" + for name, result in pairs(results) do + for version, items in pairs(result) do + for _, item in ipairs(items) do + -- Ignore provided rocks. + if item.arch ~= "installed" then + has_result = true + local filename = path.make_url(item.repo, name, version, item.arch) + local ok, err = get_file(filename) + if not ok then + all_ok = false + any_err = any_err .. "\n" .. err + end + end + end + end + end + + if has_result then + return all_ok, any_err + end + else + local url + url, search_err = search.find_suitable_rock(query) + if url then + return get_file(url) + end + end + return nil, "Could not find a result named "..name..(version and " "..version or "").. + (search_err and ": "..search_err or ".") +end + +--- Driver function for the "download" command. +-- @param name string: a rock name. +-- @param version string or nil: if the name of a package is given, a +-- version may also be passed. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +function download.command(flags, name, version) + assert(type(version) == "string" or not version) + if type(name) ~= "string" and not flags["all"] then + return nil, "Argument missing. "..util.see_help("download") + end + if not name then name, version = "", "" end + + local arch + + if flags["source"] then + arch = "src" + elseif flags["rockspec"] then + arch = "rockspec" + elseif flags["arch"] then + arch = flags["arch"] + end + + local dl, err = download.download(arch, name:lower(), version, flags["all"]) + return dl and true, err +end + +return download diff --git a/Utils/luarocks/lua/luarocks/fetch.lua b/Utils/luarocks/lua/luarocks/fetch.lua new file mode 100644 index 000000000..76f366cd2 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch.lua @@ -0,0 +1,394 @@ + +--- Functions related to fetching and loading local and remote files. +local fetch = {} +package.loaded["luarocks.fetch"] = fetch + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local type_check = require("luarocks.type_check") +local path = require("luarocks.path") +local deps = require("luarocks.deps") +local persist = require("luarocks.persist") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") + +function fetch.is_basic_protocol(protocol, remote) + return protocol == "http" or protocol == "https" or protocol == "ftp" or (not remote and protocol == "file") +end + +--- Fetch a local or remote file. +-- Make a remote or local URL/pathname local, fetching the file if necessary. +-- Other "fetch" and "load" functions use this function to obtain files. +-- If a local pathname is given, it is returned as a result. +-- @param url string: a local pathname or a remote URL. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return string or (nil, string, [string]): the absolute local pathname for the +-- fetched file, or nil and a message in case of errors, followed by +-- an optional error code. +function fetch.fetch_url(url, filename, cache) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + local protocol, pathname = dir.split_url(url) + if protocol == "file" then + return fs.absolute_name(pathname) + elseif fetch.is_basic_protocol(protocol, true) then + local ok, name = fs.download(url, filename, cache) + if not ok then + return nil, "Failed downloading "..url..(filename and " - "..filename or ""), "network" + end + return name + else + return nil, "Unsupported protocol "..protocol + end +end + +--- For remote URLs, create a temporary directory and download URL inside it. +-- This temporary directory will be deleted on program termination. +-- For local URLs, just return the local pathname and its directory. +-- @param url string: URL to be downloaded +-- @param tmpname string: name pattern to use for avoiding conflicts +-- when creating temporary directory. +-- @param filename string or nil: local filename of URL to be downloaded, +-- in case it can't be inferred from the URL. +-- @return (string, string) or (nil, string, [string]): absolute local pathname of +-- the fetched file and temporary directory name; or nil and an error message +-- followed by an optional error code +function fetch.fetch_url_at_temp_dir(url, tmpname, filename) + assert(type(url) == "string") + assert(type(tmpname) == "string") + assert(type(filename) == "string" or not filename) + filename = filename or dir.base_name(url) + + local protocol, pathname = dir.split_url(url) + if protocol == "file" then + if fs.exists(pathname) then + return pathname, dir.dir_name(fs.absolute_name(pathname)) + else + return nil, "File not found: "..pathname + end + else + local temp_dir, err = fs.make_temp_dir(tmpname) + if not temp_dir then + return nil, "Failed creating temporary directory "..tmpname..": "..err + end + util.schedule_function(fs.delete, temp_dir) + local ok, err = fs.change_dir(temp_dir) + if not ok then return nil, err end + local file, err, errcode = fetch.fetch_url(url, filename) + fs.pop_dir() + if not file then + return nil, "Error fetching file: "..err, errcode + end + return file, temp_dir + end +end + +-- Determine base directory of a fetched URL by extracting its +-- archive and looking for a directory in the root. +-- @param file string: absolute local pathname of the fetched file +-- @param temp_dir string: temporary directory in which URL was fetched. +-- @param src_url string: URL to use when inferring base directory. +-- @param src_dir string or nil: expected base directory (inferred +-- from src_url if not given). +-- @return (string, string) or (string, nil) or (nil, string): +-- The inferred base directory and the one actually found (which may +-- be nil if not found), or nil followed by an error message. +-- The inferred dir is returned first to avoid confusion with errors, +-- because it is never nil. +function fetch.find_base_dir(file, temp_dir, src_url, src_dir) + local ok, err = fs.change_dir(temp_dir) + if not ok then return nil, err end + fs.unpack_archive(file) + local inferred_dir = src_dir or fetch.url_to_base_dir(src_url) + local found_dir = nil + if fs.exists(inferred_dir) then + found_dir = inferred_dir + else + util.printerr("Directory "..inferred_dir.." not found") + local files = fs.list_dir() + if files then + table.sort(files) + for i,filename in ipairs(files) do + if fs.is_dir(filename) then + util.printerr("Found "..filename) + found_dir = filename + break + end + end + end + end + fs.pop_dir() + return inferred_dir, found_dir +end + +--- Obtain a rock and unpack it. +-- If a directory is not given, a temporary directory will be created, +-- which will be deleted on program termination. +-- @param rock_file string: URL or filename of the rock. +-- @param dest string or nil: if given, directory will be used as +-- a permanent destination. +-- @return string or (nil, string, [string]): the directory containing the contents +-- of the unpacked rock. +function fetch.fetch_and_unpack_rock(rock_file, dest) + assert(type(rock_file) == "string") + assert(type(dest) == "string" or not dest) + + local name = dir.base_name(rock_file):match("(.*)%.[^.]*%.rock") + + local rock_file, err, errcode = fetch.fetch_url_at_temp_dir(rock_file,"luarocks-rock-"..name) + if not rock_file then + return nil, "Could not fetch rock file: " .. err, errcode + end + + rock_file = fs.absolute_name(rock_file) + local unpack_dir + if dest then + unpack_dir = dest + local ok, err = fs.make_dir(unpack_dir) + if not ok then + return nil, "Failed unpacking rock file: " .. err + end + else + unpack_dir = fs.make_temp_dir(name) + end + if not dest then + util.schedule_function(fs.delete, unpack_dir) + end + local ok, err = fs.change_dir(unpack_dir) + if not ok then return nil, err end + ok = fs.unzip(rock_file) + if not ok then + return nil, "Failed unpacking rock file: " .. rock_file + end + fs.pop_dir() + return unpack_dir +end + +function fetch.url_to_base_dir(url) + -- for extensions like foo.tar.gz, "gz" is stripped first + local known_exts = {} + for _, ext in ipairs{"zip", "git", "tgz", "tar", "gz", "bz2"} do + known_exts[ext] = "" + end + local base = dir.base_name(url) + return (base:gsub("%.([^.]*)$", known_exts):gsub("%.tar", "")) +end + +--- Back-end function that actually loads the local rockspec. +-- Performs some validation and postprocessing of the rockspec contents. +-- @param filename string: The local filename of the rockspec file. +-- @param quick boolean: if true, skips some steps when loading +-- rockspec. +-- @return table or (nil, string): A table representing the rockspec +-- or nil followed by an error message. +function fetch.load_local_rockspec(filename, quick) + assert(type(filename) == "string") + filename = fs.absolute_name(filename) + local rockspec, err = persist.load_into_table(filename) + if not rockspec then + return nil, "Could not load rockspec file "..filename.." ("..err..")" + end + if cfg.branch and (type(rockspec.source) == "table") then + rockspec.source.branch = cfg.branch + end + local globals = err + + if rockspec.rockspec_format then + if deps.compare_versions(rockspec.rockspec_format, type_check.rockspec_format) then + return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." + end + end + + if not quick then + local ok, err = type_check.type_check_rockspec(rockspec, globals) + if not ok then + return nil, filename..": "..err + end + end + + util.platform_overrides(rockspec.build) + util.platform_overrides(rockspec.dependencies) + util.platform_overrides(rockspec.external_dependencies) + util.platform_overrides(rockspec.source) + util.platform_overrides(rockspec.hooks) + + local basename = dir.base_name(filename) + if basename == "rockspec" then + rockspec.name = rockspec.package:lower() + else + rockspec.name = basename:match("(.*)-[^-]*-[0-9]*") + if not rockspec.name then + return nil, "Expected filename in format 'name-version-revision.rockspec'." + end + end + + local protocol, pathname = dir.split_url(rockspec.source.url) + if fetch.is_basic_protocol(protocol) then + rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) + end + rockspec.source.protocol, rockspec.source.pathname = protocol, pathname + + -- Temporary compatibility + if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end + if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end + + local name_version = rockspec.package:lower() .. "-" .. rockspec.version + if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then + return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." + end + + rockspec.local_filename = filename + local filebase = rockspec.source.file or rockspec.source.url + local base = fetch.url_to_base_dir(filebase) + rockspec.source.dir = rockspec.source.dir + or rockspec.source.module + or ((filebase:match("%.lua$") or filebase:match("%.c$")) and ".") + or base + if rockspec.dependencies then + for i = 1, #rockspec.dependencies do + local parsed, err = deps.parse_dep(rockspec.dependencies[i]) + if not parsed then + return nil, "Parse error processing dependency '"..rockspec.dependencies[i].."': "..tostring(err) + end + rockspec.dependencies[i] = parsed + end + else + rockspec.dependencies = {} + end + if not quick then + path.configure_paths(rockspec) + end + + return rockspec +end + +--- Load a local or remote rockspec into a table. +-- This is the entry point for the LuaRocks tools. +-- Only the LuaRocks runtime loader should use +-- load_local_rockspec directly. +-- @param filename string: Local or remote filename of a rockspec. +-- @param location string or nil: Where to download. If not given, +-- a temporary dir is created. +-- @return table or (nil, string, [string]): A table representing the rockspec +-- or nil followed by an error message and optional error code. +function fetch.load_rockspec(filename, location) + assert(type(filename) == "string") + + local name + local basename = dir.base_name(filename) + if basename == "rockspec" then + name = "rockspec" + else + name = basename:match("(.*)%.rockspec") + if not name then + return nil, "Filename '"..filename.."' does not look like a rockspec." + end + end + + local err, errcode + if location then + local ok, err = fs.change_dir(location) + if not ok then return nil, err end + filename, err = fetch.fetch_url(filename) + fs.pop_dir() + else + filename, err, errcode = fetch.fetch_url_at_temp_dir(filename,"luarocks-rockspec-"..name) + end + if not filename then + return nil, err, errcode + end + + return fetch.load_local_rockspec(filename) +end + +--- Download sources for building a rock using the basic URL downloader. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Whether to extract the sources from +-- the fetched source tarball or not. +-- @param dest_dir string or nil: If set, will extract to the given directory; +-- if not given, will extract to a temporary directory. +-- @return (string, string) or (nil, string, [string]): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message and optional error code. +function fetch.get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(extract) == "boolean") + assert(type(dest_dir) == "string" or not dest_dir) + + local url = rockspec.source.url + local name = rockspec.name.."-"..rockspec.version + local filename = rockspec.source.file + local source_file, store_dir + local ok, err, errcode + if dest_dir then + ok, err = fs.change_dir(dest_dir) + if not ok then return nil, err, "dest_dir" end + source_file, err, errcode = fetch.fetch_url(url, filename) + fs.pop_dir() + store_dir = dest_dir + else + source_file, store_dir, errcode = fetch.fetch_url_at_temp_dir(url, "luarocks-source-"..name, filename) + end + if not source_file then + return nil, err or store_dir, errcode + end + if rockspec.source.md5 then + if not fs.check_md5(source_file, rockspec.source.md5) then + return nil, "MD5 check for "..filename.." has failed.", "md5" + end + end + if extract then + local ok, err = fs.change_dir(store_dir) + if not ok then return nil, err end + ok, err = fs.unpack_archive(rockspec.source.file) + if not ok then return nil, err end + if not fs.exists(rockspec.source.dir) then + return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file, "source.dir", source_file, store_dir + end + fs.pop_dir() + end + return source_file, store_dir +end + +--- Download sources for building a rock, calling the appropriate protocol method. +-- @param rockspec table: The rockspec table +-- @param extract boolean: When downloading compressed formats, whether to extract +-- the sources from the fetched archive or not. +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- if not given, will extract to a temporary directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function fetch.fetch_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(extract) == "boolean") + assert(type(dest_dir) == "string" or not dest_dir) + + local protocol = rockspec.source.protocol + local ok, proto + if fetch.is_basic_protocol(protocol) then + proto = fetch + else + ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) + if not ok then + return nil, "Unknown protocol "..protocol + end + end + + if cfg.only_sources_from + and rockspec.source.pathname + and #rockspec.source.pathname > 0 then + if #cfg.only_sources_from == 0 then + return nil, "Can't download "..rockspec.source.url.." -- download from remote servers disabled" + elseif rockspec.source.pathname:find(cfg.only_sources_from, 1, true) ~= 1 then + return nil, "Can't download "..rockspec.source.url.." -- only downloading from "..cfg.only_sources_from + end + end + return proto.get_sources(rockspec, extract, dest_dir) +end + +return fetch diff --git a/Utils/luarocks/lua/luarocks/fetch/cvs.lua b/Utils/luarocks/lua/luarocks/fetch/cvs.lua new file mode 100644 index 000000000..ece711b6f --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/cvs.lua @@ -0,0 +1,55 @@ + +--- Fetch back-end for retrieving sources from CVS. +local cvs = {} + +local unpack = unpack or table.unpack + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Download sources for building a rock, using CVS. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function cvs.get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local cvs_cmd = rockspec.variables.CVS + local ok, err_msg = fs.is_tool_available(cvs_cmd, "CVS") + if not ok then + return nil, err_msg + end + + local name_version = rockspec.name .. "-" .. rockspec.version + local module = rockspec.source.module or dir.base_name(rockspec.source.url) + local command = {cvs_cmd, "-d"..rockspec.source.pathname, "export", module} + if rockspec.source.tag then + table.insert(command, 4, "-r") + table.insert(command, 5, rockspec.source.tag) + end + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + local ok, err = fs.change_dir(store_dir) + if not ok then return nil, err end + if not fs.execute(unpack(command)) then + return nil, "Failed fetching files from CVS." + end + fs.pop_dir() + return module, store_dir +end + + +return cvs diff --git a/Utils/luarocks/lua/luarocks/fetch/git.lua b/Utils/luarocks/lua/luarocks/fetch/git.lua new file mode 100644 index 000000000..f61d89e9c --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/git.lua @@ -0,0 +1,92 @@ + +--- Fetch back-end for retrieving sources from GIT. +local git = {} + +local unpack = unpack or table.unpack + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Git >= 1.7.10 can clone a branch **or tag**, < 1.7.10 by branch only. We +-- need to know this in order to build the appropriate command; if we can't +-- clone by tag then we'll have to issue a subsequent command to check out the +-- given tag. +-- @return boolean: Whether Git can clone by tag. +local function git_can_clone_by_tag(git_cmd) + local version_string = io.popen(fs.Q(git_cmd)..' --version'):read() + local major, minor, tiny = version_string:match('(%d-)%.(%d+)%.?(%d*)') + major, minor, tiny = tonumber(major), tonumber(minor), tonumber(tiny) or 0 + local value = major > 1 or (major == 1 and (minor > 7 or (minor == 7 and tiny >= 10))) + git_can_clone_by_tag = function() return value end + return value +end + +--- Download sources for building a rock, using git. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function git.get_sources(rockspec, extract, dest_dir, depth) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local git_cmd = rockspec.variables.GIT + local name_version = rockspec.name .. "-" .. rockspec.version + local module = dir.base_name(rockspec.source.url) + -- Strip off .git from base name if present + module = module:gsub("%.git$", "") + + local ok, err_msg = fs.is_tool_available(git_cmd, "Git") + if not ok then + return nil, err_msg + end + + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + store_dir = fs.absolute_name(store_dir) + local ok, err = fs.change_dir(store_dir) + if not ok then return nil, err end + + local command = {fs.Q(git_cmd), "clone", depth or "--depth=1", rockspec.source.url, module} + local tag_or_branch = rockspec.source.tag or rockspec.source.branch + -- If the tag or branch is explicitly set to "master" in the rockspec, then + -- we can avoid passing it to Git since it's the default. + if tag_or_branch == "master" then tag_or_branch = nil end + if tag_or_branch then + if git_can_clone_by_tag(git_cmd) then + -- The argument to `--branch` can actually be a branch or a tag as of + -- Git 1.7.10. + table.insert(command, 3, "--branch=" .. tag_or_branch) + end + end + if not fs.execute(unpack(command)) then + return nil, "Failed cloning git repository." + end + ok, err = fs.change_dir(module) + if not ok then return nil, err end + if tag_or_branch and not git_can_clone_by_tag() then + local checkout_command = {fs.Q(git_cmd), "checkout", tag_or_branch} + if not fs.execute(unpack(checkout_command)) then + return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.' + end + end + + fs.delete(dir.path(store_dir, module, ".git")) + fs.delete(dir.path(store_dir, module, ".gitignore")) + fs.pop_dir() + fs.pop_dir() + return module, store_dir +end + +return git diff --git a/Utils/luarocks/lua/luarocks/fetch/git_file.lua b/Utils/luarocks/lua/luarocks/fetch/git_file.lua new file mode 100644 index 000000000..8d46bbca3 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/git_file.lua @@ -0,0 +1,19 @@ + +--- Fetch back-end for retrieving sources from local Git repositories. +local git_file = {} + +local git = require("luarocks.fetch.git") + +--- Fetch sources for building a rock from a local Git repository. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function git_file.get_sources(rockspec, extract, dest_dir) + rockspec.source.url = rockspec.source.url:gsub("^git.file://", "") + return git.get_sources(rockspec, extract, dest_dir) +end + +return git_file diff --git a/Utils/luarocks/lua/luarocks/fetch/git_http.lua b/Utils/luarocks/lua/luarocks/fetch/git_http.lua new file mode 100644 index 000000000..d85e2572d --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/git_http.lua @@ -0,0 +1,26 @@ + +--- Fetch back-end for retrieving sources from Git repositories +-- that use http:// transport. For example, for fetching a repository +-- that requires the following command line: +-- `git clone http://example.com/foo.git` +-- you can use this in the rockspec: +-- source = { url = "git+http://example.com/foo.git" } +-- Prefer using the normal git:// fetch mode as it is more widely +-- available in older versions of LuaRocks. +local git_http = {} + +local git = require("luarocks.fetch.git") + +--- Fetch sources for building a rock from a local Git repository. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function git_http.get_sources(rockspec, extract, dest_dir) + rockspec.source.url = rockspec.source.url:gsub("^git.", "") + return git.get_sources(rockspec, extract, dest_dir, "--") +end + +return git_http diff --git a/Utils/luarocks/lua/luarocks/fetch/git_https.lua b/Utils/luarocks/lua/luarocks/fetch/git_https.lua new file mode 100644 index 000000000..67f8ad6cc --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/git_https.lua @@ -0,0 +1,7 @@ +--- Fetch back-end for retrieving sources from Git repositories +-- that use https:// transport. For example, for fetching a repository +-- that requires the following command line: +-- `git clone https://example.com/foo.git` +-- you can use this in the rockspec: +-- source = { url = "git+https://example.com/foo.git" } +return require "luarocks.fetch.git_http" diff --git a/Utils/luarocks/lua/luarocks/fetch/git_ssh.lua b/Utils/luarocks/lua/luarocks/fetch/git_ssh.lua new file mode 100644 index 000000000..0c2c0750f --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/git_ssh.lua @@ -0,0 +1,32 @@ +--- Fetch back-end for retrieving sources from Git repositories +-- that use ssh:// transport. For example, for fetching a repository +-- that requires the following command line: +-- `git clone ssh://git@example.com/path/foo.git +-- you can use this in the rockspec: +-- source = { url = "git+ssh://git@example.com/path/foo.git" } +-- It also handles scp-style ssh urls: git@example.com:path/foo.git, +-- but you have to prepend the "git+ssh://" and why not use the "newer" +-- style anyway? +local git_ssh = {} + +local git = require("luarocks.fetch.git") + +--- Fetch sources for building a rock from a local Git repository. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function git_ssh.get_sources(rockspec, extract, dest_dir) + rockspec.source.url = rockspec.source.url:gsub("^git.", "") + + -- Handle old-style scp-like git ssh urls + if rockspec.source.url:match("^ssh://[^/]+:[^%d]") then + rockspec.source.url = rockspec.source.url:gsub("^ssh://", "") + end + + return git.get_sources(rockspec, extract, dest_dir, "--") +end + +return git_ssh diff --git a/Utils/luarocks/lua/luarocks/fetch/hg.lua b/Utils/luarocks/lua/luarocks/fetch/hg.lua new file mode 100644 index 000000000..4cf8d0280 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/hg.lua @@ -0,0 +1,65 @@ + +--- Fetch back-end for retrieving sources from HG. +local hg = {} + +local unpack = unpack or table.unpack + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Download sources for building a rock, using hg. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function hg.get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local hg_cmd = rockspec.variables.HG + local ok, err_msg = fs.is_tool_available(hg_cmd, "Mercurial") + if not ok then + return nil, err_msg + end + + local name_version = rockspec.name .. "-" .. rockspec.version + -- Strip off special hg:// protocol type + local url = rockspec.source.url:gsub("^hg://", "") + + local module = dir.base_name(url) + + local command = {hg_cmd, "clone", url, module} + local tag_or_branch = rockspec.source.tag or rockspec.source.branch + if tag_or_branch then + command = {hg_cmd, "clone", "--rev", tag_or_branch, url, module} + end + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + local ok, err = fs.change_dir(store_dir) + if not ok then return nil, err end + if not fs.execute(unpack(command)) then + return nil, "Failed cloning hg repository." + end + ok, err = fs.change_dir(module) + if not ok then return nil, err end + + fs.delete(dir.path(store_dir, module, ".hg")) + fs.delete(dir.path(store_dir, module, ".hgignore")) + fs.pop_dir() + fs.pop_dir() + return module, store_dir +end + + +return hg diff --git a/Utils/luarocks/lua/luarocks/fetch/hg_http.lua b/Utils/luarocks/lua/luarocks/fetch/hg_http.lua new file mode 100644 index 000000000..8f506daff --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/hg_http.lua @@ -0,0 +1,24 @@ + +--- Fetch back-end for retrieving sources from hg repositories +-- that use http:// transport. For example, for fetching a repository +-- that requires the following command line: +-- `hg clone http://example.com/foo` +-- you can use this in the rockspec: +-- source = { url = "hg+http://example.com/foo" } +local hg_http = {} + +local hg = require("luarocks.fetch.hg") + +--- Download sources for building a rock, using hg over http. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function hg_http.get_sources(rockspec, extract, dest_dir) + rockspec.source.url = rockspec.source.url:gsub("^hg.", "") + return hg.get_sources(rockspec, extract, dest_dir) +end + +return hg_http diff --git a/Utils/luarocks/lua/luarocks/fetch/hg_https.lua b/Utils/luarocks/lua/luarocks/fetch/hg_https.lua new file mode 100644 index 000000000..e67417fe8 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/hg_https.lua @@ -0,0 +1,8 @@ + +--- Fetch back-end for retrieving sources from hg repositories +-- that use https:// transport. For example, for fetching a repository +-- that requires the following command line: +-- `hg clone https://example.com/foo` +-- you can use this in the rockspec: +-- source = { url = "hg+https://example.com/foo" } +return require "luarocks.fetch.hg_http" diff --git a/Utils/luarocks/lua/luarocks/fetch/hg_ssh.lua b/Utils/luarocks/lua/luarocks/fetch/hg_ssh.lua new file mode 100644 index 000000000..0c365fabe --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/hg_ssh.lua @@ -0,0 +1,8 @@ + +--- Fetch back-end for retrieving sources from hg repositories +-- that use ssh:// transport. For example, for fetching a repository +-- that requires the following command line: +-- `hg clone ssh://example.com/foo` +-- you can use this in the rockspec: +-- source = { url = "hg+ssh://example.com/foo" } +return require "luarocks.fetch.hg_http" diff --git a/Utils/luarocks/lua/luarocks/fetch/sscm.lua b/Utils/luarocks/lua/luarocks/fetch/sscm.lua new file mode 100644 index 000000000..5add10dba --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/sscm.lua @@ -0,0 +1,44 @@ + +--- Fetch back-end for retrieving sources from Surround SCM Server +local sscm = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +--- Download sources via Surround SCM Server for building a rock. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function sscm.get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local sscm_cmd = rockspec.variables.SSCM + local module = rockspec.source.module or dir.base_name(rockspec.source.url) + local branch, repository = string.match(rockspec.source.pathname, "^([^/]*)/(.*)") + if not branch or not repository then + return nil, "Error retrieving branch and repository from rockspec." + end + -- Search for working directory. + local working_dir + local tmp = io.popen(string.format(sscm_cmd..[[ property "/" -d -b%s -p%s]], branch, repository)) + for line in tmp:lines() do + --%c because a chr(13) comes in the end. + working_dir = string.match(line, "Working directory:[%s]*(.*)%c$") + if working_dir then break end + end + tmp:close() + if not working_dir then + return nil, "Error retrieving working directory from SSCM." + end + if not fs.execute(sscm_cmd, "get", "*", "-e" , "-r", "-b"..branch, "-p"..repository, "-tmodify", "-wreplace") then + return nil, "Failed fetching files from SSCM." + end + -- FIXME: This function does not honor the dest_dir parameter. + return module, working_dir +end + +return sscm diff --git a/Utils/luarocks/lua/luarocks/fetch/svn.lua b/Utils/luarocks/lua/luarocks/fetch/svn.lua new file mode 100644 index 000000000..29bce1b5f --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fetch/svn.lua @@ -0,0 +1,64 @@ + +--- Fetch back-end for retrieving sources from Subversion. +local svn = {} + +local unpack = unpack or table.unpack + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Download sources for building a rock, using Subversion. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function svn.get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local svn_cmd = rockspec.variables.SVN + local ok, err_msg = fs.is_tool_available(svn_cmd, "--version", "Subversion") + if not ok then + return nil, err_msg + end + + local name_version = rockspec.name .. "-" .. rockspec.version + local module = rockspec.source.module or dir.base_name(rockspec.source.url) + local url = rockspec.source.url:gsub("^svn://", "") + local command = {svn_cmd, "checkout", url, module} + if rockspec.source.tag then + table.insert(command, 5, "-r") + table.insert(command, 6, rockspec.source.tag) + end + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + local ok, err = fs.change_dir(store_dir) + if not ok then return nil, err end + if not fs.execute(unpack(command)) then + return nil, "Failed fetching files from Subversion." + end + ok, err = fs.change_dir(module) + if not ok then return nil, err end + for _, d in ipairs(fs.find(".")) do + if dir.base_name(d) == ".svn" then + fs.delete(dir.path(store_dir, module, d)) + end + end + fs.pop_dir() + fs.pop_dir() + return module, store_dir +end + + +return svn diff --git a/Utils/luarocks/lua/luarocks/fs.lua b/Utils/luarocks/lua/luarocks/fs.lua new file mode 100644 index 000000000..54cc7d73d --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs.lua @@ -0,0 +1,76 @@ + +--- Proxy module for filesystem and platform abstractions. +-- All code using "fs" code should require "luarocks.fs", +-- and not the various platform-specific implementations. +-- However, see the documentation of the implementation +-- for the API reference. + +local pairs = pairs + +local fs = {} +package.loaded["luarocks.fs"] = fs + +local cfg = require("luarocks.cfg") + +local pack = table.pack or function(...) return { n = select("#", ...), ... } end +local unpack = table.unpack or unpack + +local old_popen, old_exec +fs.verbose = function() -- patch io.popen and os.execute to display commands in verbose mode + if old_popen or old_exec then return end + old_popen = io.popen + io.popen = function(one, two) + if two == nil then + print("\nio.popen: ", one) + else + print("\nio.popen: ", one, "Mode:", two) + end + return old_popen(one, two) + end + + old_exec = os.execute + os.execute = function(cmd) + -- redact api keys if present + print("\nos.execute: ", (cmd:gsub("(/api/[^/]+/)([^/]+)/", function(cap, key) return cap.."/" end)) ) + local code = pack(old_exec(cmd)) + print("Results: "..tostring(code.n)) + for i = 1,code.n do + print(" "..tostring(i).." ("..type(code[i]).."): "..tostring(code[i])) + end + return unpack(code, 1, code.n) + end +end +if cfg.verbose then fs.verbose() end + +local function load_fns(fs_table) + for name, fn in pairs(fs_table) do + if not fs[name] then + fs[name] = fn + end + end +end + +-- Load platform-specific functions +local loaded_platform = nil +for _, platform in ipairs(cfg.platforms) do + local ok, fs_plat = pcall(require, "luarocks.fs."..platform) + if ok and fs_plat then + loaded_platform = platform + load_fns(fs_plat) + break + end +end + +-- Load platform-independent pure-Lua functionality +local fs_lua = require("luarocks.fs.lua") +load_fns(fs_lua) + +-- Load platform-specific fallbacks for missing Lua modules +local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") +if ok and fs_plat_tools then + load_fns(fs_plat_tools) + load_fns(require("luarocks.fs.tools")) +end + + +return fs diff --git a/Utils/luarocks/lua/luarocks/fs/lua.lua b/Utils/luarocks/lua/luarocks/fs/lua.lua new file mode 100644 index 000000000..41711eab6 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs/lua.lua @@ -0,0 +1,873 @@ + +--- Native Lua implementation of filesystem and platform abstractions, +-- using LuaFileSystem, LZLib, MD5 and LuaCurl. +-- module("luarocks.fs.lua") +local fs_lua = {} + +local fs = require("luarocks.fs") + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") +local path = require("luarocks.path") + +local socket_ok, zip_ok, unzip_ok, lfs_ok, md5_ok, posix_ok, _ +local http, ftp, lrzip, luazip, lfs, md5, posix + +if cfg.fs_use_modules then + socket_ok, http = pcall(require, "socket.http") + _, ftp = pcall(require, "socket.ftp") + zip_ok, lrzip = pcall(require, "luarocks.tools.zip") + unzip_ok, luazip = pcall(require, "zip"); _G.zip = nil + lfs_ok, lfs = pcall(require, "lfs") + md5_ok, md5 = pcall(require, "md5") + posix_ok, posix = pcall(require, "posix") +end + +local patch = require("luarocks.tools.patch") + +local dir_stack = {} + +local dir_separator = "/" + +--- Test is file/dir is writable. +-- Warning: testing if a file/dir is writable does not guarantee +-- that it will remain writable and therefore it is no replacement +-- for checking the result of subsequent operations. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function fs_lua.is_writable(file) + assert(file) + file = dir.normalize(file) + local result + if fs.is_dir(file) then + local file2 = dir.path(file, '.tmpluarockstestwritable') + local fh = io.open(file2, 'wb') + result = fh ~= nil + if fh then fh:close() end + os.remove(file2) + else + local fh = io.open(file, 'r+b') + result = fh ~= nil + if fh then fh:close() end + end + return result +end + +local function quote_args(command, ...) + local out = { command } + for _, arg in ipairs({...}) do + assert(type(arg) == "string") + out[#out+1] = fs.Q(arg) + end + return table.concat(out, " ") +end + +--- Run the given command, quoting its arguments. +-- The command is executed in the current directory in the dir stack. +-- @param command string: The command to be executed. No quoting/escaping +-- is applied. +-- @param ... Strings containing additional arguments, which are quoted. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function fs_lua.execute(command, ...) + assert(type(command) == "string") + return fs.execute_string(quote_args(command, ...)) +end + +--- Run the given command, quoting its arguments, silencing its output. +-- The command is executed in the current directory in the dir stack. +-- Silencing is omitted if 'verbose' mode is enabled. +-- @param command string: The command to be executed. No quoting/escaping +-- is applied. +-- @param ... Strings containing additional arguments, which will be quoted. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function fs_lua.execute_quiet(command, ...) + assert(type(command) == "string") + if cfg.verbose then -- omit silencing output + return fs.execute_string(quote_args(command, ...)) + else + return fs.execute_string(fs.quiet(quote_args(command, ...))) + end +end + +--- Checks if the given tool is available. +-- The tool is executed using a flag, usually just to ask its version. +-- @param tool_cmd string: The command to be used to check the tool's presence (e.g. hg in case of Mercurial) +-- @param tool_name string: The actual name of the tool (e.g. Mercurial) +-- @param arg string: The flag to pass to the tool. '--version' by default. +function fs_lua.is_tool_available(tool_cmd, tool_name, arg) + assert(type(tool_cmd) == "string") + assert(type(tool_name) == "string") + + arg = arg or "--version" + assert(type(arg) == "string") + + if not fs.execute_quiet(fs.Q(tool_cmd), arg) then + local msg = "'%s' program not found. Make sure %s is installed and is available in your PATH " .. + "(or you may want to edit the 'variables.%s' value in file '%s')" + return nil, msg:format(tool_cmd, tool_name, tool_name:upper(), cfg.which_config().nearest) + else + return true + end +end + +--- Check the MD5 checksum for a file. +-- @param file string: The file to be checked. +-- @param md5sum string: The string with the expected MD5 checksum. +-- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false + msg if not +-- or if it could not perform the check for any reason. +function fs_lua.check_md5(file, md5sum) + file = dir.normalize(file) + local computed, msg = fs.get_md5(file) + if not computed then + return false, msg + end + if computed:match("^"..md5sum) then + return true + else + return false, "Mismatch MD5 hash for file "..file + end +end + +--- List the contents of a directory. +-- @param at string or nil: directory to list (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function fs_lua.list_dir(at) + local result = {} + for file in fs.dir(at) do + result[#result+1] = file + end + return result +end + +--- Iterate over the contents of a directory. +-- @param at string or nil: directory to list (will be the current +-- directory if none is given). +-- @return function: an iterator function suitable for use with +-- the for statement. +function fs_lua.dir(at) + if not at then + at = fs.current_dir() + end + at = dir.normalize(at) + if not fs.is_dir(at) then + return function() end + end + return coroutine.wrap(function() fs.dir_iterator(at) end) +end + +--------------------------------------------------------------------- +-- LuaFileSystem functions +--------------------------------------------------------------------- + +if lfs_ok then + +--- Run the given command. +-- The command is executed in the current directory in the dir stack. +-- @param cmd string: No quoting/escaping is applied to the command. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function fs_lua.execute_string(cmd) + local code = os.execute(cmd) + return (code == 0 or code == true) +end + +--- Obtain current directory. +-- Uses the module's internal dir stack. +-- @return string: the absolute pathname of the current directory. +function fs_lua.current_dir() + return lfs.currentdir() +end + +--- Change the current directory. +-- Uses the module's internal dir stack. This does not have exact +-- semantics of chdir, as it does not handle errors the same way, +-- but works well for our purposes for now. +-- @param d string: The directory to switch to. +function fs_lua.change_dir(d) + table.insert(dir_stack, lfs.currentdir()) + d = dir.normalize(d) + return lfs.chdir(d) +end + +--- Change directory to root. +-- Allows leaving a directory (e.g. for deleting it) in +-- a crossplatform way. +function fs_lua.change_dir_to_root() + local current = lfs.currentdir() + if not current or current == "" then + return false + end + table.insert(dir_stack, current) + lfs.chdir("/") -- works on Windows too + return true +end + +--- Change working directory to the previous in the dir stack. +-- @return true if a pop ocurred, false if the stack was empty. +function fs_lua.pop_dir() + local d = table.remove(dir_stack) + if d then + lfs.chdir(d) + return true + else + return false + end +end + +--- Create a directory if it does not already exist. +-- If any of the higher levels in the path name do not exist +-- too, they are created as well. +-- @param directory string: pathname of directory to create. +-- @return boolean or (boolean, string): true on success or (false, error message) on failure. +function fs_lua.make_dir(directory) + assert(type(directory) == "string") + directory = dir.normalize(directory) + local path = nil + if directory:sub(2, 2) == ":" then + path = directory:sub(1, 2) + directory = directory:sub(4) + else + if directory:match("^/") then + path = "" + end + end + for d in directory:gmatch("([^"..dir.separator.."]+)"..dir.separator.."*") do + path = path and path .. dir.separator .. d or d + local mode = lfs.attributes(path, "mode") + if not mode then + local ok, err = lfs.mkdir(path) + if not ok then + return false, err + end + ok, err = fs.chmod(path, cfg.perm_exec) + if not ok then + return false, err + end + elseif mode ~= "directory" then + return false, path.." is not a directory" + end + end + return true +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param d string: pathname of directory to remove. +function fs_lua.remove_dir_if_empty(d) + assert(d) + d = dir.normalize(d) + lfs.rmdir(d) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param d string: pathname of directory to remove. +function fs_lua.remove_dir_tree_if_empty(d) + assert(d) + d = dir.normalize(d) + for i=1,10 do + lfs.rmdir(d) + d = dir.dir_name(d) + end +end + +--- Copy a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perms string or nil: Permissions for destination file, +-- or nil to use the source filename permissions +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function fs_lua.copy(src, dest, perms) + assert(src and dest) + src = dir.normalize(src) + dest = dir.normalize(dest) + local destmode = lfs.attributes(dest, "mode") + if destmode == "directory" then + dest = dir.path(dest, dir.base_name(src)) + end + if not perms then perms = fs.get_permissions(src) end + local src_h, err = io.open(src, "rb") + if not src_h then return nil, err end + local dest_h, err = io.open(dest, "w+b") + if not dest_h then src_h:close() return nil, err end + while true do + local block = src_h:read(8192) + if not block then break end + dest_h:write(block) + end + src_h:close() + dest_h:close() + fs.chmod(dest, perms) + return true +end + +--- Implementation function for recursive copy of directory contents. +-- Assumes paths are normalized. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perms string or nil: Optional permissions. +-- If not given, permissions of the source are copied over to the destination. +-- @return boolean or (boolean, string): true on success, false on failure +local function recursive_copy(src, dest, perms) + local srcmode = lfs.attributes(src, "mode") + + if srcmode == "file" then + local ok = fs.copy(src, dest, perms) + if not ok then return false end + elseif srcmode == "directory" then + local subdir = dir.path(dest, dir.base_name(src)) + local ok, err = fs.make_dir(subdir) + if not ok then return nil, err end + for file in lfs.dir(src) do + if file ~= "." and file ~= ".." then + local ok = recursive_copy(dir.path(src, file), subdir, perms) + if not ok then return false end + end + end + end + return true +end + +--- Recursively copy the contents of a directory. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perms string or nil: Optional permissions. +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function fs_lua.copy_contents(src, dest, perms) + assert(src and dest) + src = dir.normalize(src) + dest = dir.normalize(dest) + assert(lfs.attributes(src, "mode") == "directory") + + for file in lfs.dir(src) do + if file ~= "." and file ~= ".." then + local ok = recursive_copy(dir.path(src, file), dest, perms) + if not ok then + return false, "Failed copying "..src.." to "..dest + end + end + end + return true +end + +--- Implementation function for recursive removal of directories. +-- Assumes paths are normalized. +-- @param name string: Pathname of file +-- @return boolean or (boolean, string): true on success, +-- or nil and an error message on failure. +local function recursive_delete(name) + local ok = os.remove(name) + if ok then return true end + local pok, ok, err = pcall(function() + for file in lfs.dir(name) do + if file ~= "." and file ~= ".." then + local ok, err = recursive_delete(dir.path(name, file)) + if not ok then return nil, err end + end + end + local ok, err = lfs.rmdir(name) + return ok, (not ok) and err + end) + if pok then + return ok, err + else + return pok, ok + end +end + +--- Delete a file or a directory and all its contents. +-- @param name string: Pathname of source +-- @return nil +function fs_lua.delete(name) + name = dir.normalize(name) + recursive_delete(name) +end + +--- Internal implementation function for fs.dir. +-- Yields a filename on each iteration. +-- @param at string: directory to list +-- @return nil +function fs_lua.dir_iterator(at) + for file in lfs.dir(at) do + if file ~= "." and file ~= ".." then + coroutine.yield(file) + end + end +end + +--- Implementation function for recursive find. +-- Assumes paths are normalized. +-- @param cwd string: Current working directory in recursion. +-- @param prefix string: Auxiliary prefix string to form pathname. +-- @param result table: Array of strings where results are collected. +local function recursive_find(cwd, prefix, result) + for file in lfs.dir(cwd) do + if file ~= "." and file ~= ".." then + local item = prefix .. file + table.insert(result, item) + local pathname = dir.path(cwd, file) + if lfs.attributes(pathname, "mode") == "directory" then + recursive_find(pathname, item..dir_separator, result) + end + end + end +end + +--- Recursively scan the contents of a directory. +-- @param at string or nil: directory to scan (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function fs_lua.find(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + at = dir.normalize(at) + if not fs.is_dir(at) then + return {} + end + local result = {} + recursive_find(at, "", result) + return result +end + +--- Test for existance of a file. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function fs_lua.exists(file) + assert(file) + file = dir.normalize(file) + return type(lfs.attributes(file)) == "table" +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function fs_lua.is_dir(file) + assert(file) + file = dir.normalize(file) + return lfs.attributes(file, "mode") == "directory" +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a file, false otherwise. +function fs_lua.is_file(file) + assert(file) + file = dir.normalize(file) + return lfs.attributes(file, "mode") == "file" +end + +function fs_lua.set_time(file, time) + file = dir.normalize(file) + return lfs.touch(file, time) +end + +end + +--------------------------------------------------------------------- +-- LuaZip functions +--------------------------------------------------------------------- + +if zip_ok then + +function fs_lua.zip(zipfile, ...) + return lrzip.zip(zipfile, ...) +end + +end + +if unzip_ok then +--- Uncompress files from a .zip archive. +-- @param zipfile string: pathname of .zip archive to be extracted. +-- @return boolean: true on success, false on failure. +function fs_lua.unzip(zipfile) + local zipfile, err = luazip.open(zipfile) + if not zipfile then return nil, err end + local files = zipfile:files() + local file = files() + repeat + if file.filename:sub(#file.filename) == "/" then + local ok, err = fs.make_dir(dir.path(fs.current_dir(), file.filename)) + if not ok then return nil, err end + else + local base = dir.dir_name(file.filename) + if base ~= "" then + base = dir.path(fs.current_dir(), base) + if not fs.is_dir(base) then + local ok, err = fs.make_dir(base) + if not ok then return nil, err end + end + end + local rf, err = zipfile:open(file.filename) + if not rf then zipfile:close(); return nil, err end + local contents = rf:read("*a") + rf:close() + local wf, err = io.open(dir.path(fs.current_dir(), file.filename), "wb") + if not wf then zipfile:close(); return nil, err end + wf:write(contents) + wf:close() + end + file = files() + until not file + zipfile:close() + return true +end + +end + +--------------------------------------------------------------------- +-- LuaSocket functions +--------------------------------------------------------------------- + +if socket_ok then + +local ltn12 = require("ltn12") +local luasec_ok, https = pcall(require, "ssl.https") + +local redirect_protocols = { + http = http, + https = luasec_ok and https, +} + +local function request(url, method, http, loop_control) + local result = {} + + local proxy = cfg.http_proxy + if type(proxy) ~= "string" then proxy = nil end + -- LuaSocket's http.request crashes when given URLs missing the scheme part. + if proxy and not proxy:find("://") then + proxy = "http://" .. proxy + end + + if cfg.show_downloads then + io.write(method.." "..url.." ...\n") + end + local dots = 0 + if cfg.connection_timeout and cfg.connection_timeout > 0 then + http.TIMEOUT = cfg.connection_timeout + end + local res, status, headers, err = http.request { + url = url, + proxy = proxy, + method = method, + redirect = false, + sink = ltn12.sink.table(result), + step = cfg.show_downloads and function(...) + io.write(".") + io.flush() + dots = dots + 1 + if dots == 70 then + io.write("\n") + dots = 0 + end + return ltn12.pump.step(...) + end, + headers = { + ["user-agent"] = cfg.user_agent.." via LuaSocket" + }, + } + if cfg.show_downloads then + io.write("\n") + end + if not res then + return nil, status + elseif status == 301 or status == 302 then + local location = headers.location + if location then + local protocol, rest = dir.split_url(location) + if redirect_protocols[protocol] then + if not loop_control then + loop_control = {} + elseif loop_control[location] then + return nil, "Redirection loop -- broken URL?" + end + loop_control[url] = true + return request(location, method, redirect_protocols[protocol], loop_control) + else + return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support.", "https" + end + end + return nil, err + elseif status ~= 200 then + return nil, err + else + return result, status, headers, err + end +end + +local function http_request(url, http, cached) + if cached then + local tsfd = io.open(cached..".timestamp", "r") + if tsfd then + local timestamp = tsfd:read("*a") + tsfd:close() + local result, status, headers, err = request(url, "HEAD", http) + if status == 200 and headers["last-modified"] == timestamp then + return true + end + if not result then + return nil, status, headers + end + end + end + local result, status, headers, err = request(url, "GET", http) + if result then + if cached and headers["last-modified"] then + local tsfd = io.open(cached..".timestamp", "w") + if tsfd then + tsfd:write(headers["last-modified"]) + tsfd:close() + end + end + return table.concat(result) + else + return nil, status, headers + end +end + +local downloader_warning = false + +--- Download a remote file. +-- @param url string: URL to be fetched. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return (boolean, string): true and the filename on success, +-- false and the error message on failure. +function fs_lua.download(url, filename, cache) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + filename = fs.absolute_name(filename or dir.base_name(url)) + + -- delegate to the configured downloader so we don't have to deal with whitelists + if cfg.no_proxy then + return fs.use_downloader(url, filename, cache) + end + + local content, err, https_err + if util.starts_with(url, "http:") then + content, err, https_err = http_request(url, http, cache and filename) + elseif util.starts_with(url, "ftp:") then + content, err = ftp.get(url) + elseif util.starts_with(url, "https:") then + -- skip LuaSec when proxy is enabled since it is not supported + if luasec_ok and not cfg.https_proxy then + content, err = http_request(url, https, cache and filename) + else + https_err = true + end + else + err = "Unsupported protocol" + end + if https_err then + if not downloader_warning then + util.printerr("Warning: falling back to "..cfg.downloader.." - install luasec to get native HTTPS support") + downloader_warning = true + end + return fs.use_downloader(url, filename, cache) + end + if cache and content == true then + return true, filename + end + if not content then + return false, tostring(err) + end + local file = io.open(filename, "wb") + if not file then return false end + file:write(content) + file:close() + return true, filename +end + +else --...if socket_ok == false then + +function fs_lua.download(url, filename, cache) + return fs.use_downloader(url, filename, cache) +end + +end +--------------------------------------------------------------------- +-- MD5 functions +--------------------------------------------------------------------- + +if md5_ok then + +-- Support the interface of lmd5 by lhf in addition to md5 by Roberto +-- and the keplerproject. +if not md5.sumhexa and md5.digest then + md5.sumhexa = function(msg) + return md5.digest(msg) + end +end + +--- Get the MD5 checksum for a file. +-- @param file string: The file to be computed. +-- @return string: The MD5 checksum or nil + error +function fs_lua.get_md5(file) + file = fs.absolute_name(file) + local file_handler = io.open(file, "rb") + if not file_handler then return nil, "Failed to open file for reading: "..file end + local computed = md5.sumhexa(file_handler:read("*a")) + file_handler:close() + if computed then return computed end + return nil, "Failed to compute MD5 hash for file "..file +end + +end + +--------------------------------------------------------------------- +-- POSIX functions +--------------------------------------------------------------------- + +if posix_ok then + +local octal_to_rwx = { + ["0"] = "---", + ["1"] = "--x", + ["2"] = "-w-", + ["3"] = "-wx", + ["4"] = "r--", + ["5"] = "r-x", + ["6"] = "rw-", + ["7"] = "rwx", +} + +function fs_lua.chmod(file, mode) + -- LuaPosix (as of 5.1.15) does not support octal notation... + if mode:sub(1,1) == "0" then + local new_mode = {} + for c in mode:sub(-3):gmatch(".") do + table.insert(new_mode, octal_to_rwx[c]) + end + mode = table.concat(new_mode) + end + local err = posix.chmod(file, mode) + return err == 0 +end + +function fs_lua.get_permissions(file) + return posix.stat(file, "mode") +end + +--- Create a temporary directory. +-- @param name string: name pattern to use for avoiding conflicts +-- when creating temporary directory. +-- @return string or (nil, string): name of temporary directory or (nil, error message) on failure. +function fs_lua.make_temp_dir(name) + assert(type(name) == "string") + name = dir.normalize(name) + + return posix.mkdtemp((os.getenv("TMPDIR") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-XXXXXX") +end + +end + +--------------------------------------------------------------------- +-- Other functions +--------------------------------------------------------------------- + +--- Apply a patch. +-- @param patchname string: The filename of the patch. +-- @param patchdata string or nil: The actual patch as a string. +function fs_lua.apply_patch(patchname, patchdata) + local p, all_ok = patch.read_patch(patchname, patchdata) + if not all_ok then + return nil, "Failed reading patch "..patchname + end + if p then + return patch.apply_patch(p, 1) + end +end + +--- Move a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perms string or nil: Permissions for destination file, +-- or nil to use the source filename permissions. +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function fs_lua.move(src, dest, perms) + assert(src and dest) + if fs.exists(dest) and not fs.is_dir(dest) then + return false, "File already exists: "..dest + end + local ok, err = fs.copy(src, dest, perms) + if not ok then + return false, err + end + fs.delete(src) + if fs.exists(src) then + return false, "Failed move: could not delete "..src.." after copy." + end + return true +end + +--- Check if user has write permissions for the command. +-- Assumes the configuration variables under cfg have been previously set up. +-- @param flags table: the flags table passed to run() drivers. +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function fs_lua.check_command_permissions(flags) + local root_dir = path.root_dir(cfg.rocks_dir) + local ok = true + local err = "" + for _, dir in ipairs { cfg.rocks_dir, root_dir } do + if fs.exists(dir) and not fs.is_writable(dir) then + ok = false + err = "Your user does not have write permissions in " .. dir + break + end + end + if ok and not fs.exists(root_dir) then + local root = fs.root_of(root_dir) + local parent = root_dir + repeat + parent = dir.dir_name(parent) + if parent == "" then + parent = root + end + until parent == root or fs.exists(parent) + if not fs.is_writable(parent) then + ok = false + err = root_dir.." does not exist and your user does not have write permissions in " .. parent + end + end + if ok then + return true + else + if flags["local"] then + err = err .. " \n-- please check your permissions." + else + err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local." + end + return nil, err + end +end + +--- Check whether a file is a Lua script +-- When the file can be succesfully compiled by the configured +-- Lua interpreter, it's considered to be a valid Lua file. +-- @param name filename of file to check +-- @return boolean true, if it is a Lua script, false otherwise +function fs_lua.is_lua(name) + name = name:gsub([[%\]],"/") -- normalize on fw slash to prevent escaping issues + local lua = fs.Q(dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)) -- get lua interpreter configured + -- execute on configured interpreter, might not be the same as the interpreter LR is run on + local result = fs.execute_string(lua..[[ -e "if loadfile(']]..name..[[') then os.exit() else os.exit(1) end"]]) + return (result == true) +end + +return fs_lua diff --git a/Utils/luarocks/lua/luarocks/fs/tools.lua b/Utils/luarocks/lua/luarocks/fs/tools.lua new file mode 100644 index 000000000..ed51b5458 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs/tools.lua @@ -0,0 +1,156 @@ + +--- Common fs operations implemented with third-party tools. +local tools = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +local vars = cfg.variables + +local dir_stack = {} + +--- Obtain current directory. +-- Uses the module's internal directory stack. +-- @return string: the absolute pathname of the current directory. +function tools.current_dir() + local current = cfg.cache_pwd + if not current then + local pipe = io.popen(fs.quiet_stderr(fs.Q(vars.PWD))) + current = pipe:read("*l") + pipe:close() + cfg.cache_pwd = current + end + for _, directory in ipairs(dir_stack) do + current = fs.absolute_name(directory, current) + end + return current +end + +--- Change the current directory. +-- Uses the module's internal directory stack. This does not have exact +-- semantics of chdir, as it does not handle errors the same way, +-- but works well for our purposes for now. +-- @param directory string: The directory to switch to. +-- @return boolean or (nil, string): true if successful, (nil, error message) if failed. +function tools.change_dir(directory) + assert(type(directory) == "string") + if fs.is_dir(directory) then + table.insert(dir_stack, directory) + return true + end + return nil, "directory not found: "..directory +end + +--- Change directory to root. +-- Allows leaving a directory (e.g. for deleting it) in +-- a crossplatform way. +function tools.change_dir_to_root() + table.insert(dir_stack, "/") +end + +--- Change working directory to the previous in the directory stack. +function tools.pop_dir() + local directory = table.remove(dir_stack) + return directory ~= nil +end + +--- Run the given command. +-- The command is executed in the current directory in the directory stack. +-- @param cmd string: No quoting/escaping is applied to the command. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function tools.execute_string(cmd) + local current = fs.current_dir() + if not current then return false end + cmd = fs.command_at(current, cmd) + local code = os.execute(cmd) + if code == 0 or code == true then + return true + else + return false + end +end + +--- Internal implementation function for fs.dir. +-- Yields a filename on each iteration. +-- @param at string: directory to list +-- @return nil +function tools.dir_iterator(at) + local pipe = io.popen(fs.command_at(at, fs.Q(vars.LS))) + for file in pipe:lines() do + if file ~= "." and file ~= ".." then + coroutine.yield(file) + end + end + pipe:close() +end + +--- Download a remote file. +-- @param url string: URL to be fetched. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return (boolean, string): true and the filename on success, +-- false and the error message on failure. +function tools.use_downloader(url, filename, cache) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + filename = fs.absolute_name(filename or dir.base_name(url)) + + local ok + if cfg.downloader == "wget" then + local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet " + if cfg.connection_timeout and cfg.connection_timeout > 0 then + wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 " + end + if cache then + -- --timestamping is incompatible with --output-document, + -- but that's not a problem for our use cases. + fs.change_dir(dir.dir_name(filename)) + ok = fs.execute_quiet(wget_cmd.." --timestamping ", url) + fs.pop_dir() + elseif filename then + ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url) + else + ok = fs.execute_quiet(wget_cmd, url) + end + elseif cfg.downloader == "curl" then + local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" " + if cfg.connection_timeout and cfg.connection_timeout > 0 then + curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." " + end + ok = fs.execute_string(fs.quiet_stderr(curl_cmd..fs.Q(url).." > "..fs.Q(filename))) + end + if ok then + return true, filename + else + return false + end +end + +local md5_cmd = { + md5sum = fs.Q(vars.MD5SUM), + openssl = fs.Q(vars.OPENSSL).." md5", + md5 = fs.Q(vars.MD5), +} + +--- Get the MD5 checksum for a file. +-- @param file string: The file to be computed. +-- @return string: The MD5 checksum or nil + message +function tools.get_md5(file) + local cmd = md5_cmd[cfg.md5checker] + if not cmd then return nil, "no MD5 checker command configured" end + local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file))) + local computed = pipe:read("*a") + pipe:close() + if computed then + computed = computed:match("("..("%x"):rep(32)..")") + end + if computed then return computed end + return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file)) +end + +return tools diff --git a/Utils/luarocks/lua/luarocks/fs/unix.lua b/Utils/luarocks/lua/luarocks/fs/unix.lua new file mode 100644 index 000000000..e2bdc7b8f --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs/unix.lua @@ -0,0 +1,135 @@ + +--- Unix implementation of filesystem and platform abstractions. +local unix = {} + +local fs = require("luarocks.fs") + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Annotate command string for quiet execution. +-- @param cmd string: A command-line string. +-- @return string: The command-line, with silencing annotation. +function unix.quiet(cmd) + return cmd.." 1> /dev/null 2> /dev/null" +end + +--- Annotate command string for execution with quiet stderr. +-- @param cmd string: A command-line string. +-- @return string: The command-line, with stderr silencing annotation. +function unix.quiet_stderr(cmd) + return cmd.." 2> /dev/null" +end + +--- Quote argument for shell processing. +-- Adds single quotes and escapes. +-- @param arg string: Unquoted argument. +-- @return string: Quoted argument. +function unix.Q(arg) + assert(type(arg) == "string") + return "'" .. arg:gsub("'", "'\\''") .. "'" +end + +--- Return an absolute pathname from a potentially relative one. +-- @param pathname string: pathname to convert. +-- @param relative_to string or nil: path to prepend when making +-- pathname absolute, or the current dir in the dir stack if +-- not given. +-- @return string: The pathname converted to absolute. +function unix.absolute_name(pathname, relative_to) + assert(type(pathname) == "string") + assert(type(relative_to) == "string" or not relative_to) + + relative_to = relative_to or fs.current_dir() + if pathname:sub(1,1) == "/" then + return pathname + else + return relative_to .. "/" .. pathname + end +end + +--- Return the root directory for the given path. +-- In Unix, root is always "/". +-- @param pathname string: pathname to use. +-- @return string: The root of the given pathname. +function unix.root_of(_) + return "/" +end + +--- Create a wrapper to make a script executable from the command-line. +-- @param file string: Pathname of script to be made executable. +-- @param dest string: Directory where to put the wrapper. +-- @param name string: rock name to be used in loader context. +-- @param version string: rock version to be used in loader context. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function unix.wrap_script(file, dest, name, version) + assert(type(file) == "string") + assert(type(dest) == "string") + + local base = dir.base_name(file) + local wrapname = fs.is_dir(dest) and dest.."/"..base or dest + local lpath, lcpath = cfg.package_paths() + local wrapper = io.open(wrapname, "w") + if not wrapper then + return nil, "Could not open "..wrapname.." for writing." + end + wrapper:write("#!/bin/sh\n\n") + local lua = dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter) + local ppaths = "package.path="..util.LQ(lpath..";").."..package.path; package.cpath="..util.LQ(lcpath..";").."..package.cpath" + local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k and l.add_context("..util.LQ(name)..","..util.LQ(version)..")" + wrapper:write('exec '..fs.Q(lua)..' -e '..fs.Q(ppaths)..' -e '..fs.Q(addctx)..' '..fs.Q(file)..' "$@"\n') + wrapper:close() + if fs.chmod(wrapname, cfg.perm_exec) then + return true + else + return nil, "Could not make "..wrapname.." executable." + end +end + +--- Check if a file (typically inside path.bin_dir) is an actual binary +-- or a Lua wrapper. +-- @param filename string: the file name with full path. +-- @return boolean: returns true if file is an actual binary +-- (or if it couldn't check) or false if it is a Lua wrapper. +function unix.is_actual_binary(filename) + if filename:match("%.lua$") then + return false + end + local file = io.open(filename) + if not file then + return true + end + local first = file:read(2) + file:close() + if not first then + util.printerr("Warning: could not read "..filename) + return true + end + return first ~= "#!" +end + +function unix.copy_binary(filename, dest) + return fs.copy(filename, dest, cfg.perm_exec) +end + +--- Move a file on top of the other. +-- The new file ceases to exist under its original name, +-- and takes over the name of the old file. +-- On Unix this is done through a single rename operation. +-- @param old_file The name of the original file, +-- which will be the new name of new_file. +-- @param new_file The name of the new file, +-- which will replace old_file. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function unix.replace_file(old_file, new_file) + return os.rename(new_file, old_file) +end + +function unix.tmpname() + return os.tmpname() +end + +return unix diff --git a/Utils/luarocks/lua/luarocks/fs/unix/tools.lua b/Utils/luarocks/lua/luarocks/fs/unix/tools.lua new file mode 100644 index 000000000..d0802725a --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs/unix/tools.lua @@ -0,0 +1,237 @@ + +--- fs operations implemented with third-party tools for Unix platform abstractions. +local tools = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +local vars = cfg.variables + +--- Adds prefix to command to make it run from a directory. +-- @param directory string: Path to a directory. +-- @param cmd string: A command-line string. +-- @return string: The command-line with prefix. +function tools.command_at(directory, cmd) + return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd +end + +--- Create a directory if it does not already exist. +-- If any of the higher levels in the path name does not exist +-- too, they are created as well. +-- @param directory string: pathname of directory to create. +-- @return boolean: true on success, false on failure. +function tools.make_dir(directory) + assert(directory) + local ok, err = fs.execute(vars.MKDIR.." -p", directory) + if not ok then + err = "failed making directory "..directory + end + return ok, err +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function tools.remove_dir_if_empty(directory) + assert(directory) + fs.execute_quiet(vars.RMDIR, directory) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function tools.remove_dir_tree_if_empty(directory) + assert(directory) + fs.execute_quiet(vars.RMDIR, "-p", directory) +end + +--- Copy a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perm string or nil: Permissions for destination file, +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function tools.copy(src, dest, perm) + assert(src and dest) + if fs.execute(vars.CP, src, dest) then + if perm then + if fs.is_dir(dest) then + dest = dir.path(dest, dir.base_name(src)) + end + if fs.chmod(dest, perm) then + return true + else + return false, "Failed setting permissions of "..dest + end + end + return true + else + return false, "Failed copying "..src.." to "..dest + end +end + +--- Recursively copy the contents of a directory. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function tools.copy_contents(src, dest) + assert(src and dest) + if fs.execute_quiet(vars.CP.." -pPR "..fs.Q(src).."/* "..fs.Q(dest)) then + return true + else + return false, "Failed copying "..src.." to "..dest + end +end +--- Delete a file or a directory and all its contents. +-- For safety, this only accepts absolute paths. +-- @param arg string: Pathname of source +-- @return nil +function tools.delete(arg) + assert(arg) + assert(arg:sub(1,1) == "/") + fs.execute_quiet(vars.RM, "-rf", arg) +end + +--- Recursively scan the contents of a directory. +-- @param at string or nil: directory to scan (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function tools.find(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + if not fs.is_dir(at) then + return {} + end + local result = {} + local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(vars.FIND.." *"))) + for file in pipe:lines() do + table.insert(result, file) + end + pipe:close() + return result +end + +--- Compress files in a .zip archive. +-- @param zipfile string: pathname of .zip archive to be created. +-- @param ... Filenames to be stored in the archive are given as +-- additional arguments. +-- @return boolean: true on success, false on failure. +function tools.zip(zipfile, ...) + return fs.execute(vars.ZIP.." -r", zipfile, ...) +end + +--- Uncompress files from a .zip archive. +-- @param zipfile string: pathname of .zip archive to be extracted. +-- @return boolean: true on success, false on failure. +function tools.unzip(zipfile) + assert(zipfile) + return fs.execute_quiet(vars.UNZIP, zipfile) +end + +--- Test is file/directory exists +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function tools.exists(file) + assert(file) + return fs.execute(vars.TEST, "-e", file) +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function tools.is_dir(file) + assert(file) + return fs.execute(vars.TEST, "-d", file) +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a regular file, false otherwise. +function tools.is_file(file) + assert(file) + return fs.execute(vars.TEST, "-f", file) +end + +function tools.chmod(pathname, mode) + if mode then + return fs.execute(vars.CHMOD, mode, pathname) + else + return false + end +end + +--- Unpack an archive. +-- Extract the contents of an archive, detecting its format by +-- filename extension. +-- @param archive string: Filename of archive. +-- @return boolean or (boolean, string): true on success, false and an error message on failure. +function tools.unpack_archive(archive) + assert(type(archive) == "string") + + local pipe_to_tar = " | "..vars.TAR.." -xf -" + + if not cfg.verbose then + pipe_to_tar = " 2> /dev/null"..fs.quiet(pipe_to_tar) + end + + local ok + if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then + ok = fs.execute_string(vars.GUNZIP.." -c "..fs.Q(archive)..pipe_to_tar) + elseif archive:match("%.tar%.bz2$") then + ok = fs.execute_string(vars.BUNZIP2.." -c "..fs.Q(archive)..pipe_to_tar) + elseif archive:match("%.zip$") then + ok = fs.execute_quiet(vars.UNZIP, archive) + elseif archive:match("%.lua$") or archive:match("%.c$") then + -- Ignore .lua and .c files; they don't need to be extracted. + return true + else + return false, "Couldn't extract archive "..archive..": unrecognized filename extension" + end + if not ok then + return false, "Failed extracting "..archive + end + return true +end + +function tools.get_permissions(filename) + local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename)) + local ret = pipe:read("*l") + pipe:close() + return ret +end + +function tools.browser(url) + return fs.execute(cfg.web_browser, url) +end + +function tools.set_time(file, time) + file = dir.normalize(file) + return fs.execute(vars.TOUCH, "-d", "@"..tostring(time), file) +end + +--- Create a temporary directory. +-- @param name string: name pattern to use for avoiding conflicts +-- when creating temporary directory. +-- @return string or (nil, string): name of temporary directory or (nil, error message) on failure. +function tools.make_temp_dir(name) + assert(type(name) == "string") + name = dir.normalize(name) + + local template = (os.getenv("TMPDIR") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-XXXXXX" + local pipe = io.popen(vars.MKTEMP.." -d "..fs.Q(template)) + local dirname = pipe:read("*l") + pipe:close() + if dirname and dirname:match("^/") then + return dirname + end + return nil, "Failed to create temporary directory "..tostring(dirname) +end + +return tools diff --git a/Utils/luarocks/lua/luarocks/fs/win32.lua b/Utils/luarocks/lua/luarocks/fs/win32.lua new file mode 100644 index 000000000..cfc28d35f --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs/win32.lua @@ -0,0 +1,266 @@ +--- Windows implementation of filesystem and platform abstractions. +-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities +-- used by this module. +local win32 = {} + +local fs = require("luarocks.fs") + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +math.randomseed(os.time()) + +-- Monkey patch io.popen and os.execute to make sure quoting +-- works as expected. +-- See http://lua-users.org/lists/lua-l/2013-11/msg00367.html +local _prefix = "type NUL && " +local _popen, _execute = io.popen, os.execute +io.popen = function(cmd, ...) return _popen(_prefix..cmd, ...) end +os.execute = function(cmd, ...) return _execute(_prefix..cmd, ...) end + +--- Annotate command string for quiet execution. +-- @param cmd string: A command-line string. +-- @return string: The command-line, with silencing annotation. +function win32.quiet(cmd) + return cmd.." 2> NUL 1> NUL" +end + +--- Annotate command string for execution with quiet stderr. +-- @param cmd string: A command-line string. +-- @return string: The command-line, with stderr silencing annotation. +function win32.quiet_stderr(cmd) + return cmd.." 2> NUL" +end + +-- Split path into root and the rest. +-- Root part consists of an optional drive letter (e.g. "C:") +-- and an optional directory separator. +local function split_root(path) + local root = "" + + if path:match("^.:") then + root = path:sub(1, 2) + path = path:sub(3) + end + + if path:match("^[\\/]") then + root = path:sub(1, 1) + path = path:sub(2) + end + + return root, path +end + +--- Quote argument for shell processing. Fixes paths on Windows. +-- Adds double quotes and escapes. +-- @param arg string: Unquoted argument. +-- @return string: Quoted argument. +function win32.Q(arg) + assert(type(arg) == "string") + -- Use Windows-specific directory separator for paths. + -- Paths should be converted to absolute by now. + if split_root(arg) ~= "" then + arg = arg:gsub("/", "\\") + end + if arg == "\\" then + return '\\' -- CHDIR needs special handling for root dir + end + -- URLs and anything else + arg = arg:gsub('\\(\\*)"', '\\%1%1"') + arg = arg:gsub('\\+$', '%0%0') + arg = arg:gsub('"', '\\"') + arg = arg:gsub('(\\*)%%', '%1%1"%%"') + return '"' .. arg .. '"' +end + +--- Quote argument for shell processing in batch files. +-- Adds double quotes and escapes. +-- @param arg string: Unquoted argument. +-- @return string: Quoted argument. +function win32.Qb(arg) + assert(type(arg) == "string") + -- Use Windows-specific directory separator for paths. + -- Paths should be converted to absolute by now. + if split_root(arg) ~= "" then + arg = arg:gsub("/", "\\") + end + if arg == "\\" then + return '\\' -- CHDIR needs special handling for root dir + end + -- URLs and anything else + arg = arg:gsub('\\(\\*)"', '\\%1%1"') + arg = arg:gsub('\\+$', '%0%0') + arg = arg:gsub('"', '\\"') + arg = arg:gsub('%%', '%%%%') + return '"' .. arg .. '"' +end + +--- Return an absolute pathname from a potentially relative one. +-- @param pathname string: pathname to convert. +-- @param relative_to string or nil: path to prepend when making +-- pathname absolute, or the current dir in the dir stack if +-- not given. +-- @return string: The pathname converted to absolute. +function win32.absolute_name(pathname, relative_to) + assert(type(pathname) == "string") + assert(type(relative_to) == "string" or not relative_to) + + relative_to = relative_to or fs.current_dir() + local root, rest = split_root(pathname) + if root:match("[\\/]$") then + -- It's an absolute path already. + return pathname + else + -- It's a relative path, join it with base path. + -- This drops drive letter from paths like "C:foo". + return relative_to .. "/" .. rest + end +end + +--- Return the root directory for the given path. +-- For example, for "c:\hello", returns "c:\" +-- @param pathname string: pathname to use. +-- @return string: The root of the given pathname. +function win32.root_of(pathname) + return (split_root(fs.absolute_name(pathname))) +end + +--- Create a wrapper to make a script executable from the command-line. +-- @param file string: Pathname of script to be made executable. +-- @param dest string: Directory where to put the wrapper. +-- @param name string: rock name to be used in loader context. +-- @param version string: rock version to be used in loader context. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function win32.wrap_script(file, dest, name, version) + assert(type(file) == "string") + assert(type(dest) == "string") + + local base = dir.base_name(file) + local wrapname = fs.is_dir(dest) and dest.."/"..base or dest + wrapname = wrapname..".bat" + local lpath, lcpath = cfg.package_paths() + lpath = util.remove_path_dupes(lpath, ";") + lcpath = util.remove_path_dupes(lcpath, ";") + local wrapper = io.open(wrapname, "w") + if not wrapper then + return nil, "Could not open "..wrapname.." for writing." + end + wrapper:write("@echo off\n") + local lua = dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter) + local ppaths = "package.path="..util.LQ(lpath..";").."..package.path; package.cpath="..util.LQ(lcpath..";").."..package.cpath" + local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k and l.add_context("..util.LQ(name)..","..util.LQ(version)..")" + wrapper:write(fs.Qb(lua)..' -e '..fs.Qb(ppaths)..' -e '..fs.Qb(addctx)..' '..fs.Qb(file)..' %*\n') + wrapper:write("exit /b %ERRORLEVEL%\n") + wrapper:close() + return true +end + +function win32.is_actual_binary(name) + name = name:lower() + if name:match("%.bat$") or name:match("%.exe$") then + return true + end + return false +end + +function win32.copy_binary(filename, dest) + local ok, err = fs.copy(filename, dest) + if not ok then + return nil, err + end + local exe_pattern = "%.[Ee][Xx][Ee]$" + local base = dir.base_name(filename) + dest = dir.dir_name(dest) + if base:match(exe_pattern) then + base = base:gsub(exe_pattern, ".lua") + local helpname = dest.."/"..base + local helper = io.open(helpname, "w") + if not helper then + return nil, "Could not open "..helpname.." for writing." + end + helper:write('package.path=\"'..package.path:gsub("\\","\\\\")..';\"..package.path\n') + helper:write('package.cpath=\"'..package.path:gsub("\\","\\\\")..';\"..package.cpath\n') + helper:close() + end + return true +end + +function win32.chmod(filename, mode) + return true +end + +function win32.get_permissions(filename) + return "" +end + +--- Move a file on top of the other. +-- The new file ceases to exist under its original name, +-- and takes over the name of the old file. +-- On Windows this is done by removing the original file and +-- renaming the new file to its original name. +-- @param old_file The name of the original file, +-- which will be the new name of new_file. +-- @param new_file The name of the new file, +-- which will replace old_file. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function win32.replace_file(old_file, new_file) + os.remove(old_file) + return os.rename(new_file, old_file) +end + +--- Test is file/dir is writable. +-- Warning: testing if a file/dir is writable does not guarantee +-- that it will remain writable and therefore it is no replacement +-- for checking the result of subsequent operations. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function win32.is_writable(file) + assert(file) + file = dir.normalize(file) + local result + local tmpname = 'tmpluarockstestwritable.deleteme' + if fs.is_dir(file) then + local file2 = dir.path(file, tmpname) + local fh = io.open(file2, 'wb') + result = fh ~= nil + if fh then fh:close() end + if result then + -- the above test might give a false positive when writing to + -- c:\program files\ because of VirtualStore redirection on Vista and up + -- So check whether it's really there + result = fs.exists(file2) + end + os.remove(file2) + else + local fh = io.open(file, 'r+b') + result = fh ~= nil + if fh then fh:close() end + end + return result +end + +--- Create a temporary directory. +-- @param name string: name pattern to use for avoiding conflicts +-- when creating temporary directory. +-- @return string or (nil, string): name of temporary directory or (nil, error message) on failure. +function win32.make_temp_dir(name) + assert(type(name) == "string") + name = dir.normalize(name) + + local temp_dir = os.getenv("TMP") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) + local ok, err = fs.make_dir(temp_dir) + if ok then + return temp_dir + else + return nil, err + end +end + +function win32.tmpname() + return os.getenv("TMP")..os.tmpname() +end + +return win32 diff --git a/Utils/luarocks/lua/luarocks/fs/win32/tools.lua b/Utils/luarocks/lua/luarocks/fs/win32/tools.lua new file mode 100644 index 000000000..4adc78d1e --- /dev/null +++ b/Utils/luarocks/lua/luarocks/fs/win32/tools.lua @@ -0,0 +1,227 @@ + +--- fs operations implemented with third-party tools for Windows platform abstractions. +-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities +-- used by this module. +local tools = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +local vars = cfg.variables + +--- Adds prefix to command to make it run from a directory. +-- @param directory string: Path to a directory. +-- @param cmd string: A command-line string. +-- @return string: The command-line with prefix. +function tools.command_at(directory, cmd) + local drive = directory:match("^([A-Za-z]:)") + cmd = "cd " .. fs.Q(directory) .. " & " .. cmd + if drive then + cmd = drive .. " & " .. cmd + end + return cmd +end + +--- Create a directory if it does not already exist. +-- If any of the higher levels in the path name does not exist +-- too, they are created as well. +-- @param directory string: pathname of directory to create. +-- @return boolean: true on success, false on failure. +function tools.make_dir(directory) + assert(directory) + directory = dir.normalize(directory) + fs.execute_quiet(fs.Q(vars.MKDIR).." -p ", directory) + if not fs.is_dir(directory) then + return false, "failed making directory "..directory + end + return true +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function tools.remove_dir_if_empty(directory) + assert(directory) + fs.execute_quiet(fs.Q(vars.RMDIR), directory) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function tools.remove_dir_tree_if_empty(directory) + assert(directory) + fs.execute_quiet(fs.Q(vars.RMDIR), directory) +end + +--- Copy a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function tools.copy(src, dest) + assert(src and dest) + if dest:match("[/\\]$") then dest = dest:sub(1, -2) end + local ok = fs.execute(fs.Q(vars.CP), src, dest) + if ok then + return true + else + return false, "Failed copying "..src.." to "..dest + end +end + +--- Recursively copy the contents of a directory. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function tools.copy_contents(src, dest) + assert(src and dest) + if fs.execute_quiet(fs.Q(vars.CP), "-dR", src.."\\*.*", dest) then + return true + else + return false, "Failed copying "..src.." to "..dest + end +end + +--- Delete a file or a directory and all its contents. +-- For safety, this only accepts absolute paths. +-- @param arg string: Pathname of source +-- @return nil +function tools.delete(arg) + assert(arg) + assert(arg:match("^[a-zA-Z]?:?[\\/]")) + fs.execute_quiet("if exist "..fs.Q(arg.."\\").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )") +end + +--- Recursively scan the contents of a directory. +-- @param at string or nil: directory to scan (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. Paths are returned with forward slashes. +function tools.find(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + if not fs.is_dir(at) then + return {} + end + local result = {} + local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(fs.Q(vars.FIND)))) + for file in pipe:lines() do + -- Windows find is a bit different + local first_two = file:sub(1,2) + if first_two == ".\\" or first_two == "./" then file=file:sub(3) end + if file ~= "." then + table.insert(result, (file:gsub("\\", "/"))) + end + end + pipe:close() + return result +end + +--- Compress files in a .zip archive. +-- @param zipfile string: pathname of .zip archive to be created. +-- @param ... Filenames to be stored in the archive are given as +-- additional arguments. +-- @return boolean: true on success, false on failure. +function tools.zip(zipfile, ...) + return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa a -tzip", zipfile, ...) +end + +--- Uncompress files from a .zip archive. +-- @param zipfile string: pathname of .zip archive to be extracted. +-- @return boolean: true on success, false on failure. +function tools.unzip(zipfile) + assert(zipfile) + return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa x", zipfile) +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function tools.is_dir(file) + assert(file) + return fs.execute_quiet("if not exist " .. fs.Q(file.."\\").." invalidcommandname") +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a regular file, false otherwise. +function tools.is_file(file) + assert(file) + return fs.execute(fs.Q(vars.TEST).." -f", file) +end + +--- Strip the last extension of a filename. +-- Example: "foo.tar.gz" becomes "foo.tar". +-- If filename has no dots, returns it unchanged. +-- @param filename string: The file name to strip. +-- @return string: The stripped name. +local function strip_extension(filename) + assert(type(filename) == "string") + return (filename:gsub("%.[^.]+$", "")) or filename +end + +--- Uncompress gzip file. +-- @param archive string: Filename of archive. +-- @return boolean : success status +local function gunzip(archive) + return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa x", archive) +end + +--- Unpack an archive. +-- Extract the contents of an archive, detecting its format by +-- filename extension. +-- @param archive string: Filename of archive. +-- @return boolean or (boolean, string): true on success, false and an error message on failure. +function tools.unpack_archive(archive) + assert(type(archive) == "string") + + local ok + local sevenzx = fs.Q(vars.SEVENZ).." -aoa x" + if archive:match("%.tar%.gz$") then + ok = gunzip(archive) + if ok then + ok = fs.execute_quiet(sevenzx, strip_extension(archive)) + end + elseif archive:match("%.tgz$") then + ok = gunzip(archive) + if ok then + ok = fs.execute_quiet(sevenzx, strip_extension(archive)..".tar") + end + elseif archive:match("%.tar%.bz2$") then + ok = fs.execute_quiet(sevenzx, archive) + if ok then + ok = fs.execute_quiet(sevenzx, strip_extension(archive)) + end + elseif archive:match("%.zip$") then + ok = fs.execute_quiet(sevenzx, archive) + elseif archive:match("%.lua$") or archive:match("%.c$") then + -- Ignore .lua and .c files; they don't need to be extracted. + return true + else + return false, "Couldn't extract archive "..archive..": unrecognized filename extension" + end + if not ok then + return false, "Failed extracting "..archive + end + return true +end + +--- Test for existance of a file. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function tools.exists(file) + assert(file) + return fs.execute_quiet("if not exist " .. fs.Q(file) .. " invalidcommandname") +end + +function tools.browser(url) + return fs.execute(cfg.web_browser..' "Starting docs..." '..fs.Q(url)) +end + +return tools diff --git a/Utils/luarocks/lua/luarocks/help.lua b/Utils/luarocks/lua/luarocks/help.lua new file mode 100644 index 000000000..871e97e99 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/help.lua @@ -0,0 +1,118 @@ + +--- Module implementing the LuaRocks "help" command. +-- This is a generic help display module, which +-- uses a global table called "commands" to find commands +-- to show help for; each command should be represented by a +-- table containing "help" and "help_summary" fields. +local help = {} + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") + +local program = util.this_program("luarocks") + +util.add_run_function(help) +help.help_summary = "Help on commands. Type '"..program.." help ' for more." + +help.help_arguments = "[]" +help.help = [[ + is the command to show help for. +]] + +local function print_banner() + util.printout("\nLuaRocks "..cfg.program_version..", a module deployment system for Lua") +end + +local function print_section(section) + util.printout("\n"..section) +end + +local function get_status(status) + if status then + return "ok" + else + return "not found" + end +end + +--- Driver function for the "help" command. +-- @param command string or nil: command to show help for; if not +-- given, help summaries for all commands are shown. +-- @return boolean or (nil, string): true if there were no errors +-- or nil and an error message if an invalid command was requested. +function help.command(flags, command) + if not command then + local conf = cfg.which_config() + print_banner() + print_section("NAME") + util.printout("\t"..program..[[ - ]]..program_description) + print_section("SYNOPSIS") + util.printout("\t"..program..[[ [--from= | --only-from=] [--to=] [VAR=VALUE]... [] ]]) + print_section("GENERAL OPTIONS") + util.printout([[ + These apply to all commands, as appropriate: + + --server= Fetch rocks/rockspecs from this server + (takes priority over config file) + --only-server= Fetch rocks/rockspecs from this server only + (overrides any entries in the config file) + --only-sources= Restrict downloads to paths matching the + given URL. + --tree= Which tree to operate on. + --local Use the tree in the user's home directory. + To enable it, see ']]..program..[[ help path'. + --verbose Display verbose output of commands executed. + --timeout= Timeout on network operations, in seconds. + 0 means no timeout (wait forever). + Default is ]]..tostring(cfg.connection_timeout)..[[.]]) + print_section("VARIABLES") + util.printout([[ + Variables from the "variables" table of the configuration file + can be overriden with VAR=VALUE assignments.]]) + print_section("COMMANDS") + for name, command in util.sortedpairs(commands) do + local cmd = require(command) + util.printout("", name) + util.printout("\t", cmd.help_summary) + end + print_section("CONFIGURATION") + util.printout("\tLua version: " .. cfg.lua_version) + util.printout("\tConfiguration files:") + util.printout("\t\tSystem: ".. dir.normalize(conf.system.file) .. " (" .. get_status(conf.system.ok) ..")") + if conf.user.file then + util.printout("\t\tUser : ".. dir.normalize(conf.user.file) .. " (" .. get_status(conf.user.ok) ..")\n") + else + util.printout("\t\tUser : disabled in this LuaRocks installation.\n") + end + util.printout("\tRocks trees in use: ") + for _, tree in ipairs(cfg.rocks_trees) do + if type(tree) == "string" then + util.printout("\t\t"..dir.normalize(tree)) + else + local name = tree.name and " (\""..tree.name.."\")" or "" + util.printout("\t\t"..dir.normalize(tree.root)..name) + end + end + else + command = command:gsub("-", "_") + local cmd = commands[command] and require(commands[command]) + if cmd then + local arguments = cmd.help_arguments or "" + print_banner() + print_section("NAME") + util.printout("\t"..program.." "..command.." - "..cmd.help_summary) + print_section("SYNOPSIS") + util.printout("\t"..program.." "..command.." "..arguments) + print_section("DESCRIPTION") + util.printout("",(cmd.help:gsub("\n","\n\t"):gsub("\n\t$",""))) + print_section("SEE ALSO") + util.printout("","'"..program.." help' for general options and configuration.\n") + else + return nil, "Unknown command: "..command + end + end + return true +end + +return help diff --git a/Utils/luarocks/lua/luarocks/index.lua b/Utils/luarocks/lua/luarocks/index.lua new file mode 100644 index 000000000..e1f563ef2 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/index.lua @@ -0,0 +1,186 @@ + +--- Module which builds the index.html page to be used in rocks servers. +local index = {} +package.loaded["luarocks.index"] = index + +local util = require("luarocks.util") +local fs = require("luarocks.fs") +local deps = require("luarocks.deps") +local persist = require("luarocks.persist") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") + +local ext_url_target = ' target="_blank"' + +local index_header = [[ + + + +Available rocks + + + + +

Available rocks

+

+Lua modules available from this location for use with LuaRocks: +

+ +]] + +local index_package_begin = [[ + + + +]] + +local index_footer_begin = [[ +
+

$package - $summary
+

$detailed
+$externaldependencies +latest sources $homepage | License: $license

+
+]] + +local index_package_end = [[ +
+

+manifest file +]] +local index_manifest_ver = [[ +• Lua $VER manifest file (zip) +]] +local index_footer_end = [[ +

+ + +]] + +function index.format_external_dependencies(rockspec) + if rockspec.external_dependencies then + local deplist = {} + local listed_set = {} + local plats = nil + for name, desc in util.sortedpairs(rockspec.external_dependencies) do + if name ~= "platforms" then + table.insert(deplist, name:lower()) + listed_set[name] = true + else + plats = desc + end + end + if plats then + for plat, entries in util.sortedpairs(plats) do + for name, desc in util.sortedpairs(entries) do + if not listed_set[name] then + table.insert(deplist, name:lower() .. " (on "..plat..")") + end + end + end + end + return '

External dependencies: ' .. table.concat(deplist, ', ').. '

' + else + return "" + end +end + +function index.make_index(repo) + if not fs.is_dir(repo) then + return nil, "Cannot access repository at "..repo + end + local manifest = manif.load_manifest(repo) + local out = io.open(dir.path(repo, "index.html"), "w") + + out:write(index_header) + for package, version_list in util.sortedpairs(manifest.repository) do + local latest_rockspec = nil + local output = index_package_begin + for version, data in util.sortedpairs(version_list, deps.compare_versions) do + local versions = {} + output = output..version..': ' + table.sort(data, function(a,b) return a.arch < b.arch end) + for _, item in ipairs(data) do + local file + if item.arch == 'rockspec' then + file = ("%s-%s.rockspec"):format(package, version) + if not latest_rockspec then latest_rockspec = file end + else + file = ("%s-%s.%s.rock"):format(package, version, item.arch) + end + table.insert(versions, ''..item.arch..'') + end + output = output .. table.concat(versions, ', ') .. '
' + end + output = output .. index_package_end + if latest_rockspec then + local rockspec = persist.load_into_table(dir.path(repo, latest_rockspec)) + local descript = rockspec.description or {} + local vars = { + anchor = package, + package = rockspec.package, + original = rockspec.source.url, + summary = descript.summary or "", + detailed = descript.detailed or "", + license = descript.license or "N/A", + homepage = descript.homepage and ('| project homepage') or "", + externaldependencies = index.format_external_dependencies(rockspec) + } + vars.detailed = vars.detailed:gsub("\n\n", "

"):gsub("%s+", " ") + vars.detailed = vars.detailed:gsub("(https?://[a-zA-Z0-9%.%%-_%+%[%]=%?&/$@;:]+)", '%1') + output = output:gsub("$(%w+)", vars) + else + output = output:gsub("$anchor", package) + output = output:gsub("$package", package) + output = output:gsub("$(%w+)", "") + end + out:write(output) + end + out:write(index_footer_begin) + for ver in util.lua_versions() do + out:write((index_manifest_ver:gsub("$VER", ver))) + end + out:write(index_footer_end) + out:close() +end + +return index diff --git a/Utils/luarocks/lua/luarocks/install.lua b/Utils/luarocks/lua/luarocks/install.lua new file mode 100644 index 000000000..e28c24f08 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/install.lua @@ -0,0 +1,188 @@ +--- Module implementing the LuaRocks "install" command. +-- Installs binary rocks. +local install = {} +package.loaded["luarocks.install"] = install + +local path = require("luarocks.path") +local repos = require("luarocks.repos") +local fetch = require("luarocks.fetch") +local util = require("luarocks.util") +local fs = require("luarocks.fs") +local deps = require("luarocks.deps") +local manif = require("luarocks.manif") +local remove = require("luarocks.remove") +local cfg = require("luarocks.cfg") + +util.add_run_function(install) +install.help_summary = "Install a rock." + +install.help_arguments = "{| []}" + +install.help = [[ +Argument may be the name of a rock to be fetched from a repository +or a filename of a locally available rock. + +--keep Do not remove previously installed versions of the + rock after installing a new one. This behavior can + be made permanent by setting keep_other_versions=true + in the configuration file. + +--only-deps Installs only the dependencies of the rock. +]]..util.deps_mode_help() + + +--- Install a binary rock. +-- @param rock_file string: local or remote filename of a rock. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +-- @return (string, string) or (nil, string, [string]): Name and version of +-- installed rock if succeeded or nil and an error message followed by an error code. +function install.install_binary_rock(rock_file, deps_mode) + assert(type(rock_file) == "string") + + local name, version, arch = path.parse_name(rock_file) + if not name then + return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." + end + + if arch ~= "all" and arch ~= cfg.arch then + return nil, "Incompatible architecture "..arch, "arch" + end + if repos.is_installed(name, version) then + repos.delete_version(name, version, deps_mode) + end + + local rollback = util.schedule_function(function() + fs.delete(path.install_dir(name, version)) + fs.remove_dir_if_empty(path.versions_dir(name)) + end) + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) + if not ok then return nil, err, errcode end + + local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) + if err then + return nil, "Failed loading rockspec for installed package: "..err, errcode + end + + if deps_mode == "none" then + util.printerr("Warning: skipping dependency checks.") + else + ok, err, errcode = deps.check_external_deps(rockspec, "install") + if err then return nil, err, errcode end + end + + -- For compatibility with .rock files built with LuaRocks 1 + if not fs.exists(path.rock_manifest_file(name, version)) then + ok, err = manif.make_rock_manifest(name, version) + if err then return nil, err end + end + + if deps_mode ~= "none" then + ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) + if err then return nil, err, errcode end + end + + ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode) + if err then return nil, err end + + util.remove_scheduled_function(rollback) + rollback = util.schedule_function(function() + repos.delete_version(name, version, deps_mode) + end) + + ok, err = repos.run_hook(rockspec, "post_install") + if err then return nil, err end + + util.announce_install(rockspec) + util.remove_scheduled_function(rollback) + return name, version +end + +--- Installs the dependencies of a binary rock. +-- @param rock_file string: local or remote filename of a rock. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +-- @return (string, string) or (nil, string, [string]): Name and version of +-- the rock whose dependencies were installed if succeeded or nil and an error message +-- followed by an error code. +function install.install_binary_rock_deps(rock_file, deps_mode) + assert(type(rock_file) == "string") + + local name, version, arch = path.parse_name(rock_file) + if not name then + return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." + end + + if arch ~= "all" and arch ~= cfg.arch then + return nil, "Incompatible architecture "..arch, "arch" + end + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) + if not ok then return nil, err, errcode end + + local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) + if err then + return nil, "Failed loading rockspec for installed package: "..err, errcode + end + + ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) + if err then return nil, err, errcode end + + util.printout() + util.printout("Successfully installed dependencies for " ..name.." "..version) + + return name, version +end + +--- Driver function for the "install" command. +-- @param name string: name of a binary rock. If an URL or pathname +-- to a binary rock is given, fetches and installs it. If a rockspec or a +-- source rock is given, forwards the request to the "build" command. +-- If a package name is given, forwards the request to "search" and, +-- if returned a result, installs the matching rock. +-- @param version string: When passing a package name, a version number +-- may also be given. +-- @return boolean or (nil, string, exitcode): True if installation was +-- successful, nil and an error message otherwise. exitcode is optionally returned. +function install.command(flags, name, version) + if type(name) ~= "string" then + return nil, "Argument missing. "..util.see_help("install") + end + + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end + + if name:match("%.rockspec$") or name:match("%.src%.rock$") then + local build = require("luarocks.build") + return build.command(flags, name) + elseif name:match("%.rock$") then + if flags["only-deps"] then + ok, err = install.install_binary_rock_deps(name, deps.get_deps_mode(flags)) + else + ok, err = install.install_binary_rock(name, deps.get_deps_mode(flags)) + end + if not ok then return nil, err end + name, version = ok, err + + if (not flags["only-deps"]) and (not flags["keep"]) and not cfg.keep_other_versions then + local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) + if not ok then util.printerr(err) end + end + + manif.check_dependencies(nil, deps.get_deps_mode(flags)) + return name, version + else + local search = require("luarocks.search") + local url, err = search.find_suitable_rock(search.make_query(name:lower(), version)) + if not url then + return nil, err + end + util.printout("Installing "..url) + return install.command(flags, url) + end +end + +return install diff --git a/Utils/luarocks/lua/luarocks/lint.lua b/Utils/luarocks/lua/luarocks/lint.lua new file mode 100644 index 000000000..0fd81a203 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/lint.lua @@ -0,0 +1,55 @@ + +--- Module implementing the LuaRocks "lint" command. +-- Utility function that checks syntax of the rockspec. +local lint = {} +package.loaded["luarocks.lint"] = lint + +local util = require("luarocks.util") +local download = require("luarocks.download") +local fetch = require("luarocks.fetch") + +util.add_run_function(lint) +lint.help_summary = "Check syntax of a rockspec." +lint.help_arguments = "" +lint.help = [[ +This is a utility function that checks the syntax of a rockspec. + +It returns success or failure if the text of a rockspec is +syntactically correct. +]] + +function lint.command(flags, input) + if not input then + return nil, "Argument missing. "..util.see_help("lint") + end + + local filename = input + if not input:match(".rockspec$") then + local err + filename, err = download.download("rockspec", input:lower()) + if not filename then + return nil, err + end + end + + local rs, err = fetch.load_local_rockspec(filename) + if not rs then + return nil, "Failed loading rockspec: "..err + end + + local ok = true + + -- This should have been done in the type checker, + -- but it would break compatibility of other commands. + -- Making 'lint' alone be stricter shouldn't be a problem, + -- because extra-strict checks is what lint-type commands + -- are all about. + if not rs.description.license then + util.printerr("Rockspec has no license field.") + ok = false + end + + return ok, ok or filename.." failed consistency checks." +end + +return lint diff --git a/Utils/luarocks/lua/luarocks/list.lua b/Utils/luarocks/lua/luarocks/list.lua new file mode 100644 index 000000000..c65e058f9 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/list.lua @@ -0,0 +1,97 @@ + +--- Module implementing the LuaRocks "list" command. +-- Lists currently installed rocks. +local list = {} +package.loaded["luarocks.list"] = list + +local search = require("luarocks.search") +local deps = require("luarocks.deps") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local path = require("luarocks.path") + +util.add_run_function(list) +list.help_summary = "List currently installed rocks." +list.help_arguments = "[--porcelain] " +list.help = [[ + is a substring of a rock name to filter by. + +--outdated List only rocks for which there is a + higher version available in the rocks server. + +--porcelain Produce machine-friendly output. +]] + +local function check_outdated(trees, query) + local results_installed = {} + for _, tree in ipairs(trees) do + search.manifest_search(results_installed, path.rocks_dir(tree), query) + end + local outdated = {} + for name, versions in util.sortedpairs(results_installed) do + versions = util.keys(versions) + table.sort(versions, deps.compare_versions) + local latest_installed = versions[1] + + local query_available = search.make_query(name:lower()) + query.exact_name = true + local results_available, err = search.search_repos(query_available) + + if results_available[name] then + local available_versions = util.keys(results_available[name]) + table.sort(available_versions, deps.compare_versions) + local latest_available = available_versions[1] + local latest_available_repo = results_available[name][latest_available][1].repo + + if deps.compare_versions(latest_available, latest_installed) then + table.insert(outdated, { name = name, installed = latest_installed, available = latest_available, repo = latest_available_repo }) + end + end + end + return outdated +end + +local function list_outdated(trees, query, porcelain) + util.title("Outdated rocks:", porcelain) + local outdated = check_outdated(trees, query) + for _, item in ipairs(outdated) do + if porcelain then + util.printout(item.name, item.installed, item.available, item.repo) + else + util.printout(item.name) + util.printout(" "..item.installed.." < "..item.available.." at "..item.repo) + util.printout() + end + end + return true +end + +--- Driver function for "list" command. +-- @param filter string or nil: A substring of a rock name to filter by. +-- @param version string or nil: a version may also be passed. +-- @return boolean: True if succeeded, nil on errors. +function list.command(flags, filter, version) + local query = search.make_query(filter and filter:lower() or "", version) + query.exact_name = false + local trees = cfg.rocks_trees + if flags["tree"] then + trees = { flags["tree"] } + end + + if flags["outdated"] then + return list_outdated(trees, query, flags["porcelain"]) + end + + local results = {} + for _, tree in ipairs(trees) do + local ok, err, errcode = search.manifest_search(results, path.rocks_dir(tree), query) + if not ok and errcode ~= "open" then + util.warning(err) + end + end + util.title("Installed rocks:", flags["porcelain"]) + search.print_results(results, flags["porcelain"]) + return true +end + +return list diff --git a/Utils/luarocks/lua/luarocks/loader.lua b/Utils/luarocks/lua/luarocks/loader.lua new file mode 100644 index 000000000..874bc10c3 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/loader.lua @@ -0,0 +1,249 @@ + +--- A module which installs a Lua package loader that is LuaRocks-aware. +-- This loader uses dependency information from the LuaRocks tree to load +-- correct versions of modules. It does this by constructing a "context" +-- table in the environment, which records which versions of packages were +-- used to load previous modules, so that the loader chooses versions +-- that are declared to be compatible with the ones loaded earlier. +local loaders = package.loaders or package.searchers +local package, require, ipairs, table, type, next, tostring, error = + package, require, ipairs, table, type, next, tostring, error +local unpack = unpack or table.unpack + +--module("luarocks.loader") +local loader = {} +package.loaded["luarocks.loader"] = loader + +local cfg = require("luarocks.cfg") +cfg.init_package_paths() + +local path = require("luarocks.path") +local manif_core = require("luarocks.manif_core") +local deps = require("luarocks.deps") +local util = require("luarocks.util") + +-- Workaround for wrappers produced by older versions of LuaRocks +local temporary_global = false +if luarocks then + -- The site_config.lua file generated by old versions uses module(), + -- so it produces a global `luarocks` table. Since we have the table, + -- add the `loader` field to make the old wrappers happy. + luarocks.loader = loader +else + -- When a new version is installed on top of an old version, + -- site_config.lua may be replaced, and then it no longer creates + -- a global. + -- Detect when being called via -lluarocks.loader; this is + -- most likely a wrapper. + local info = debug.getinfo(2, "nS") + if info.what == "C" and not info.name then + luarocks = { loader = loader } + temporary_global = true + -- For the other half of this hack, + -- see the next use of `temporary_global` below. + end +end + +loader.context = {} + +-- Contains a table when rocks trees are loaded, +-- or 'false' to indicate rocks trees failed to load. +-- 'nil' indicates rocks trees were not attempted to be loaded yet. +loader.rocks_trees = nil + +local function load_rocks_trees() + local any_ok = false + local trees = {} + for _, tree in ipairs(cfg.rocks_trees) do + local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree)) + if manifest then + any_ok = true + table.insert(trees, {tree=tree, manifest=manifest}) + end + end + if not any_ok then + loader.rocks_trees = false + return false + end + loader.rocks_trees = trees + return true +end + +--- Process the dependencies of a package to determine its dependency +-- chain for loading modules. +-- @param name string: The name of an installed rock. +-- @param version string: The version of the rock, in string format +function loader.add_context(name, version) + -- assert(type(name) == "string") + -- assert(type(version) == "string") + + if temporary_global then + -- The first thing a wrapper does is to call add_context. + -- From here on, it's safe to clean the global environment. + luarocks = nil + temporary_global = false + end + + if loader.context[name] then + return + end + loader.context[name] = version + + if not loader.rocks_trees and not load_rocks_trees() then + return nil + end + + for _, tree in ipairs(loader.rocks_trees) do + local manifest = tree.manifest + + local pkgdeps + if manifest.dependencies and manifest.dependencies[name] then + pkgdeps = manifest.dependencies[name][version] + end + if not pkgdeps then + return nil + end + for _, dep in ipairs(pkgdeps) do + local pkg, constraints = dep.name, dep.constraints + + for _, tree in ipairs(loader.rocks_trees) do + local entries = tree.manifest.repository[pkg] + if entries then + for version, pkgs in util.sortedpairs(entries, deps.compare_versions) do + if (not constraints) or deps.match_constraints(deps.parse_version(version), constraints) then + loader.add_context(pkg, version) + end + end + end + end + end + end +end + +--- Internal sorting function. +-- @param a table: A provider table. +-- @param b table: Another provider table. +-- @return boolean: True if the version of a is greater than that of b. +local function sort_versions(a,b) + return a.version > b.version +end + +--- Request module to be loaded through other loaders, +-- once the proper name of the module has been determined. +-- For example, in case the module "socket.core" has been requested +-- to the LuaRocks loader and it determined based on context that +-- the version 2.0.2 needs to be loaded and it is not the current +-- version, the module requested for the other loaders will be +-- "socket.core_2_0_2". +-- @param module The module name requested by the user, such as "socket.core" +-- @param name The rock name, such as "luasocket" +-- @param version The rock version, such as "2.0.2-1" +-- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". +-- @return table or (nil, string): The module table as returned by some other loader, +-- or nil followed by an error message if no other loader managed to load the module. +local function call_other_loaders(module, name, version, module_name) + for i, a_loader in ipairs(loaders) do + if a_loader ~= loader.luarocks_loader then + local results = { a_loader(module_name) } + if type(results[1]) == "function" then + return unpack(results) + end + end + end + return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version +end + +--- Search for a module in the rocks trees +-- @param module string: module name (eg. "socket.core") +-- @param filter_file_name function(string, string, string, string, number): +-- a function that takes the module file name (eg "socket/core.so"), the rock name +-- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree +-- (eg "/usr/local"), and the numeric index of the matching entry, so the +-- filter function can know if the matching module was the first entry or not. +-- @return string, string, string, (string or table): +-- * name of the rock containing the module (eg. "luasocket") +-- * version of the rock (eg. "2.0.2-1") +-- * return value of filter_file_name +-- * tree of the module (string or table in `rocks_trees` format) +local function select_module(module, filter_file_name) + --assert(type(module) == "string") + --assert(type(filter_module_name) == "function") + + if not loader.rocks_trees and not load_rocks_trees() then + return nil + end + + local providers = {} + for _, tree in ipairs(loader.rocks_trees) do + local entries = tree.manifest.modules[module] + if entries then + for i, entry in ipairs(entries) do + local name, version = entry:match("^([^/]*)/(.*)$") + local file_name = tree.manifest.repository[name][version][1].modules[module] + if type(file_name) ~= "string" then + error("Invalid data in manifest file for module "..tostring(module).." (invalid data for "..tostring(name).." "..tostring(version)..")") + end + file_name = filter_file_name(file_name, name, version, tree.tree, i) + if loader.context[name] == version then + return name, version, file_name + end + version = deps.parse_version(version) + table.insert(providers, {name = name, version = version, module_name = file_name, tree = tree}) + end + end + end + + if next(providers) then + table.sort(providers, sort_versions) + local first = providers[1] + return first.name, first.version.string, first.module_name, first.tree + end +end + +--- Search for a module +-- @param module string: module name (eg. "socket.core") +-- @return string, string, string, (string or table): +-- * name of the rock containing the module (eg. "luasocket") +-- * version of the rock (eg. "2.0.2-1") +-- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). +-- * tree of the module (string or table in `rocks_trees` format) +local function pick_module(module) + return + select_module(module, function(file_name, name, version, tree, i) + if i > 1 then + file_name = path.versioned_name(file_name, "", name, version) + end + return path.path_to_module(file_name) + end) +end + +--- Return the pathname of the file that would be loaded for a module. +-- @param module string: module name (eg. "socket.core") +-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") +function loader.which(module) + local _, _, file_name = select_module(module, path.which_i) + return file_name +end + +--- Package loader for LuaRocks support. +-- A module is searched in installed rocks that match the +-- current LuaRocks context. If module is not part of the +-- context, or if a context has not yet been set, the module +-- in the package with the highest version is used. +-- @param module string: The module name, like in plain require(). +-- @return table: The module table (typically), like in plain +-- require(). See require() +-- in the Lua reference manual for details. +function loader.luarocks_loader(module) + local name, version, module_name = pick_module(module) + if not name then + return "No LuaRocks module found for "..module + else + loader.add_context(name, version) + return call_other_loaders(module, name, version, module_name) + end +end + +table.insert(loaders, 1, loader.luarocks_loader) + +return loader diff --git a/Utils/luarocks/lua/luarocks/make.lua b/Utils/luarocks/lua/luarocks/make.lua new file mode 100644 index 000000000..15167c1eb --- /dev/null +++ b/Utils/luarocks/lua/luarocks/make.lua @@ -0,0 +1,92 @@ + +--- Module implementing the LuaRocks "make" command. +-- Builds sources in the current directory, but unlike "build", +-- it does not fetch sources, etc., assuming everything is +-- available in the current directory. +local make = {} +package.loaded["luarocks.make"] = make + +local build = require("luarocks.build") +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local fetch = require("luarocks.fetch") +local pack = require("luarocks.pack") +local remove = require("luarocks.remove") +local deps = require("luarocks.deps") +local manif = require("luarocks.manif") + +util.add_run_function(make) +make.help_summary = "Compile package in current directory using a rockspec." +make.help_arguments = "[--pack-binary-rock] []" +make.help = [[ +Builds sources in the current directory, but unlike "build", +it does not fetch sources, etc., assuming everything is +available in the current directory. If no argument is given, +it looks for a rockspec in the current directory and in "rockspec/" +and "rockspecs/" subdirectories, picking the rockspec with newest version +or without version name. If rockspecs for different rocks are found +or there are several rockspecs without version, you must specify which to use, +through the command-line. + +This command is useful as a tool for debugging rockspecs. +To install rocks, you'll normally want to use the "install" and +"build" commands. See the help on those for details. + +--pack-binary-rock Do not install rock. Instead, produce a .rock file + with the contents of compilation in the current + directory. + +--keep Do not remove previously installed versions of the + rock after installing a new one. This behavior can + be made permanent by setting keep_other_versions=true + in the configuration file. + +--branch= Override the `source.branch` field in the loaded + rockspec. Allows to specify a different branch to + fetch. Particularly for SCM rocks. + +]] + +--- Driver function for "make" command. +-- @param name string: A local rockspec. +-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an +-- error message otherwise. exitcode is optionally returned. +function make.command(flags, rockspec) + assert(type(rockspec) == "string" or not rockspec) + + if not rockspec then + local err + rockspec, err = util.get_default_rockspec() + if not rockspec then + return nil, err + end + end + if not rockspec:match("rockspec$") then + return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make") + end + + if flags["pack-binary-rock"] then + local rspec, err, errcode = fetch.load_rockspec(rockspec) + if not rspec then + return nil, err + end + return pack.pack_binary_rock(rspec.name, rspec.version, build.build_rockspec, rockspec, false, true, deps.get_deps_mode(flags)) + else + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end + ok, err = build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) + if not ok then return nil, err end + local name, version = ok, err + + if (not flags["keep"]) and not cfg.keep_other_versions then + local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) + if not ok then util.printerr(err) end + end + + manif.check_dependencies(nil, deps.get_deps_mode(flags)) + return name, version + end +end + +return make diff --git a/Utils/luarocks/lua/luarocks/make_manifest.lua b/Utils/luarocks/lua/luarocks/make_manifest.lua new file mode 100644 index 000000000..c39c2939f --- /dev/null +++ b/Utils/luarocks/lua/luarocks/make_manifest.lua @@ -0,0 +1,53 @@ + +--- Module implementing the luarocks-admin "make_manifest" command. +-- Compile a manifest file for a repository. +local make_manifest = {} +package.loaded["luarocks.make_manifest"] = make_manifest + +local manif = require("luarocks.manif") +local index = require("luarocks.index") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local deps = require("luarocks.deps") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +util.add_run_function(make_manifest) +make_manifest.help_summary = "Compile a manifest file for a repository." + +make_manifest.help = [[ +, if given, is a local repository pathname. + +--local-tree If given, do not write versioned versions of the manifest file. + Use this when rebuilding the manifest of a local rocks tree. +]] + +--- Driver function for "make_manifest" command. +-- @param repo string or nil: Pathname of a local repository. If not given, +-- the default local repository configured as cfg.rocks_dir is used. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function make_manifest.command(flags, repo) + assert(type(repo) == "string" or not repo) + repo = repo or cfg.rocks_dir + + util.printout("Making manifest for "..repo) + + if repo:match("/lib/luarocks") and not flags["local-tree"] then + util.warning("This looks like a local rocks tree, but you did not pass --local-tree.") + end + + local ok, err = manif.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"]) + if ok and not flags["local-tree"] then + util.printout("Generating index.html for "..repo) + index.make_index(repo) + end + if flags["local-tree"] then + for luaver in util.lua_versions() do + fs.delete(dir.path(repo, "manifest-"..luaver)) + end + end + return ok, err +end + +return make_manifest diff --git a/Utils/luarocks/lua/luarocks/manif.lua b/Utils/luarocks/lua/luarocks/manif.lua new file mode 100644 index 000000000..88a13f107 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/manif.lua @@ -0,0 +1,628 @@ +--- Module for handling manifest files and tables. +-- Manifest files describe the contents of a LuaRocks tree or server. +-- They are loaded into manifest tables, which are then used for +-- performing searches, matching dependencies, etc. +local manif = {} +package.loaded["luarocks.manif"] = manif + +local manif_core = require("luarocks.manif_core") +local persist = require("luarocks.persist") +local fetch = require("luarocks.fetch") +local dir = require("luarocks.dir") +local fs = require("luarocks.fs") +local search = require("luarocks.search") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local path = require("luarocks.path") +local repos = require("luarocks.repos") +local deps = require("luarocks.deps") + +manif.rock_manifest_cache = {} + +--- Commit a table to disk in given local path. +-- @param where string: The directory where the table should be saved. +-- @param name string: The filename. +-- @param tbl table: The table to be saved. +-- @return boolean or (nil, string): true if successful, or nil and a +-- message in case of errors. +local function save_table(where, name, tbl) + assert(type(where) == "string") + assert(type(name) == "string") + assert(type(tbl) == "table") + + local filename = dir.path(where, name) + local ok, err = persist.save_from_table(filename..".tmp", tbl) + if ok then + ok, err = fs.replace_file(filename, filename..".tmp") + end + return ok, err +end + +function manif.load_rock_manifest(name, version, root) + assert(type(name) == "string") + assert(type(version) == "string") + + local name_version = name.."/"..version + if manif.rock_manifest_cache[name_version] then + return manif.rock_manifest_cache[name_version].rock_manifest + end + local pathname = path.rock_manifest_file(name, version, root) + local rock_manifest = persist.load_into_table(pathname) + if not rock_manifest then return nil end + manif.rock_manifest_cache[name_version] = rock_manifest + return rock_manifest.rock_manifest +end + +function manif.make_rock_manifest(name, version) + local install_dir = path.install_dir(name, version) + local tree = {} + for _, file in ipairs(fs.find(install_dir)) do + local full_path = dir.path(install_dir, file) + local walk = tree + local last + local last_name + for name in file:gmatch("[^/]+") do + local next = walk[name] + if not next then + next = {} + walk[name] = next + end + last = walk + last_name = name + walk = next + end + if fs.is_file(full_path) then + local sum, err = fs.get_md5(full_path) + if not sum then + return nil, "Failed producing checksum: "..tostring(err) + end + last[last_name] = sum + end + end + local rock_manifest = { rock_manifest=tree } + manif.rock_manifest_cache[name.."/"..version] = rock_manifest + save_table(install_dir, "rock_manifest", rock_manifest ) +end + +local function fetch_manifest_from(repo_url, filename) + local url = dir.path(repo_url, filename) + local name = repo_url:gsub("[/:]","_") + local cache_dir = dir.path(cfg.local_cache, name) + local ok = fs.make_dir(cache_dir) + if not ok then + return nil, "Failed creating temporary cache directory "..cache_dir + end + local file, err, errcode = fetch.fetch_url(url, dir.path(cache_dir, filename), true) + if not file then + return nil, "Failed fetching manifest for "..repo_url..(err and " - "..err or ""), errcode + end + return file +end + +--- Load a local or remote manifest describing a repository. +-- All functions that use manifest tables assume they were obtained +-- through either this function or load_local_manifest. +-- @param repo_url string: URL or pathname for the repository. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @return table or (nil, string, [string]): A table representing the manifest, +-- or nil followed by an error message and an optional error code. +function manif.load_manifest(repo_url, lua_version) + assert(type(repo_url) == "string") + assert(type(lua_version) == "string" or not lua_version) + lua_version = lua_version or cfg.lua_version + + local cached_manifest = manif_core.get_cached_manifest(repo_url, lua_version) + if cached_manifest then + return cached_manifest + end + + local filenames = { + "manifest-"..lua_version..".zip", + "manifest-"..lua_version, + "manifest", + } + + local protocol, repodir = dir.split_url(repo_url) + local pathname + if protocol == "file" then + for _, filename in ipairs(filenames) do + pathname = dir.path(repodir, filename) + if fs.exists(pathname) then + break + end + end + else + local err, errcode + for _, filename in ipairs(filenames) do + pathname, err, errcode = fetch_manifest_from(repo_url, filename) + if pathname then + break + end + end + if not pathname then + return nil, err, errcode + end + end + if pathname:match(".*%.zip$") then + pathname = fs.absolute_name(pathname) + local dir = dir.dir_name(pathname) + fs.change_dir(dir) + local nozip = pathname:match("(.*)%.zip$") + fs.delete(nozip) + local ok = fs.unzip(pathname) + fs.pop_dir() + if not ok then + fs.delete(pathname) + fs.delete(pathname..".timestamp") + return nil, "Failed extracting manifest file" + end + pathname = nozip + end + return manif_core.manifest_loader(pathname, repo_url, lua_version) +end + +--- Update storage table to account for items provided by a package. +-- @param storage table: a table storing items in the following format: +-- keys are item names and values are arrays of packages providing each item, +-- where a package is specified as string `name/version`. +-- @param items table: a table mapping item names to paths. +-- @param name string: package name. +-- @param version string: package version. +local function store_package_items(storage, name, version, items) + assert(type(storage) == "table") + assert(type(items) == "table") + assert(type(name) == "string") + assert(type(version) == "string") + + local package_identifier = name.."/"..version + + for item_name, path in pairs(items) do + if not storage[item_name] then + storage[item_name] = {} + end + + table.insert(storage[item_name], package_identifier) + end +end + +--- Update storage table removing items provided by a package. +-- @param storage table: a table storing items in the following format: +-- keys are item names and values are arrays of packages providing each item, +-- where a package is specified as string `name/version`. +-- @param items table: a table mapping item names to paths. +-- @param name string: package name. +-- @param version string: package version. +local function remove_package_items(storage, name, version, items) + assert(type(storage) == "table") + assert(type(items) == "table") + assert(type(name) == "string") + assert(type(version) == "string") + + local package_identifier = name.."/"..version + + for item_name, path in pairs(items) do + local all_identifiers = storage[item_name] + + for i, identifier in ipairs(all_identifiers) do + if identifier == package_identifier then + table.remove(all_identifiers, i) + break + end + end + + if #all_identifiers == 0 then + storage[item_name] = nil + end + end +end + +--- Sort function for ordering rock identifiers in a manifest's +-- modules table. Rocks are ordered alphabetically by name, and then +-- by version which greater first. +-- @param a string: Version to compare. +-- @param b string: Version to compare. +-- @return boolean: The comparison result, according to the +-- rule outlined above. +local function sort_pkgs(a, b) + assert(type(a) == "string") + assert(type(b) == "string") + + local na, va = a:match("(.*)/(.*)$") + local nb, vb = b:match("(.*)/(.*)$") + + return (na == nb) and deps.compare_versions(va, vb) or na < nb +end + +--- Sort items of a package matching table by version number (higher versions first). +-- @param tbl table: the package matching table: keys should be strings +-- and values arrays of strings with packages names in "name/version" format. +local function sort_package_matching_table(tbl) + assert(type(tbl) == "table") + + if next(tbl) then + for item, pkgs in pairs(tbl) do + if #pkgs > 1 then + table.sort(pkgs, sort_pkgs) + -- Remove duplicates from the sorted array. + local prev = nil + local i = 1 + while pkgs[i] do + local curr = pkgs[i] + if curr == prev then + table.remove(pkgs, i) + else + prev = curr + i = i + 1 + end + end + end + end + end +end + +--- Process the dependencies of a manifest table to determine its dependency +-- chains for loading modules. The manifest dependencies information is filled +-- and any dependency inconsistencies or missing dependencies are reported to +-- standard error. +-- @param manifest table: a manifest table. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for no trees. +local function update_dependencies(manifest, deps_mode) + assert(type(manifest) == "table") + assert(type(deps_mode) == "string") + + for pkg, versions in pairs(manifest.repository) do + for version, repositories in pairs(versions) do + for _, repo in ipairs(repositories) do + if repo.arch == "installed" then + repo.dependencies = {} + deps.scan_deps(repo.dependencies, manifest, pkg, version, deps_mode) + repo.dependencies[pkg] = nil + end + end + end + end +end + +--- Filter manifest table by Lua version, removing rockspecs whose Lua version +-- does not match. +-- @param manifest table: a manifest table. +-- @param lua_version string or nil: filter by Lua version +-- @param repodir string: directory of repository being scanned +-- @param cache table: temporary rockspec cache table +local function filter_by_lua_version(manifest, lua_version, repodir, cache) + assert(type(manifest) == "table") + assert(type(repodir) == "string") + assert((not cache) or type(cache) == "table") + + cache = cache or {} + lua_version = deps.parse_version(lua_version) + for pkg, versions in pairs(manifest.repository) do + local to_remove = {} + for version, repositories in pairs(versions) do + for _, repo in ipairs(repositories) do + if repo.arch == "rockspec" then + local pathname = dir.path(repodir, pkg.."-"..version..".rockspec") + local rockspec, err = cache[pathname] + if not rockspec then + rockspec, err = fetch.load_local_rockspec(pathname, true) + end + if rockspec then + cache[pathname] = rockspec + for _, dep in ipairs(rockspec.dependencies) do + if dep.name == "lua" then + if not deps.match_constraints(lua_version, dep.constraints) then + table.insert(to_remove, version) + end + break + end + end + else + util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err) + end + end + end + end + if next(to_remove) then + for _, incompat in ipairs(to_remove) do + versions[incompat] = nil + end + if not next(versions) then + manifest.repository[pkg] = nil + end + end + end +end + +--- Store search results in a manifest table. +-- @param results table: The search results as returned by search.disk_search. +-- @param manifest table: A manifest table (must contain repository, modules, commands tables). +-- It will be altered to include the search results. +-- @return boolean or (nil, string): true in case of success, or nil followed by an error message. +local function store_results(results, manifest) + assert(type(results) == "table") + assert(type(manifest) == "table") + + for name, versions in pairs(results) do + local pkgtable = manifest.repository[name] or {} + for version, entries in pairs(versions) do + local versiontable = {} + for _, entry in ipairs(entries) do + local entrytable = {} + entrytable.arch = entry.arch + if entry.arch == "installed" then + local rock_manifest = manif.load_rock_manifest(name, version) + if not rock_manifest then + return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?" + end + + entrytable.modules = repos.package_modules(name, version) + store_package_items(manifest.modules, name, version, entrytable.modules) + entrytable.commands = repos.package_commands(name, version) + store_package_items(manifest.commands, name, version, entrytable.commands) + end + table.insert(versiontable, entrytable) + end + pkgtable[version] = versiontable + end + manifest.repository[name] = pkgtable + end + sort_package_matching_table(manifest.modules) + sort_package_matching_table(manifest.commands) + return true +end + +--- Scan a LuaRocks repository and output a manifest file. +-- A file called 'manifest' will be written in the root of the given +-- repository directory. +-- @param repo A local repository directory. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for the default dependency mode from the configuration. +-- @param remote boolean: 'true' if making a manifest for a rocks server. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function manif.make_manifest(repo, deps_mode, remote) + assert(type(repo) == "string") + assert(type(deps_mode) == "string") + + if deps_mode == "none" then deps_mode = cfg.deps_mode end + + if not fs.is_dir(repo) then + return nil, "Cannot access repository at "..repo + end + + local query = search.make_query("") + query.exact_name = false + query.arch = "any" + local results = search.disk_search(repo, query) + local manifest = { repository = {}, modules = {}, commands = {} } + + manif_core.cache_manifest(repo, nil, manifest) + + local ok, err = store_results(results, manifest) + if not ok then return nil, err end + + if remote then + local cache = {} + for luaver in util.lua_versions() do + local vmanifest = { repository = {}, modules = {}, commands = {} } + local ok, err = store_results(results, vmanifest) + filter_by_lua_version(vmanifest, luaver, repo, cache) + save_table(repo, "manifest-"..luaver, vmanifest) + end + else + update_dependencies(manifest, deps_mode) + end + + return save_table(repo, "manifest", manifest) +end + +--- Update manifest file for a local repository +-- adding information about a version of a package installed in that repository. +-- @param name string: Name of a package from the repository. +-- @param version string: Version of a package from the repository. +-- @param repo string or nil: Pathname of a local repository. If not given, +-- the default local repository is used. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for using the default dependency mode from the configuration. +-- @return boolean or (nil, string): True if manifest was updated successfully, +-- or nil and an error message. +function manif.add_to_manifest(name, version, repo, deps_mode) + assert(type(name) == "string") + assert(type(version) == "string") + local rocks_dir = path.rocks_dir(repo or cfg.root_dir) + assert(type(deps_mode) == "string") + + if deps_mode == "none" then deps_mode = cfg.deps_mode end + + local manifest, err = manif_core.load_local_manifest(rocks_dir) + if not manifest then + util.printerr("No existing manifest. Attempting to rebuild...") + -- Manifest built by `manif.make_manifest` should already + -- include information about given name and version, + -- no need to update it. + return manif.make_manifest(rocks_dir, deps_mode) + end + + local results = {[name] = {[version] = {{arch = "installed", repo = rocks_dir}}}} + + local ok, err = store_results(results, manifest) + if not ok then return nil, err end + + update_dependencies(manifest, deps_mode) + return save_table(rocks_dir, "manifest", manifest) +end + +--- Update manifest file for a local repository +-- removing information about a version of a package. +-- @param name string: Name of a package removed from the repository. +-- @param version string: Version of a package removed from the repository. +-- @param repo string or nil: Pathname of a local repository. If not given, +-- the default local repository is used. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for using the default dependency mode from the configuration. +-- @return boolean or (nil, string): True if manifest was updated successfully, +-- or nil and an error message. +function manif.remove_from_manifest(name, version, repo, deps_mode) + assert(type(name) == "string") + assert(type(version) == "string") + local rocks_dir = path.rocks_dir(repo or cfg.root_dir) + assert(type(deps_mode) == "string") + + if deps_mode == "none" then deps_mode = cfg.deps_mode end + + local manifest, err = manif_core.load_local_manifest(rocks_dir) + if not manifest then + util.printerr("No existing manifest. Attempting to rebuild...") + -- Manifest built by `manif.make_manifest` should already + -- include up-to-date information, no need to update it. + return manif.make_manifest(rocks_dir, deps_mode) + end + + local package_entry = manifest.repository[name] + + local version_entry = package_entry[version][1] + remove_package_items(manifest.modules, name, version, version_entry.modules) + remove_package_items(manifest.commands, name, version, version_entry.commands) + + package_entry[version] = nil + manifest.dependencies[name][version] = nil + + if not next(package_entry) then + -- No more versions of this package. + manifest.repository[name] = nil + manifest.dependencies[name] = nil + end + + update_dependencies(manifest, deps_mode) + return save_table(rocks_dir, "manifest", manifest) +end + +--- Report missing dependencies for all rocks installed in a repository. +-- @param repo string or nil: Pathname of a local repository. If not given, +-- the default local repository is used. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for using the default dependency mode from the configuration. +function manif.check_dependencies(repo, deps_mode) + local rocks_dir = path.rocks_dir(repo or cfg.root_dir) + assert(type(deps_mode) == "string") + if deps_mode == "none" then deps_mode = cfg.deps_mode end + + local manifest = manif_core.load_local_manifest(rocks_dir) + if not manifest then + return + end + + for name, versions in util.sortedpairs(manifest.repository) do + for version, version_entries in util.sortedpairs(versions, deps.compare_versions) do + for _, entry in ipairs(version_entries) do + if entry.arch == "installed" then + if manifest.dependencies[name] and manifest.dependencies[name][version] then + deps.report_missing_dependencies(name, version, manifest.dependencies[name][version], deps_mode) + end + end + end + end + end +end + +function manif.zip_manifests() + for ver in util.lua_versions() do + local file = "manifest-"..ver + local zip = file..".zip" + fs.delete(dir.path(fs.current_dir(), zip)) + fs.zip(zip, file) + end +end + +--- Get type and name of an item (a module or a command) provided by a file. +-- @param deploy_type string: rock manifest subtree the file comes from ("bin", "lua", or "lib"). +-- @param file_path string: path to the file relatively to deploy_type subdirectory. +-- @return (string, string): item type ("module" or "command") and name. +function manif.get_provided_item(deploy_type, file_path) + assert(type(deploy_type) == "string") + assert(type(file_path) == "string") + local item_type = deploy_type == "bin" and "command" or "module" + local item_name = item_type == "command" and file_path or path.path_to_module(file_path) + return item_type, item_name +end + +local function get_providers(item_type, item_name, repo) + assert(type(item_type) == "string") + assert(type(item_name) == "string") + local rocks_dir = path.rocks_dir(repo or cfg.root_dir) + local manifest = manif_core.load_local_manifest(rocks_dir) + return manifest and manifest[item_type .. "s"][item_name] +end + +--- Given a name of a module or a command, figure out which rock name and version +-- correspond to it in the rock tree manifest. +-- @param item_type string: "module" or "command". +-- @param item_name string: module or command name. +-- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used. +-- @return (string, string) or nil: name and version of the provider rock or nil if there +-- is no provider. +function manif.get_current_provider(item_type, item_name, repo) + local providers = get_providers(item_type, item_name, repo) + if providers then + return providers[1]:match("([^/]*)/([^/]*)") + end +end + +function manif.get_next_provider(item_type, item_name, repo) + local providers = get_providers(item_type, item_name, repo) + if providers and providers[2] then + return providers[2]:match("([^/]*)/([^/]*)") + end +end + +--- Given a name of a module or a command provided by a package, figure out +-- which file provides it. +-- @param name string: package name. +-- @param version string: package version. +-- @param item_type string: "module" or "command". +-- @param item_name string: module or command name. +-- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used. +-- @return (string, string): rock manifest subtree the file comes from ("bin", "lua", or "lib") +-- and path to the providing file relatively to that subtree. +function manif.get_providing_file(name, version, item_type, item_name, repo) + local rocks_dir = path.rocks_dir(repo or cfg.root_dir) + local manifest = manif_core.load_local_manifest(rocks_dir) + + local entry_table = manifest.repository[name][version][1] + local file_path = entry_table[item_type .. "s"][item_name] + + if item_type == "command" then + return "bin", file_path + end + + -- A module can be in "lua" or "lib". Decide based on extension first: + -- most likely Lua modules are in "lua/" and C modules are in "lib/". + if file_path:match("%." .. cfg.lua_extension .. "$") then + return "lua", file_path + elseif file_path:match("%." .. cfg.lib_extension .. "$") then + return "lib", file_path + end + + -- Fallback to rock manifest scanning. + local rock_manifest = manif.load_rock_manifest(name, version) + local subtree = rock_manifest.lib + + for path_part in file_path:gmatch("[^/]+") do + if type(subtree) == "table" then + subtree = subtree[path_part] + else + -- Assume it's in "lua/" if it's not in "lib/". + return "lua", file_path + end + end + + return type(subtree) == "string" and "lib" or "lua", file_path +end + +return manif diff --git a/Utils/luarocks/lua/luarocks/manif_core.lua b/Utils/luarocks/lua/luarocks/manif_core.lua new file mode 100644 index 000000000..82e7ea4de --- /dev/null +++ b/Utils/luarocks/lua/luarocks/manif_core.lua @@ -0,0 +1,106 @@ + +--- Core functions for querying manifest files. +-- This module requires no specific 'fs' functionality. +local manif_core = {} +package.loaded["luarocks.manif_core"] = manif_core + +local persist = require("luarocks.persist") +local type_check = require("luarocks.type_check") +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") +local path = require("luarocks.path") + +-- Table with repository identifiers as keys and tables mapping +-- Lua versions to cached loaded manifests as values. +local manifest_cache = {} + +--- Cache a loaded manifest. +-- @param repo_url string: The repository identifier. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @param manifest table: the manifest to be cached. +function manif_core.cache_manifest(repo_url, lua_version, manifest) + lua_version = lua_version or cfg.lua_version + manifest_cache[repo_url] = manifest_cache[repo_url] or {} + manifest_cache[repo_url][lua_version] = manifest +end + +--- Attempt to get cached loaded manifest. +-- @param repo_url string: The repository identifier. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @return table or nil: loaded manifest or nil if cache is empty. +function manif_core.get_cached_manifest(repo_url, lua_version) + lua_version = lua_version or cfg.lua_version + return manifest_cache[repo_url] and manifest_cache[repo_url][lua_version] +end + +--- Back-end function that actually loads the manifest +-- and stores it in the manifest cache. +-- @param file string: The local filename of the manifest file. +-- @param repo_url string: The repository identifier. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @param quick boolean: If given, skips type checking. +-- @return table or (nil, string, string): the manifest or nil, +-- error message and error code ("open", "load", "run" or "type"). +function manif_core.manifest_loader(file, repo_url, lua_version, quick) + local manifest, err, errcode = persist.load_into_table(file) + if not manifest then + return nil, "Failed loading manifest for "..repo_url..": "..err, errcode + end + local globals = err + if not quick then + local ok, err = type_check.type_check_manifest(manifest, globals) + if not ok then + return nil, "Error checking manifest: "..err, "type" + end + end + + manif_core.cache_manifest(repo_url, lua_version, manifest) + return manifest +end + +--- Load a local manifest describing a repository. +-- All functions that use manifest tables assume they were obtained +-- through either this function or load_manifest. +-- @param repo_url string: URL or pathname for the repository. +-- @return table or (nil, string, string): A table representing the manifest, +-- or nil followed by an error message and an error code, see manifest_loader. +function manif_core.load_local_manifest(repo_url) + assert(type(repo_url) == "string") + + local cached_manifest = manif_core.get_cached_manifest(repo_url) + if cached_manifest then + return cached_manifest + end + + local pathname = dir.path(repo_url, "manifest") + return manif_core.manifest_loader(pathname, repo_url, nil, true) +end + +--- Get all versions of a package listed in a manifest file. +-- @param name string: a package name. +-- @param deps_mode string: "one", to use only the currently +-- configured tree; "order" to select trees based on order +-- (use the current tree and all trees below it on the list) +-- or "all", to use all trees. +-- @return table: An array of strings listing installed +-- versions of a package. +function manif_core.get_versions(name, deps_mode) + assert(type(name) == "string") + assert(type(deps_mode) == "string") + + local version_set = {} + path.map_trees(deps_mode, function(tree) + local manifest = manif_core.load_local_manifest(path.rocks_dir(tree)) + + if manifest and manifest.repository[name] then + for version in pairs(manifest.repository[name]) do + version_set[version] = true + end + end + end) + + return util.keys(version_set) +end + +return manif_core diff --git a/Utils/luarocks/lua/luarocks/new_version.lua b/Utils/luarocks/lua/luarocks/new_version.lua new file mode 100644 index 000000000..91f7607c3 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/new_version.lua @@ -0,0 +1,200 @@ + +--- Module implementing the LuaRocks "new_version" command. +-- Utility function that writes a new rockspec, updating data from a previous one. +local new_version = {} + +local util = require("luarocks.util") +local download = require("luarocks.download") +local fetch = require("luarocks.fetch") +local persist = require("luarocks.persist") +local fs = require("luarocks.fs") +local type_check = require("luarocks.type_check") + +util.add_run_function(new_version) +new_version.help_summary = "Auto-write a rockspec for a new version of a rock." +new_version.help_arguments = "[--tag=] [|] [] []" +new_version.help = [[ +This is a utility function that writes a new rockspec, updating data +from a previous one. + +If a package name is given, it downloads the latest rockspec from the +default server. If a rockspec is given, it uses it instead. If no argument +is given, it looks for a rockspec same way 'luarocks make' does. + +If the version number is not given and tag is passed using --tag, +it is used as the version, with 'v' removed from beginning. +Otherwise, it only increments the revision number of the given +(or downloaded) rockspec. + +If a URL is given, it replaces the one from the old rockspec with the +given URL. If a URL is not given and a new version is given, it tries +to guess the new URL by replacing occurrences of the version number +in the URL or tag. It also tries to download the new URL to determine +the new MD5 checksum. + +If a tag is given, it replaces the one from the old rockspec. If there is +an old tag but no new one passed, it is guessed in the same way URL is. + +WARNING: it writes the new rockspec to the current directory, +overwriting the file if it already exists. +]] + +local function try_replace(tbl, field, old, new) + if not tbl[field] then + return false + end + local old_field = tbl[field] + local new_field = tbl[field]:gsub(old, new) + if new_field ~= old_field then + util.printout("Guessing new '"..field.."' field as "..new_field) + tbl[field] = new_field + return true + end + return false +end + +-- Try to download source file using URL from a rockspec. +-- If it specified MD5, update it. +-- @return (true, false) if MD5 was not specified or it stayed same, +-- (true, true) if MD5 changed, (nil, string) on error. +local function check_url_and_update_md5(out_rs) + local file, temp_dir = fetch.fetch_url_at_temp_dir(out_rs.source.url, "luarocks-new-version-"..out_rs.package) + if not file then + util.printerr("Warning: invalid URL - "..temp_dir) + return true, false + end + + local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, out_rs.source.url, out_rs.source.dir) + if not inferred_dir then + return nil, found_dir + end + + if found_dir and found_dir ~= inferred_dir then + out_rs.source.dir = found_dir + end + + if file then + if out_rs.source.md5 then + util.printout("File successfully downloaded. Updating MD5 checksum...") + local new_md5, err = fs.get_md5(file) + if not new_md5 then + return nil, err + end + local old_md5 = out_rs.source.md5 + out_rs.source.md5 = new_md5 + return true, new_md5 ~= old_md5 + else + util.printout("File successfully downloaded.") + return true, false + end + end +end + +local function update_source_section(out_rs, url, tag, old_ver, new_ver) + if tag then + out_rs.source.tag = tag + end + if url then + out_rs.source.url = url + return check_url_and_update_md5(out_rs) + end + if new_ver == old_ver then + return true + end + if out_rs.source.dir then + try_replace(out_rs.source, "dir", old_ver, new_ver) + end + if out_rs.source.file then + try_replace(out_rs.source, "file", old_ver, new_ver) + end + if try_replace(out_rs.source, "url", old_ver, new_ver) then + return check_url_and_update_md5(out_rs) + end + if tag or try_replace(out_rs.source, "tag", old_ver, new_ver) then + return true + end + -- Couldn't replace anything significant, use the old URL. + local ok, md5_changed = check_url_and_update_md5(out_rs) + if not ok then + return nil, md5_changed + end + if md5_changed then + util.printerr("Warning: URL is the same, but MD5 has changed. Old rockspec is broken.") + end + return true +end + +function new_version.command(flags, input, version, url) + if not input then + local err + input, err = util.get_default_rockspec() + if not input then + return nil, err + end + end + assert(type(input) == "string") + + local filename, err + if input:match("rockspec$") then + filename, err = fetch.fetch_url(input) + if not filename then + return nil, err + end + else + filename, err = download.download("rockspec", input:lower()) + if not filename then + return nil, err + end + end + + local valid_rs, err = fetch.load_rockspec(filename) + if not valid_rs then + return nil, err + end + + local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$") + local new_ver, new_rev + + if flags.tag and not version then + version = flags.tag:gsub("^v", "") + end + + if version then + new_ver, new_rev = version:match("(.*)%-(%d+)$") + new_rev = tonumber(new_rev) + if not new_rev then + new_ver = version + new_rev = 1 + end + else + new_ver = old_ver + new_rev = tonumber(old_rev) + 1 + end + local new_rockver = new_ver:gsub("-", "") + + local out_rs, err = persist.load_into_table(filename) + local out_name = out_rs.package:lower() + out_rs.version = new_rockver.."-"..new_rev + + local ok, err = update_source_section(out_rs, url, flags.tag, old_ver, new_ver) + if not ok then return nil, err end + + if out_rs.build and out_rs.build.type == "module" then + out_rs.build.type = "builtin" + end + + local out_filename = out_name.."-"..new_rockver.."-"..new_rev..".rockspec" + + persist.save_from_table(out_filename, out_rs, type_check.rockspec_order) + + util.printout("Wrote "..out_filename) + + local valid_out_rs, err = fetch.load_local_rockspec(out_filename) + if not valid_out_rs then + return nil, "Failed loading generated rockspec: "..err + end + + return true +end + +return new_version diff --git a/Utils/luarocks/lua/luarocks/pack.lua b/Utils/luarocks/lua/luarocks/pack.lua new file mode 100644 index 000000000..35bbe8380 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/pack.lua @@ -0,0 +1,197 @@ + +--- Module implementing the LuaRocks "pack" command. +-- Creates a rock, packing sources or binaries. +local pack = {} +package.loaded["luarocks.pack"] = pack + +local unpack = unpack or table.unpack + +local path = require("luarocks.path") +local repos = require("luarocks.repos") +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local search = require("luarocks.search") + +util.add_run_function(pack) +pack.help_summary = "Create a rock, packing sources or binaries." +pack.help_arguments = "{| []}" +pack.help = [[ +Argument may be a rockspec file, for creating a source rock, +or the name of an installed package, for creating a binary rock. +In the latter case, the app version may be given as a second +argument. +]] + +--- Create a source rock. +-- Packages a rockspec and its required source files in a rock +-- file with the .src.rock extension, which can later be built and +-- installed with the "build" command. +-- @param rockspec_file string: An URL or pathname for a rockspec file. +-- @return string or (nil, string): The filename of the resulting +-- .src.rock file; or nil and an error message. +function pack.pack_source_rock(rockspec_file) + assert(type(rockspec_file) == "string") + + local rockspec, err = fetch.load_rockspec(rockspec_file) + if err then + return nil, "Error loading rockspec: "..err + end + rockspec_file = rockspec.local_filename + + local name_version = rockspec.name .. "-" .. rockspec.version + local rock_file = fs.absolute_name(name_version .. ".src.rock") + + local source_file, source_dir = fetch.fetch_sources(rockspec, false) + if not source_file then + return nil, source_dir + end + local ok, err = fs.change_dir(source_dir) + if not ok then return nil, err end + + fs.delete(rock_file) + fs.copy(rockspec_file, source_dir, cfg.perm_read) + if not fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) then + return nil, "Failed packing "..rock_file + end + fs.pop_dir() + + return rock_file +end + +local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir, perms) + local ok, err = fs.make_dir(pack_dir) + if not ok then return nil, err end + for file, sub in pairs(file_tree) do + local source = dir.path(deploy_dir, file) + local target = dir.path(pack_dir, file) + if type(sub) == "table" then + local ok, err = copy_back_files(name, version, sub, source, target) + if not ok then return nil, err end + else + local versioned = path.versioned_name(source, deploy_dir, name, version) + if fs.exists(versioned) then + fs.copy(versioned, target, perms) + else + fs.copy(source, target, perms) + end + end + end + return true +end + +-- @param name string: Name of package to pack. +-- @param version string or nil: A version number may also be passed. +-- @param tree string or nil: An optional tree to pick the package from. +-- @return string or (nil, string): The filename of the resulting +-- .src.rock file; or nil and an error message. +local function do_pack_binary_rock(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string" or not version) + + local repo, repo_url + name, version, repo, repo_url = search.pick_installed_rock(name, version, tree) + if not name then + return nil, version + end + + local root = path.root_dir(repo_url) + local prefix = path.install_dir(name, version, root) + if not fs.exists(prefix) then + return nil, "'"..name.." "..version.."' does not seem to be an installed rock." + end + + local rock_manifest = manif.load_rock_manifest(name, version, root) + if not rock_manifest then + return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?" + end + + local name_version = name .. "-" .. version + local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock") + + local temp_dir = fs.make_temp_dir("pack") + fs.copy_contents(prefix, temp_dir) + + local is_binary = false + if rock_manifest.lib then + local ok, err = copy_back_files(name, version, rock_manifest.lib, path.deploy_lib_dir(root), dir.path(temp_dir, "lib"), cfg.perm_exec) + if not ok then return nil, "Failed copying back files: " .. err end + is_binary = true + end + if rock_manifest.lua then + local ok, err = copy_back_files(name, version, rock_manifest.lua, path.deploy_lua_dir(root), dir.path(temp_dir, "lua"), cfg.perm_read) + if not ok then return nil, "Failed copying back files: " .. err end + end + + local ok, err = fs.change_dir(temp_dir) + if not ok then return nil, err end + if not is_binary and not repos.has_binaries(name, version) then + rock_file = rock_file:gsub("%."..cfg.arch:gsub("%-","%%-").."%.", ".all.") + end + fs.delete(rock_file) + if not fs.zip(rock_file, unpack(fs.list_dir())) then + return nil, "Failed packing "..rock_file + end + fs.pop_dir() + fs.delete(temp_dir) + return rock_file +end + +function pack.pack_binary_rock(name, version, cmd, ...) + + -- The --pack-binary-rock option for "luarocks build" basically performs + -- "luarocks build" on a temporary tree and then "luarocks pack". The + -- alternative would require refactoring parts of luarocks.build and + -- luarocks.pack, which would save a few file operations: the idea would be + -- to shave off the final deploy steps from the build phase and the initial + -- collect steps from the pack phase. + + local temp_dir, err = fs.make_temp_dir("luarocks-build-pack-"..dir.base_name(name)) + if not temp_dir then + return nil, "Failed creating temporary directory: "..err + end + util.schedule_function(fs.delete, temp_dir) + + path.use_tree(temp_dir) + local ok, err = cmd(...) + if not ok then + return nil, err + end + local rname, rversion = path.parse_name(name) + if not rname then + rname, rversion = name, version + end + return do_pack_binary_rock(rname, rversion, temp_dir) +end + +--- Driver function for the "pack" command. +-- @param arg string: may be a rockspec file, for creating a source rock, +-- or the name of an installed package, for creating a binary rock. +-- @param version string or nil: if the name of a package is given, a +-- version may also be passed. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +function pack.command(flags, arg, version) + assert(type(version) == "string" or not version) + if type(arg) ~= "string" then + return nil, "Argument missing. "..util.see_help("pack") + end + + local file, err + if arg:match(".*%.rockspec") then + file, err = pack.pack_source_rock(arg) + else + file, err = do_pack_binary_rock(arg:lower(), version, flags["tree"]) + end + if err then + return nil, err + else + util.printout("Packed: "..file) + return true + end +end + +return pack diff --git a/Utils/luarocks/lua/luarocks/path.lua b/Utils/luarocks/lua/luarocks/path.lua new file mode 100644 index 000000000..dafc64e7c --- /dev/null +++ b/Utils/luarocks/lua/luarocks/path.lua @@ -0,0 +1,388 @@ + +--- LuaRocks-specific path handling functions. +-- All paths are configured in this module, making it a single +-- point where the layout of the local installation is defined in LuaRocks. +local path = {} + +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") + +--- Infer rockspec filename from a rock filename. +-- @param rock_name string: Pathname of a rock file. +-- @return string: Filename of the rockspec, without path. +function path.rockspec_name_from_rock(rock_name) + assert(type(rock_name) == "string") + local base_name = dir.base_name(rock_name) + return base_name:match("(.*)%.[^.]*.rock") .. ".rockspec" +end + +function path.rocks_dir(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.rocks_subdir) + else + assert(type(tree) == "table") + return tree.rocks_dir or dir.path(tree.root, cfg.rocks_subdir) + end +end + +function path.root_dir(rocks_dir) + assert(type(rocks_dir) == "string") + return rocks_dir:match("(.*)" .. util.matchquote(cfg.rocks_subdir) .. ".*$") +end + +function path.rocks_tree_to_string(tree) + if type(tree) == "string" then + return tree + else + assert(type(tree) == "table") + return tree.root + end +end + +function path.deploy_bin_dir(tree) + if type(tree) == "string" then + return dir.path(tree, "bin") + else + assert(type(tree) == "table") + return tree.bin_dir or dir.path(tree.root, "bin") + end +end + +function path.deploy_lua_dir(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.lua_modules_path) + else + assert(type(tree) == "table") + return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path) + end +end + +function path.deploy_lib_dir(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.lib_modules_path) + else + assert(type(tree) == "table") + return tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path) + end +end + +function path.manifest_file(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.rocks_subdir, "manifest") + else + assert(type(tree) == "table") + return (tree.rocks_dir and dir.path(tree.rocks_dir, "manifest")) or dir.path(tree.root, cfg.rocks_subdir, "manifest") + end +end + +--- Get the directory for all versions of a package in a tree. +-- @param name string: The package name. +-- @return string: The resulting path -- does not guarantee that +-- @param tree string or nil: If given, specifies the local tree to use. +-- the package (and by extension, the path) exists. +function path.versions_dir(name, tree) + assert(type(name) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name) +end + +--- Get the local installation directory (prefix) for a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function path.install_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version) +end + +--- Get the local filename of the rockspec of an installed rock. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the file) exists. +function path.rockspec_file(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, name.."-"..version..".rockspec") +end + +--- Get the local filename of the rock_manifest file of an installed rock. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the file) exists. +function path.rock_manifest_file(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, "rock_manifest") +end + +--- Get the local installation directory for C libraries of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function path.lib_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, "lib") +end + +--- Get the local installation directory for Lua modules of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function path.lua_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, "lua") +end + +--- Get the local installation directory for documentation of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function path.doc_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, "doc") +end + +--- Get the local installation directory for configuration files of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function path.conf_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, "conf") +end + +--- Get the local installation directory for command-line scripts +-- of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function path.bin_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(path.rocks_dir(tree), name, version, "bin") +end + +--- Extract name, version and arch of a rock filename, +-- or name, version and "rockspec" from a rockspec name. +-- @param file_name string: pathname of a rock or rockspec +-- @return (string, string, string) or nil: name, version and arch +-- or nil if name could not be parsed +function path.parse_name(file_name) + assert(type(file_name) == "string") + if file_name:match("%.rock$") then + return dir.base_name(file_name):match("(.*)-([^-]+-%d+)%.([^.]+)%.rock$") + else + return dir.base_name(file_name):match("(.*)-([^-]+-%d+)%.(rockspec)") + end +end + +--- Make a rockspec or rock URL. +-- @param pathname string: Base URL or pathname. +-- @param name string: Package name. +-- @param version string: Package version. +-- @param arch string: Architecture identifier, or "rockspec" or "installed". +-- @return string: A URL or pathname following LuaRocks naming conventions. +function path.make_url(pathname, name, version, arch) + assert(type(pathname) == "string") + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(arch) == "string") + + local filename = name.."-"..version + if arch == "installed" then + filename = dir.path(name, version, filename..".rockspec") + elseif arch == "rockspec" then + filename = filename..".rockspec" + else + filename = filename.."."..arch..".rock" + end + return dir.path(pathname, filename) +end + +--- Convert a pathname to a module identifier. +-- In Unix, for example, a path "foo/bar/baz.lua" is converted to +-- "foo.bar.baz"; "bla/init.lua" returns "bla"; "foo.so" returns "foo". +-- @param file string: Pathname of module +-- @return string: The module identifier, or nil if given path is +-- not a conformant module path (the function does not check if the +-- path actually exists). +function path.path_to_module(file) + assert(type(file) == "string") + + local name = file:match("(.*)%."..cfg.lua_extension.."$") + if name then + name = name:gsub(dir.separator, ".") + local init = name:match("(.*)%.init$") + if init then + name = init + end + else + name = file:match("(.*)%."..cfg.lib_extension.."$") + if name then + name = name:gsub(dir.separator, ".") + end + end + if not name then name = file end + name = name:gsub("^%.+", ""):gsub("%.+$", "") + return name +end + +--- Obtain the directory name where a module should be stored. +-- For example, on Unix, "foo.bar.baz" will return "foo/bar". +-- @param mod string: A module name in Lua dot-separated format. +-- @return string: A directory name using the platform's separator. +function path.module_to_path(mod) + assert(type(mod) == "string") + return (mod:gsub("[^.]*$", ""):gsub("%.", dir.separator)) +end + +--- Set up path-related variables for a given rock. +-- Create a "variables" table in the rockspec table, containing +-- adjusted variables according to the configuration file. +-- @param rockspec table: The rockspec table. +function path.configure_paths(rockspec) + assert(type(rockspec) == "table") + local vars = {} + for k,v in pairs(cfg.variables) do + vars[k] = v + end + local name, version = rockspec.name, rockspec.version + vars.PREFIX = path.install_dir(name, version) + vars.LUADIR = path.lua_dir(name, version) + vars.LIBDIR = path.lib_dir(name, version) + vars.CONFDIR = path.conf_dir(name, version) + vars.BINDIR = path.bin_dir(name, version) + vars.DOCDIR = path.doc_dir(name, version) + rockspec.variables = vars +end + +--- Produce a versioned version of a filename. +-- @param file string: filename (must start with prefix) +-- @param prefix string: Path prefix for file +-- @param name string: Rock name +-- @param version string: Rock version +-- @return string: a pathname with the same directory parts and a versioned basename. +function path.versioned_name(file, prefix, name, version) + assert(type(file) == "string") + assert(type(name) == "string") + assert(type(version) == "string") + + local rest = file:sub(#prefix+1):gsub("^/*", "") + local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_") + return dir.path(prefix, name_version.."-"..rest) +end + +function path.use_tree(tree) + cfg.root_dir = tree + cfg.rocks_dir = path.rocks_dir(tree) + cfg.deploy_bin_dir = path.deploy_bin_dir(tree) + cfg.deploy_lua_dir = path.deploy_lua_dir(tree) + cfg.deploy_lib_dir = path.deploy_lib_dir(tree) +end + +--- Apply a given function to the active rocks trees based on chosen dependency mode. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for no trees (this function becomes a nop). +-- @param fn function: function to be applied, with the tree dir (string) as the first +-- argument and the remaining varargs of map_trees as the following arguments. +-- @return a table with all results of invocations of fn collected. +function path.map_trees(deps_mode, fn, ...) + local result = {} + if deps_mode == "one" then + table.insert(result, (fn(cfg.root_dir, ...)) or 0) + elseif deps_mode == "all" or deps_mode == "order" then + local use = false + if deps_mode == "all" then + use = true + end + for _, tree in ipairs(cfg.rocks_trees) do + if dir.normalize(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then + use = true + end + if use then + table.insert(result, (fn(tree, ...)) or 0) + end + end + end + return result +end + +local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true } + +--- Return the pathname of the file that would be loaded for a module, indexed. +-- @param file_name string: module file name as in manifest (eg. "socket/core.so") +-- @param name string: name of the package (eg. "luasocket") +-- @param version string: version number (eg. "2.0.2-1") +-- @param tree string: repository path (eg. "/usr/local") +-- @param i number: the index, 1 if version is the current default, > 1 otherwise. +-- This is done this way for use by select_module in luarocks.loader. +-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") +function path.which_i(file_name, name, version, tree, i) + local deploy_dir + local extension = file_name:match("%.[a-z]+$") + if is_src_extension[extension] then + deploy_dir = path.deploy_lua_dir(tree) + file_name = dir.path(deploy_dir, file_name) + else + deploy_dir = path.deploy_lib_dir(tree) + file_name = dir.path(deploy_dir, file_name) + end + if i > 1 then + file_name = path.versioned_name(file_name, deploy_dir, name, version) + end + return file_name +end + +--- Return the pathname of the file that would be loaded for a module, +-- returning the versioned pathname if given version is not the default version +-- in the given manifest. +-- @param module_name string: module name (eg. "socket.core") +-- @param file_name string: module file name as in manifest (eg. "socket/core.so") +-- @param name string: name of the package (eg. "luasocket") +-- @param version string: version number (eg. "2.0.2-1") +-- @param tree string: repository path (eg. "/usr/local") +-- @param manifest table: the manifest table for the tree. +-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") +function path.which(module_name, file_name, name, version, tree, manifest) + local versions = manifest.modules[module_name] + assert(versions) + for i, name_version in ipairs(versions) do + if name_version == name.."/"..version then + return path.which_i(file_name, name, version, tree, i):gsub("//", "/") + end + end + assert(false) +end + +return path diff --git a/Utils/luarocks/lua/luarocks/path_cmd.lua b/Utils/luarocks/lua/luarocks/path_cmd.lua new file mode 100644 index 000000000..eba85d46d --- /dev/null +++ b/Utils/luarocks/lua/luarocks/path_cmd.lua @@ -0,0 +1,69 @@ + +--- @module luarocks.path_cmd +-- Driver for the `luarocks path` command. +local path_cmd = {} + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") + +util.add_run_function(path_cmd) +path_cmd.help_summary = "Return the currently configured package path." +path_cmd.help_arguments = "" +path_cmd.help = [[ +Returns the package path currently configured for this installation +of LuaRocks, formatted as shell commands to update LUA_PATH and LUA_CPATH. + +--bin Adds the system path to the output + +--append Appends the paths to the existing paths. Default is to prefix + the LR paths to the existing paths. + +--lr-path Exports the Lua path (not formatted as shell command) + +--lr-cpath Exports the Lua cpath (not formatted as shell command) + +--lr-bin Exports the system path (not formatted as shell command) + + +On Unix systems, you may run: + eval `luarocks path` +And on Windows: + luarocks path > "%temp%\_lrp.bat" && call "%temp%\_lrp.bat" && del "%temp%\_lrp.bat" +]] + +--- Driver function for "path" command. +-- @return boolean This function always succeeds. +function path_cmd.command(flags) + local lr_path, lr_cpath, lr_bin = cfg.package_paths(flags["tree"]) + local path_sep = cfg.export_path_separator + + if flags["lr-path"] then + util.printout(util.remove_path_dupes(lr_path, ';')) + return true + elseif flags["lr-cpath"] then + util.printout(util.remove_path_dupes(lr_cpath, ';')) + return true + elseif flags["lr-bin"] then + util.printout(util.remove_path_dupes(lr_bin, path_sep)) + return true + end + + if flags["append"] then + lr_path = package.path .. ";" .. lr_path + lr_cpath = package.cpath .. ";" .. lr_cpath + lr_bin = os.getenv("PATH") .. path_sep .. lr_bin + else + lr_path = lr_path.. ";" .. package.path + lr_cpath = lr_cpath .. ";" .. package.cpath + lr_bin = lr_bin .. path_sep .. os.getenv("PATH") + end + + util.printout(cfg.export_lua_path:format(util.remove_path_dupes(lr_path, ';'))) + util.printout(cfg.export_lua_cpath:format(util.remove_path_dupes(lr_cpath, ';'))) + if flags["bin"] then + util.printout(cfg.export_path:format(util.remove_path_dupes(lr_bin, path_sep))) + end + return true +end + +return path_cmd diff --git a/Utils/luarocks/lua/luarocks/persist.lua b/Utils/luarocks/lua/luarocks/persist.lua new file mode 100644 index 000000000..708f07bed --- /dev/null +++ b/Utils/luarocks/lua/luarocks/persist.lua @@ -0,0 +1,210 @@ + +--- Utility module for loading files into tables and +-- saving tables into files. +-- Implemented separately to avoid interdependencies, +-- as it is used in the bootstrapping stage of the cfg module. +local persist = {} +package.loaded["luarocks.persist"] = persist + +local util = require("luarocks.util") + +--- Load and run a Lua file in an environment. +-- @param filename string: the name of the file. +-- @param env table: the environment table. +-- @return (true, any) or (nil, string, string): true and the return value +-- of the file, or nil, an error message and an error code ("open", "load" +-- or "run") in case of errors. +local function run_file(filename, env) + local fd, err = io.open(filename) + if not fd then + return nil, err, "open" + end + local str, err = fd:read("*a") + fd:close() + if not str then + return nil, err, "open" + end + str = str:gsub("^#![^\n]*\n", "") + local chunk, ran + if _VERSION == "Lua 5.1" then -- Lua 5.1 + chunk, err = loadstring(str, filename) + if chunk then + setfenv(chunk, env) + ran, err = pcall(chunk) + end + else -- Lua 5.2 + chunk, err = load(str, filename, "t", env) + if chunk then + ran, err = pcall(chunk) + end + end + if not chunk then + return nil, "Error loading file: "..err, "load" + end + if not ran then + return nil, "Error running file: "..err, "run" + end + return true, err +end + +--- Load a Lua file containing assignments, storing them in a table. +-- The global environment is not propagated to the loaded file. +-- @param filename string: the name of the file. +-- @param tbl table or nil: if given, this table is used to store +-- loaded values. +-- @return (table, table) or (nil, string, string): a table with the file's assignments +-- as fields and set of undefined globals accessed in file, +-- or nil, an error message and an error code ("open"; couldn't open the file, +-- "load"; compile-time error, or "run"; run-time error) +-- in case of errors. +function persist.load_into_table(filename, tbl) + assert(type(filename) == "string") + assert(type(tbl) == "table" or not tbl) + + local result = tbl or {} + local globals = {} + local globals_mt = { + __index = function(t, k) + globals[k] = true + end + } + local save_mt = getmetatable(result) + setmetatable(result, globals_mt) + + local ok, err, errcode = run_file(filename, result) + + setmetatable(result, save_mt) + + if not ok then + return nil, err, errcode + end + return result, globals +end + +local write_table + +--- Write a value as Lua code. +-- This function handles only numbers and strings, invoking write_table +-- to write tables. +-- @param out table or userdata: a writer object supporting :write() method. +-- @param v: the value to be written. +-- @param level number: the indentation level +-- @param sub_order table: optional prioritization table +-- @see write_table +local function write_value(out, v, level, sub_order) + if type(v) == "table" then + write_table(out, v, level + 1, sub_order) + elseif type(v) == "string" then + if v:match("[\r\n]") then + local open, close = "[[", "]]" + local equals = 0 + local v_with_bracket = v.."]" + while v_with_bracket:find(close, 1, true) do + equals = equals + 1 + local eqs = ("="):rep(equals) + open, close = "["..eqs.."[", "]"..eqs.."]" + end + out:write(open.."\n"..v..close) + else + out:write(("%q"):format(v)) + end + else + out:write(tostring(v)) + end +end + +--- Write a table as Lua code in curly brackets notation to a writer object. +-- Only numbers, strings and tables (containing numbers, strings +-- or other recursively processed tables) are supported. +-- @param out table or userdata: a writer object supporting :write() method. +-- @param tbl table: the table to be written. +-- @param level number: the indentation level +-- @param field_order table: optional prioritization table +write_table = function(out, tbl, level, field_order) + out:write("{") + local sep = "\n" + local indentation = " " + local indent = true + local i = 1 + for k, v, sub_order in util.sortedpairs(tbl, field_order) do + out:write(sep) + if indent then + for n = 1,level do out:write(indentation) end + end + + if k == i then + i = i + 1 + else + if type(k) == "string" and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then + out:write(k) + else + out:write("[") + write_value(out, k, level) + out:write("]") + end + + out:write(" = ") + end + + write_value(out, v, level, sub_order) + if type(v) == "number" then + sep = ", " + indent = false + else + sep = ",\n" + indent = true + end + end + if sep ~= "\n" then + out:write("\n") + for n = 1,level-1 do out:write(indentation) end + end + out:write("}") +end + +--- Write a table as series of assignments to a writer object. +-- @param out table or userdata: a writer object supporting :write() method. +-- @param tbl table: the table to be written. +-- @param field_order table: optional prioritization table +local function write_table_as_assignments(out, tbl, field_order) + for k, v, sub_order in util.sortedpairs(tbl, field_order) do + out:write(k.." = ") + write_value(out, v, 0, sub_order) + out:write("\n") + end +end + +--- Save the contents of a table to a string. +-- Each element of the table is saved as a global assignment. +-- Only numbers, strings and tables (containing numbers, strings +-- or other recursively processed tables) are supported. +-- @param tbl table: the table containing the data to be written +-- @param field_order table: an optional array indicating the order of top-level fields. +-- @return string +function persist.save_from_table_to_string(tbl, field_order) + local out = {buffer = {}} + function out:write(data) table.insert(self.buffer, data) end + write_table_as_assignments(out, tbl, field_order) + return table.concat(out.buffer) +end + +--- Save the contents of a table in a file. +-- Each element of the table is saved as a global assignment. +-- Only numbers, strings and tables (containing numbers, strings +-- or other recursively processed tables) are supported. +-- @param filename string: the output filename +-- @param tbl table: the table containing the data to be written +-- @param field_order table: an optional array indicating the order of top-level fields. +-- @return boolean or (nil, string): true if successful, or nil and a +-- message in case of errors. +function persist.save_from_table(filename, tbl, field_order) + local out = io.open(filename, "w") + if not out then + return nil, "Cannot create file at "..filename + end + write_table_as_assignments(out, tbl, field_order) + out:close() + return true +end + +return persist diff --git a/Utils/luarocks/lua/luarocks/purge.lua b/Utils/luarocks/lua/luarocks/purge.lua new file mode 100644 index 000000000..17724e847 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/purge.lua @@ -0,0 +1,79 @@ + +--- Module implementing the LuaRocks "purge" command. +-- Remove all rocks from a given tree. +local purge = {} +package.loaded["luarocks.purge"] = purge + +local util = require("luarocks.util") +local fs = require("luarocks.fs") +local path = require("luarocks.path") +local search = require("luarocks.search") +local deps = require("luarocks.deps") +local repos = require("luarocks.repos") +local manif = require("luarocks.manif") +local cfg = require("luarocks.cfg") +local remove = require("luarocks.remove") + +util.add_run_function(purge) +purge.help_summary = "Remove all installed rocks from a tree." +purge.help_arguments = "--tree= [--old-versions]" +purge.help = [[ +This command removes rocks en masse from a given tree. +By default, it removes all rocks from a tree. + +The --tree argument is mandatory: luarocks purge does not +assume a default tree. + +--old-versions Keep the highest-numbered version of each + rock and remove the other ones. By default + it only removes old versions if they are + not needed as dependencies. This can be + overridden with the flag --force. +]] + +function purge.command(flags) + local tree = flags["tree"] + + if type(tree) ~= "string" then + return nil, "The --tree argument is mandatory. "..util.see_help("purge") + end + + local results = {} + local query = search.make_query("") + query.exact_name = false + if not fs.is_dir(tree) then + return nil, "Directory not found: "..tree + end + + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end + + search.manifest_search(results, path.rocks_dir(tree), query) + + local sort = function(a,b) return deps.compare_versions(b,a) end + if flags["old-versions"] then + sort = deps.compare_versions + end + + for package, versions in util.sortedpairs(results) do + for version, repositories in util.sortedpairs(versions, sort) do + if flags["old-versions"] then + util.printout("Keeping "..package.." "..version.."...") + local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"]) + if not ok then + util.printerr(err) + end + break + else + util.printout("Removing "..package.." "..version.."...") + local ok, err = repos.delete_version(package, version, "none", true) + if not ok then + util.printerr(err) + end + end + end + end + return manif.make_manifest(cfg.rocks_dir, "one") +end + +return purge diff --git a/Utils/luarocks/lua/luarocks/refresh_cache.lua b/Utils/luarocks/lua/luarocks/refresh_cache.lua new file mode 100644 index 000000000..bbfd1f4d8 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/refresh_cache.lua @@ -0,0 +1,33 @@ + +--- Module implementing the luarocks-admin "refresh_cache" command. +local refresh_cache = {} +package.loaded["luarocks.refresh_cache"] = refresh_cache + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local cache = require("luarocks.cache") + +util.add_run_function(refresh_cache) +refresh_cache.help_summary = "Refresh local cache of a remote rocks server." +refresh_cache.help_arguments = "[--from=]" +refresh_cache.help = [[ +The flag --from indicates which server to use. +If not given, the default server set in the upload_server variable +from the configuration file is used instead. +]] + +function refresh_cache.command(flags) + local server, upload_server = cache.get_upload_server(flags["server"]) + if not server then return nil, upload_server end + local download_url = cache.get_server_urls(server, upload_server) + + local ok, err = cache.refresh_local_cache(server, download_url, cfg.upload_user, cfg.upload_password) + if not ok then + return nil, err + else + return true + end +end + + +return refresh_cache diff --git a/Utils/luarocks/lua/luarocks/remove.lua b/Utils/luarocks/lua/luarocks/remove.lua new file mode 100644 index 000000000..514c6dfa1 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/remove.lua @@ -0,0 +1,174 @@ + +--- Module implementing the LuaRocks "remove" command. +-- Uninstalls rocks. +local remove = {} +package.loaded["luarocks.remove"] = remove + +local search = require("luarocks.search") +local deps = require("luarocks.deps") +local fetch = require("luarocks.fetch") +local repos = require("luarocks.repos") +local path = require("luarocks.path") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local fs = require("luarocks.fs") +local manif = require("luarocks.manif") + +util.add_run_function(remove) +remove.help_summary = "Uninstall a rock." +remove.help_arguments = "[--force|--force-fast] []" +remove.help = [[ +Argument is the name of a rock to be uninstalled. +If a version is not given, try to remove all versions at once. +Will only perform the removal if it does not break dependencies. +To override this check and force the removal, use --force. +To perform a forced removal without reporting dependency issues, +use --force-fast. + +]]..util.deps_mode_help() + +--- Obtain a list of packages that depend on the given set of packages +-- (where all packages of the set are versions of one program). +-- @param name string: the name of a program +-- @param versions array of string: the versions to be deleted. +-- @return array of string: an empty table if no packages depend on any +-- of the given list, or an array of strings in "name/version" format. +local function check_dependents(name, versions, deps_mode) + local dependents = {} + local blacklist = {} + blacklist[name] = {} + for version, _ in pairs(versions) do + blacklist[name][version] = true + end + local local_rocks = {} + local query_all = search.make_query("") + query_all.exact_name = false + search.manifest_search(local_rocks, cfg.rocks_dir, query_all) + local_rocks[name] = nil + for rock_name, rock_versions in pairs(local_rocks) do + for rock_version, _ in pairs(rock_versions) do + local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version)) + if rockspec then + local _, missing = deps.match_deps(rockspec, blacklist, deps_mode) + if missing[name] then + table.insert(dependents, { name = rock_name, version = rock_version }) + end + end + end + end + return dependents +end + +--- Delete given versions of a program. +-- @param name string: the name of a program +-- @param versions array of string: the versions to be deleted. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +-- @return boolean or (nil, string): true on success or nil and an error message. +local function delete_versions(name, versions, deps_mode) + + for version, _ in pairs(versions) do + util.printout("Removing "..name.." "..version.."...") + local ok, err = repos.delete_version(name, version, deps_mode) + if not ok then return nil, err end + end + + return true +end + +function remove.remove_search_results(results, name, deps_mode, force, fast) + local versions = results[name] + + local version = next(versions) + local second = next(versions, version) + + local dependents = {} + if not fast then + util.printout("Checking stability of dependencies in the absence of") + util.printout(name.." "..table.concat(util.keys(versions), ", ").."...") + util.printout() + dependents = check_dependents(name, versions, deps_mode) + end + + if #dependents > 0 then + if force or fast then + util.printerr("The following packages may be broken by this forced removal:") + for _, dependent in ipairs(dependents) do + util.printerr(dependent.name.." "..dependent.version) + end + util.printerr() + else + if not second then + util.printerr("Will not remove "..name.." "..version..".") + util.printerr("Removing it would break dependencies for: ") + else + util.printerr("Will not remove installed versions of "..name..".") + util.printerr("Removing them would break dependencies for: ") + end + for _, dependent in ipairs(dependents) do + util.printerr(dependent.name.." "..dependent.version) + end + util.printerr() + util.printerr("Use --force to force removal (warning: this may break modules).") + return nil, "Failed removing." + end + end + + local ok, err = delete_versions(name, versions, deps_mode) + if not ok then return nil, err end + + util.printout("Removal successful.") + return true +end + +function remove.remove_other_versions(name, version, force, fast) + local results = {} + search.manifest_search(results, cfg.rocks_dir, { name = name, exact_name = true, constraints = {{ op = "~=", version = version}} }) + if results[name] then + return remove.remove_search_results(results, name, cfg.deps_mode, force, fast) + end + return true +end + +--- Driver function for the "remove" command. +-- @param name string: name of a rock. If a version is given, refer to +-- a specific version; otherwise, try to remove all versions. +-- @param version string: When passing a package name, a version number +-- may also be given. +-- @return boolean or (nil, string, exitcode): True if removal was +-- successful, nil and an error message otherwise. exitcode is optionally returned. +function remove.command(flags, name, version) + if type(name) ~= "string" then + return nil, "Argument missing. "..util.see_help("remove") + end + + local deps_mode = flags["deps-mode"] or cfg.deps_mode + + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end + + local rock_type = name:match("%.(rock)$") or name:match("%.(rockspec)$") + local filename = name + if rock_type then + name, version = path.parse_name(filename) + if not name then return nil, "Invalid "..rock_type.." filename: "..filename end + end + + local results = {} + name = name:lower() + search.manifest_search(results, cfg.rocks_dir, search.make_query(name, version)) + if not results[name] then + return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir) + end + + local ok, err = remove.remove_search_results(results, name, deps_mode, flags["force"], flags["force-fast"]) + if not ok then + return nil, err + end + + manif.check_dependencies(nil, deps.get_deps_mode(flags)) + return true +end + +return remove diff --git a/Utils/luarocks/lua/luarocks/repos.lua b/Utils/luarocks/lua/luarocks/repos.lua new file mode 100644 index 000000000..5d5eac708 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/repos.lua @@ -0,0 +1,422 @@ + +--- Functions for managing the repository on disk. +local repos = {} +package.loaded["luarocks.repos"] = repos + +local fs = require("luarocks.fs") +local path = require("luarocks.path") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local deps = require("luarocks.deps") + +-- Tree of files installed by a package are stored +-- in its rock manifest. Some of these files have to +-- be deployed to locations where Lua can load them as +-- modules or where they can be used as commands. +-- These files are characterised by pair +-- (deploy_type, file_path), where deploy_type is the first +-- component of the file path and file_path is the rest of the +-- path. Only files with deploy_type in {"lua", "lib", "bin"} +-- are deployed somewhere. +-- Each deployed file provides an "item". An item is +-- characterised by pair (item_type, item_name). +-- item_type is "command" for files with deploy_type +-- "bin" and "module" for deploy_type in {"lua", "lib"}. +-- item_name is same as file_path for commands +-- and is produced using path.path_to_module(file_path) +-- for modules. + +--- Get all installed versions of a package. +-- @param name string: a package name. +-- @return table or nil: An array of strings listing installed +-- versions of a package, or nil if none is available. +local function get_installed_versions(name) + assert(type(name) == "string") + + local dirs = fs.list_dir(path.versions_dir(name)) + return (dirs and #dirs > 0) and dirs or nil +end + +--- Check if a package exists in a local repository. +-- Version numbers are compared as exact string comparison. +-- @param name string: name of package +-- @param version string: package version in string format +-- @return boolean: true if a package is installed, +-- false otherwise. +function repos.is_installed(name, version) + assert(type(name) == "string") + assert(type(version) == "string") + + return fs.is_dir(path.install_dir(name, version)) +end + +local function recurse_rock_manifest_tree(file_tree, action) + assert(type(file_tree) == "table") + assert(type(action) == "function") + local function do_recurse_rock_manifest_tree(tree, parent_path, parent_module) + + for file, sub in pairs(tree) do + if type(sub) == "table" then + local ok, err = do_recurse_rock_manifest_tree(sub, parent_path..file.."/", parent_module..file..".") + if not ok then return nil, err end + else + local ok, err = action(parent_path, parent_module, file) + if not ok then return nil, err end + end + end + return true + end + return do_recurse_rock_manifest_tree(file_tree, "", "") +end + +local function store_package_data(result, name, file_tree) + if not file_tree then return end + return recurse_rock_manifest_tree(file_tree, + function(parent_path, parent_module, file) + local pathname = parent_path..file + result[path.path_to_module(pathname)] = pathname + return true + end + ) +end + +--- Obtain a list of modules within an installed package. +-- @param package string: The package name; for example "luasocket" +-- @param version string: The exact version number including revision; +-- for example "2.0.1-1". +-- @return table: A table of modules where keys are module identifiers +-- in "foo.bar" format and values are pathnames in architecture-dependent +-- "foo/bar.so" format. If no modules are found or if package or version +-- are invalid, an empty table is returned. +function repos.package_modules(package, version) + assert(type(package) == "string") + assert(type(version) == "string") + + local result = {} + local rock_manifest = manif.load_rock_manifest(package, version) + store_package_data(result, package, rock_manifest.lib) + store_package_data(result, package, rock_manifest.lua) + return result +end + +--- Obtain a list of command-line scripts within an installed package. +-- @param package string: The package name; for example "luasocket" +-- @param version string: The exact version number including revision; +-- for example "2.0.1-1". +-- @return table: A table of items where keys are command names +-- as strings and values are pathnames in architecture-dependent +-- ".../bin/foo" format. If no modules are found or if package or version +-- are invalid, an empty table is returned. +function repos.package_commands(package, version) + assert(type(package) == "string") + assert(type(version) == "string") + + local result = {} + local rock_manifest = manif.load_rock_manifest(package, version) + store_package_data(result, package, rock_manifest.bin) + return result +end + + +--- Check if a rock contains binary executables. +-- @param name string: name of an installed rock +-- @param version string: version of an installed rock +-- @return boolean: returns true if rock contains platform-specific +-- binary executables, or false if it is a pure-Lua rock. +function repos.has_binaries(name, version) + assert(type(name) == "string") + assert(type(version) == "string") + + local rock_manifest = manif.load_rock_manifest(name, version) + if rock_manifest.bin then + for name, md5 in pairs(rock_manifest.bin) do + -- TODO verify that it is the same file. If it isn't, find the actual command. + if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, name)) then + return true + end + end + end + return false +end + +function repos.run_hook(rockspec, hook_name) + assert(type(rockspec) == "table") + assert(type(hook_name) == "string") + + local hooks = rockspec.hooks + if not hooks then + return true + end + + if cfg.hooks_enabled == false then + return nil, "This rockspec contains hooks, which are blocked by the 'hooks_enabled' setting in your LuaRocks configuration." + end + + if not hooks.substituted_variables then + util.variable_substitutions(hooks, rockspec.variables) + hooks.substituted_variables = true + end + local hook = hooks[hook_name] + if hook then + util.printout(hook) + if not fs.execute(hook) then + return nil, "Failed running "..hook_name.." hook." + end + end + return true +end + +function repos.should_wrap_bin_scripts(rockspec) + assert(type(rockspec) == "table") + + if cfg.wrap_bin_scripts ~= nil then + return cfg.wrap_bin_scripts + end + if rockspec.deploy and rockspec.deploy.wrap_bin_scripts == false then + return false + end + return true +end + +local function find_suffixed(file, suffix) + local filenames = {file} + if suffix and suffix ~= "" then + table.insert(filenames, 1, file .. suffix) + end + + for _, filename in ipairs(filenames) do + if fs.exists(filename) then + return filename + end + end + + return nil, table.concat(filenames, ", ") .. " not found" +end + +local function move_suffixed(from_file, to_file, suffix) + local suffixed_from_file, err = find_suffixed(from_file, suffix) + if not suffixed_from_file then + return nil, "Could not move " .. from_file .. " to " .. to_file .. ": " .. err + end + + suffix = suffixed_from_file:sub(#from_file + 1) + local suffixed_to_file = to_file .. suffix + return fs.move(suffixed_from_file, suffixed_to_file) +end + +local function delete_suffixed(file, suffix) + local suffixed_file, err = find_suffixed(file, suffix) + if not suffixed_file then + return nil, "Could not remove " .. file .. ": " .. err + end + + fs.delete(suffixed_file) + if fs.exists(suffixed_file) then + return nil, "Failed deleting " .. suffixed_file .. ": file still exists" + end + + return true +end + +-- Files can be deployed using versioned and non-versioned names. +-- Several items with same type and name can exist if they are +-- provided by different packages or versions. In any case +-- item from the newest version of lexicographically smallest package +-- is deployed using non-versioned name and others use versioned names. + +local function get_deploy_paths(name, version, deploy_type, file_path) + local deploy_dir = cfg["deploy_" .. deploy_type .. "_dir"] + local non_versioned = dir.path(deploy_dir, file_path) + local versioned = path.versioned_name(non_versioned, deploy_dir, name, version) + return non_versioned, versioned +end + +local function prepare_target(name, version, deploy_type, file_path, suffix) + local non_versioned, versioned = get_deploy_paths(name, version, deploy_type, file_path) + local item_type, item_name = manif.get_provided_item(deploy_type, file_path) + local cur_name, cur_version = manif.get_current_provider(item_type, item_name) + + if not cur_name then + return non_versioned + elseif name < cur_name or (name == cur_name and deps.compare_versions(version, cur_version)) then + -- New version has priority. Move currently provided version back using versioned name. + local cur_deploy_type, cur_file_path = manif.get_providing_file(cur_name, cur_version, item_type, item_name) + local cur_non_versioned, cur_versioned = get_deploy_paths(cur_name, cur_version, cur_deploy_type, cur_file_path) + + local dir_ok, dir_err = fs.make_dir(dir.dir_name(cur_versioned)) + if not dir_ok then return nil, dir_err end + + local move_ok, move_err = move_suffixed(cur_non_versioned, cur_versioned, suffix) + if not move_ok then return nil, move_err end + + return non_versioned + else + -- Current version has priority, deploy new version using versioned name. + return versioned + end +end + +--- Deploy a package from the rocks subdirectory. +-- @param name string: name of package +-- @param version string: exact package version in string format +-- @param wrap_bin_scripts bool: whether commands written in Lua should be wrapped. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode) + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(wrap_bin_scripts) == "boolean") + + local rock_manifest = manif.load_rock_manifest(name, version) + + local function deploy_file_tree(deploy_type, source_dir, move_fn, suffix) + if not rock_manifest[deploy_type] then + return true + end + + return recurse_rock_manifest_tree(rock_manifest[deploy_type], function(parent_path, parent_module, file) + local file_path = parent_path .. file + local source = dir.path(source_dir, file_path) + + local target, prepare_err = prepare_target(name, version, deploy_type, file_path, suffix) + if not target then return nil, prepare_err end + + local dir_ok, dir_err = fs.make_dir(dir.dir_name(target)) + if not dir_ok then return nil, dir_err end + + local suffixed_target, mover = move_fn(source, target) + if fs.exists(suffixed_target) then + local backup = suffixed_target + repeat + backup = backup.."~" + until not fs.exists(backup) -- Slight race condition here, but shouldn't be a problem. + + util.printerr("Warning: "..suffixed_target.." is not tracked by this installation of LuaRocks. Moving it to "..backup) + local move_ok, move_err = fs.move(suffixed_target, backup) + if not move_ok then return nil, move_err end + end + + local move_ok, move_err = mover() + if not move_ok then return nil, move_err end + + fs.remove_dir_tree_if_empty(dir.dir_name(source)) + return true + end) + end + + local function install_binary(source, target) + if wrap_bin_scripts and fs.is_lua(source) then + return target .. (cfg.wrapper_suffix or ""), function() return fs.wrap_script(source, target, name, version) end + else + return target, function() return fs.copy_binary(source, target) end + end + end + + local function make_mover(perms) + return function(source, target) + return target, function() return fs.move(source, target, perms) end + end + end + + local ok, err = deploy_file_tree("bin", path.bin_dir(name, version), install_binary, cfg.wrapper_suffix) + if not ok then return nil, err end + + ok, err = deploy_file_tree("lua", path.lua_dir(name, version), make_mover(cfg.perm_read)) + if not ok then return nil, err end + + ok, err = deploy_file_tree("lib", path.lib_dir(name, version), make_mover(cfg.perm_exec)) + if not ok then return nil, err end + + return manif.add_to_manifest(name, version, nil, deps_mode) +end + +--- Delete a package from the local repository. +-- @param name string: name of package +-- @param version string: exact package version in string format +-- @param deps_mode: string: Which trees to check dependencies for: +-- "one" for the current default tree, "all" for all trees, +-- "order" for all trees with priority >= the current default, "none" for no trees. +-- @param quick boolean: do not try to fix the versioned name +-- of another version that provides the same module that +-- was deleted. This is used during 'purge', as every module +-- will be eventually deleted. +function repos.delete_version(name, version, deps_mode, quick) + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(deps_mode) == "string") + + local rock_manifest = manif.load_rock_manifest(name, version) + if not rock_manifest then + return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?" + end + + local function delete_deployed_file_tree(deploy_type, suffix) + if not rock_manifest[deploy_type] then + return true + end + + return recurse_rock_manifest_tree(rock_manifest[deploy_type], function(parent_path, parent_module, file) + local file_path = parent_path .. file + local non_versioned, versioned = get_deploy_paths(name, version, deploy_type, file_path) + + -- Figure out if the file is deployed using versioned or non-versioned name. + local target + local item_type, item_name = manif.get_provided_item(deploy_type, file_path) + local cur_name, cur_version = manif.get_current_provider(item_type, item_name) + + if cur_name == name and cur_version == version then + -- This package has highest priority, should be in non-versioned location. + target = non_versioned + else + target = versioned + end + + local ok, err = delete_suffixed(target, suffix) + if not ok then return nil, err end + + if not quick and target == non_versioned then + -- If another package provides this file, move its version + -- into non-versioned location instead. + local next_name, next_version = manif.get_next_provider(item_type, item_name) + + if next_name then + local next_deploy_type, next_file_path = manif.get_providing_file(next_name, next_version, item_type, item_name) + local next_non_versioned, next_versioned = get_deploy_paths(next_name, next_version, next_deploy_type, next_file_path) + + local move_ok, move_err = move_suffixed(next_versioned, next_non_versioned, suffix) + if not move_ok then return nil, move_err end + + fs.remove_dir_tree_if_empty(dir.dir_name(next_versioned)) + end + end + + fs.remove_dir_tree_if_empty(dir.dir_name(target)) + return true + end) + end + + local ok, err = delete_deployed_file_tree("bin", cfg.wrapper_suffix) + if not ok then return nil, err end + + ok, err = delete_deployed_file_tree("lua") + if not ok then return nil, err end + + ok, err = delete_deployed_file_tree("lib") + if not ok then return nil, err end + + fs.delete(path.install_dir(name, version)) + if not get_installed_versions(name) then + fs.delete(dir.path(cfg.rocks_dir, name)) + end + + if quick then + return true + end + + return manif.remove_from_manifest(name, version, nil, deps_mode) +end + +return repos diff --git a/Utils/luarocks/lua/luarocks/require.lua b/Utils/luarocks/lua/luarocks/require.lua new file mode 100644 index 000000000..902bd1a3c --- /dev/null +++ b/Utils/luarocks/lua/luarocks/require.lua @@ -0,0 +1,2 @@ +--- Retained for compatibility reasons only. Use luarocks.loader instead. +return require("luarocks.loader") diff --git a/Utils/luarocks/lua/luarocks/search.lua b/Utils/luarocks/lua/luarocks/search.lua new file mode 100644 index 000000000..d22c2a185 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/search.lua @@ -0,0 +1,483 @@ + +--- Module implementing the LuaRocks "search" command. +-- Queries LuaRocks servers. +local search = {} +package.loaded["luarocks.search"] = search + +local dir = require("luarocks.dir") +local path = require("luarocks.path") +local manif = require("luarocks.manif") +local deps = require("luarocks.deps") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") + +util.add_run_function(search) +search.help_summary = "Query the LuaRocks servers." +search.help_arguments = "[--source] [--binary] { [] | --all }" +search.help = [[ +--source Return only rockspecs and source rocks, + to be used with the "build" command. +--binary Return only pure Lua and binary rocks (rocks that can be used + with the "install" command without requiring a C toolchain). +--all List all contents of the server that are suitable to + this platform, do not filter by name. +]] + +--- Convert the arch field of a query table to table format. +-- @param query table: A query table. +local function query_arch_as_table(query) + local format = type(query.arch) + if format == "table" then + return + elseif format == "nil" then + local accept = {} + accept["src"] = true + accept["all"] = true + accept["rockspec"] = true + accept["installed"] = true + accept[cfg.arch] = true + query.arch = accept + elseif format == "string" then + local accept = {} + for a in query.arch:gmatch("[%w_-]+") do + accept[a] = true + end + query.arch = accept + end +end + +--- Store a search result (a rock or rockspec) in the results table. +-- @param results table: The results table, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- @param name string: Package name. +-- @param version string: Package version. +-- @param arch string: Architecture of rock ("all", "src" or platform +-- identifier), "rockspec" or "installed" +-- @param repo string: Pathname of a local repository of URL of +-- rocks server. +local function store_result(results, name, version, arch, repo) + assert(type(results) == "table") + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(arch) == "string") + assert(type(repo) == "string") + + if not results[name] then results[name] = {} end + if not results[name][version] then results[name][version] = {} end + table.insert(results[name][version], { + arch = arch, + repo = repo + }) +end + +--- Test the name field of a query. +-- If query has a boolean field exact_name set to false, +-- then substring match is performed; otherwise, exact string +-- comparison is done. +-- @param query table: A query in dependency table format. +-- @param name string: A package name. +-- @return boolean: True if names match, false otherwise. +local function match_name(query, name) + assert(type(query) == "table") + assert(type(name) == "string") + if query.exact_name == false then + return name:find(query.name, 0, true) and true or false + else + return name == query.name + end +end + +--- Store a match in a results table if version matches query. +-- Name, version, arch and repository path are stored in a given +-- table, optionally checking if version and arch (if given) match +-- a query. +-- @param results table: The results table, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- @param repo string: URL or pathname of the repository. +-- @param name string: The name of the package being tested. +-- @param version string: The version of the package being tested. +-- @param arch string: The arch of the package being tested. +-- @param query table: A table describing the query in dependency +-- format (for example, {name = "filesystem", exact_name = false, +-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). +-- If the arch field is omitted, the local architecture (cfg.arch) +-- is used. The special value "any" is also recognized, returning all +-- matches regardless of architecture. +local function store_if_match(results, repo, name, version, arch, query) + if match_name(query, name) then + if query.arch[arch] or query.arch["any"] then + if deps.match_constraints(deps.parse_version(version), query.constraints) then + store_result(results, name, version, arch, repo) + end + end + end +end + +--- Perform search on a local repository. +-- @param repo string: The pathname of the local repository. +-- @param query table: A table describing the query in dependency +-- format (for example, {name = "filesystem", exact_name = false, +-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). +-- If the arch field is omitted, the local architecture (cfg.arch) +-- is used. The special value "any" is also recognized, returning all +-- matches regardless of architecture. +-- @param results table or nil: If given, this table will store the +-- results; if not given, a new table will be created. +-- @return table: The results table, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- If a table was given in the "results" parameter, that is the result value. +function search.disk_search(repo, query, results) + assert(type(repo) == "string") + assert(type(query) == "table") + assert(type(results) == "table" or not results) + + local fs = require("luarocks.fs") + + if not results then + results = {} + end + query_arch_as_table(query) + + for name in fs.dir(repo) do + local pathname = dir.path(repo, name) + local rname, rversion, rarch = path.parse_name(name) + + if rname and (pathname:match(".rockspec$") or pathname:match(".rock$")) then + store_if_match(results, repo, rname, rversion, rarch, query) + elseif fs.is_dir(pathname) then + for version in fs.dir(pathname) do + if version:match("-%d+$") then + store_if_match(results, repo, name, version, "installed", query) + end + end + end + end + return results +end + +--- Perform search on a rocks server or tree. +-- @param results table: The results table, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- @param repo string: The URL of a rocks server or +-- the pathname of a rocks tree (as returned by path.rocks_dir()). +-- @param query table: A table describing the query in dependency +-- format (for example, {name = "filesystem", exact_name = false, +-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). +-- If the arch field is omitted, the local architecture (cfg.arch) +-- is used. The special value "any" is also recognized, returning all +-- matches regardless of architecture. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @return true or, in case of errors, nil, an error message and an optional error code. +function search.manifest_search(results, repo, query, lua_version) + assert(type(results) == "table") + assert(type(repo) == "string") + assert(type(query) == "table") + + query_arch_as_table(query) + local manifest, err, errcode = manif.load_manifest(repo, lua_version) + if not manifest then + return nil, err, errcode + end + for name, versions in pairs(manifest.repository) do + for version, items in pairs(versions) do + for _, item in ipairs(items) do + store_if_match(results, repo, name, version, item.arch, query) + end + end + end + return true +end + +--- Search on all configured rocks servers. +-- @param query table: A dependency query. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @return table: A table where keys are package names +-- and values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +function search.search_repos(query, lua_version) + assert(type(query) == "table") + + local results = {} + for _, repo in ipairs(cfg.rocks_servers) do + if not cfg.disabled_servers[repo] then + if type(repo) == "string" then + repo = { repo } + end + for _, mirror in ipairs(repo) do + local protocol, pathname = dir.split_url(mirror) + if protocol == "file" then + mirror = pathname + end + local ok, err, errcode = search.manifest_search(results, mirror, query, lua_version) + if errcode == "network" then + cfg.disabled_servers[repo] = true + end + if ok then + break + else + util.warning("Failed searching manifest: "..err) + end + end + end + end + -- search through rocks in cfg.rocks_provided + local provided_repo = "provided by VM or rocks_provided" + for name, versions in pairs(cfg.rocks_provided) do + store_if_match(results, provided_repo, name, versions, "installed", query) + end + return results +end + +--- Prepare a query in dependency table format. +-- @param name string: The query name. +-- @param version string or nil: +-- @return table: A query in table format +function search.make_query(name, version) + assert(type(name) == "string") + assert(type(version) == "string" or not version) + + local query = { + name = name, + constraints = {} + } + if version then + table.insert(query.constraints, { op = "==", version = deps.parse_version(version)}) + end + return query +end + +--- Get the URL for the latest in a set of versions. +-- @param name string: The package name to be used in the URL. +-- @param versions table: An array of version informations, as stored +-- in search results tables. +-- @return string or nil: the URL for the latest version if one could +-- be picked, or nil. +local function pick_latest_version(name, versions) + assert(type(name) == "string") + assert(type(versions) == "table") + + local vtables = {} + for v, _ in pairs(versions) do + table.insert(vtables, deps.parse_version(v)) + end + table.sort(vtables) + local version = vtables[#vtables].string + local items = versions[version] + if items then + local pick = 1 + for i, item in ipairs(items) do + if (item.arch == 'src' and items[pick].arch == 'rockspec') + or (item.arch ~= 'src' and item.arch ~= 'rockspec') then + pick = i + end + end + return path.make_url(items[pick].repo, name, version, items[pick].arch) + end + return nil +end + +-- Find out which other Lua versions provide rock versions matching a query, +-- @param query table: A dependency query matching a single rock. +-- @return table: array of Lua versions supported, in "5.x" format. +local function supported_lua_versions(query) + local results = {} + + for lua_version in util.lua_versions() do + if lua_version ~= cfg.lua_version then + if search.search_repos(query, lua_version)[query.name] then + table.insert(results, lua_version) + end + end + end + + return results +end + +--- Attempt to get a single URL for a given search for a rock. +-- @param query table: A dependency query matching a single rock. +-- @return string or (nil, string): URL for latest matching version +-- of the rock if it was found, or nil followed by an error message. +function search.find_suitable_rock(query) + assert(type(query) == "table") + + local results = search.search_repos(query) + local first_rock = next(results) + if not first_rock then + if cfg.rocks_provided[query.name] == nil then + -- Check if constraints are satisfiable with other Lua versions. + local lua_versions = supported_lua_versions(query) + + if #lua_versions ~= 0 then + -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format + for i, lua_version in ipairs(lua_versions) do + lua_versions[i] = "Lua "..lua_version + end + + local versions_message = "only "..table.concat(lua_versions, " and ").. + " but not Lua "..cfg.lua_version.."." + + if #query.constraints == 0 then + return nil, query.name.." supports "..versions_message + elseif #query.constraints == 1 and query.constraints[1].op == "==" then + return nil, query.name.." "..query.constraints[1].version.string.." supports "..versions_message + else + return nil, "Matching "..query.name.." versions support "..versions_message + end + end + end + + return nil, "No results matching query were found." + elseif next(results, first_rock) then + -- Shouldn't happen as query must match only one package. + return nil, "Several rocks matched query." + elseif cfg.rocks_provided[query.name] ~= nil then + -- Do not install versions listed in cfg.rocks_provided. + return nil, "Rock "..query.name.." "..cfg.rocks_provided[query.name].. + " was found but it is provided by VM or 'rocks_provided' in the config file." + else + return pick_latest_version(query.name, results[first_rock]) + end +end + +--- Print a list of rocks/rockspecs on standard output. +-- @param results table: A table where keys are package names and versions +-- are tables matching version strings to an array of rocks servers. +-- @param porcelain boolean or nil: A flag to force machine-friendly output. +function search.print_results(results, porcelain) + assert(type(results) == "table") + assert(type(porcelain) == "boolean" or not porcelain) + + for package, versions in util.sortedpairs(results) do + if not porcelain then + util.printout(package) + end + for version, repos in util.sortedpairs(versions, deps.compare_versions) do + for _, repo in ipairs(repos) do + repo.repo = dir.normalize(repo.repo) + if porcelain then + util.printout(package, version, repo.arch, repo.repo) + else + util.printout(" "..version.." ("..repo.arch..") - "..repo.repo) + end + end + end + if not porcelain then + util.printout() + end + end +end + +--- Splits a list of search results into two lists, one for "source" results +-- to be used with the "build" command, and one for "binary" results to be +-- used with the "install" command. +-- @param results table: A search results table. +-- @return (table, table): Two tables, one for source and one for binary +-- results. +local function split_source_and_binary_results(results) + local sources, binaries = {}, {} + for name, versions in pairs(results) do + for version, repositories in pairs(versions) do + for _, repo in ipairs(repositories) do + local where = sources + if repo.arch == "all" or repo.arch == cfg.arch then + where = binaries + end + store_result(where, name, version, repo.arch, repo.repo) + end + end + end + return sources, binaries +end + +--- Given a name and optionally a version, try to find in the rocks +-- servers a single .src.rock or .rockspec file that satisfies +-- the request, and run the given function on it; or display to the +-- user possibilities if it couldn't narrow down a single match. +-- @param action function: A function that takes a .src.rock or +-- .rockspec URL as a parameter. +-- @param name string: A rock name +-- @param version string or nil: A version number may also be given. +-- @return The result of the action function, or nil and an error message. +function search.act_on_src_or_rockspec(action, name, version, ...) + assert(type(action) == "function") + assert(type(name) == "string") + assert(type(version) == "string" or not version) + + local query = search.make_query(name, version) + query.arch = "src|rockspec" + local url, err = search.find_suitable_rock(query) + if not url then + return nil, "Could not find a result named "..name..(version and " "..version or "")..": "..err + end + return action(url, ...) +end + +function search.pick_installed_rock(name, version, given_tree) + local results = {} + local query = search.make_query(name, version) + query.exact_name = true + local tree_map = {} + local trees = cfg.rocks_trees + if given_tree then + trees = { given_tree } + end + for _, tree in ipairs(trees) do + local rocks_dir = path.rocks_dir(tree) + tree_map[rocks_dir] = tree + search.manifest_search(results, rocks_dir, query) + end + + if not next(results) then -- + return nil,"cannot find package "..name.." "..(version or "").."\nUse 'list' to find installed rocks." + end + + version = nil + local repo_url + local package, versions = util.sortedpairs(results)() + --question: what do we do about multiple versions? This should + --give us the latest version on the last repo (which is usually the global one) + for vs, repositories in util.sortedpairs(versions, deps.compare_versions) do + if not version then version = vs end + for _, rp in ipairs(repositories) do repo_url = rp.repo end + end + + local repo = tree_map[repo_url] + return name, version, repo, repo_url +end + +--- Driver function for "search" command. +-- @param name string: A substring of a rock name to search. +-- @param version string or nil: a version may also be passed. +-- @return boolean or (nil, string): True if build was successful; nil and an +-- error message otherwise. +function search.command(flags, name, version) + if flags["all"] then + name, version = "", nil + end + + if type(name) ~= "string" and not flags["all"] then + return nil, "Enter name and version or use --all. "..util.see_help("search") + end + + local query = search.make_query(name:lower(), version) + query.exact_name = false + local results, err = search.search_repos(query) + local porcelain = flags["porcelain"] + util.title("Search results:", porcelain, "=") + local sources, binaries = split_source_and_binary_results(results) + if next(sources) and not flags["binary"] then + util.title("Rockspecs and source rocks:", porcelain) + search.print_results(sources, porcelain) + end + if next(binaries) and not flags["source"] then + util.title("Binary and pure-Lua rocks:", porcelain) + search.print_results(binaries, porcelain) + end + return true +end + +return search diff --git a/Utils/luarocks/lua/luarocks/show.lua b/Utils/luarocks/lua/luarocks/show.lua new file mode 100644 index 000000000..85c7edcbd --- /dev/null +++ b/Utils/luarocks/lua/luarocks/show.lua @@ -0,0 +1,152 @@ +--- Module implementing the LuaRocks "show" command. +-- Shows information about an installed rock. +local show = {} +package.loaded["luarocks.show"] = show + +local search = require("luarocks.search") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local path = require("luarocks.path") +local deps = require("luarocks.deps") +local fetch = require("luarocks.fetch") +local manif = require("luarocks.manif") + +util.add_run_function(show) +show.help_summary = "Show information about an installed rock." + +show.help = [[ + is an existing package name. +Without any flags, show all module information. +With these flags, return only the desired information: + +--home home page of project +--modules all modules provided by this package as used by require() +--deps packages this package depends on +--rockspec the full path of the rockspec file +--mversion the package version +--rock-tree local tree where rock is installed +--rock-dir data directory of the installed rock +]] + +local function keys_as_string(t, sep) + local keys = util.keys(t) + table.sort(keys) + return table.concat(keys, sep or " ") +end + +local function word_wrap(line) + local width = tonumber(os.getenv("COLUMNS")) or 80 + if width > 80 then width = 80 end + if #line > width then + local brk = width + while brk > 0 and line:sub(brk, brk) ~= " " do + brk = brk - 1 + end + if brk > 0 then + return line:sub(1, brk-1) .. "\n" .. word_wrap(line:sub(brk+1)) + end + end + return line +end + +local function format_text(text) + text = text:gsub("^%s*",""):gsub("%s$", ""):gsub("\n[ \t]+","\n"):gsub("([^\n])\n([^\n])","%1 %2") + local paragraphs = util.split_string(text, "\n\n") + for n, line in ipairs(paragraphs) do + paragraphs[n] = word_wrap(line) + end + return (table.concat(paragraphs, "\n\n"):gsub("%s$", "")) +end + +local function installed_rock_label(name, tree) + local installed, version + if cfg.rocks_provided[name] then + installed, version = true, cfg.rocks_provided[name] + else + installed, version = search.pick_installed_rock(name, nil, tree) + end + return installed and "(using "..version..")" or "(missing)" +end + +--- Driver function for "show" command. +-- @param name or nil: an existing package name. +-- @param version string or nil: a version may also be passed. +-- @return boolean: True if succeeded, nil on errors. +function show.command(flags, name, version) + if not name then + return nil, "Argument missing. "..util.see_help("show") + end + + local repo, repo_url + name, version, repo, repo_url = search.pick_installed_rock(name:lower(), version, flags["tree"]) + if not name then + return nil, version + end + + local directory = path.install_dir(name,version,repo) + local rockspec_file = path.rockspec_file(name, version, repo) + local rockspec, err = fetch.load_local_rockspec(rockspec_file) + if not rockspec then return nil,err end + + local descript = rockspec.description or {} + local manifest, err = manif.load_manifest(repo_url) + if not manifest then return nil,err end + local minfo = manifest.repository[name][version][1] + + if flags["rock-tree"] then util.printout(path.rocks_tree_to_string(repo)) + elseif flags["rock-dir"] then util.printout(directory) + elseif flags["home"] then util.printout(descript.homepage) + elseif flags["modules"] then util.printout(keys_as_string(minfo.modules, "\n")) + elseif flags["deps"] then util.printout(keys_as_string(minfo.dependencies)) + elseif flags["rockspec"] then util.printout(rockspec_file) + elseif flags["mversion"] then util.printout(version) + else + util.printout() + util.printout(rockspec.package.." "..rockspec.version.." - "..(descript.summary or "")) + util.printout() + if descript.detailed then + util.printout(format_text(descript.detailed)) + util.printout() + end + if descript.license then + util.printout("License: ", descript.license) + end + if descript.homepage then + util.printout("Homepage: ", descript.homepage) + end + util.printout("Installed in: ", path.rocks_tree_to_string(repo)) + if next(minfo.modules) then + util.printout() + util.printout("Modules:") + for mod, filename in util.sortedpairs(minfo.modules) do + util.printout("\t"..mod.." ("..path.which(mod, filename, name, version, repo, manifest)..")") + end + end + local direct_deps = {} + if #rockspec.dependencies > 0 then + util.printout() + util.printout("Depends on:") + for _, dep in ipairs(rockspec.dependencies) do + direct_deps[dep.name] = true + util.printout("\t"..deps.show_dep(dep).." "..installed_rock_label(dep.name, flags["tree"])) + end + end + local has_indirect_deps + for dep_name in util.sortedpairs(minfo.dependencies) do + if not direct_deps[dep_name] then + if not has_indirect_deps then + util.printout() + util.printout("Indirectly pulling:") + has_indirect_deps = true + end + + util.printout("\t"..dep_name.." "..installed_rock_label(dep_name, flags["tree"])) + end + end + util.printout() + end + return true +end + + +return show diff --git a/Utils/luarocks/lua/luarocks/site_config_5_1.lua b/Utils/luarocks/lua/luarocks/site_config_5_1.lua new file mode 100644 index 000000000..85ab3ddf4 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/site_config_5_1.lua @@ -0,0 +1,14 @@ +local site_config = {} +site_config.LUA_INCDIR=[[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\include]] +site_config.LUA_LIBDIR=[[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks]] +site_config.LUA_BINDIR=[[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks]] +site_config.LUA_INTERPRETER=[[lua5.1]] +site_config.LUAROCKS_UNAME_S=[[MINGW]] +site_config.LUAROCKS_UNAME_M=[[x86]] +site_config.LUAROCKS_ROCKS_TREE=[[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\systree]] +site_config.LUAROCKS_PREFIX=[[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks]] +site_config.LUAROCKS_DOWNLOADER=[[wget]] +site_config.LUAROCKS_MD5CHECKER=[[md5sum]] +site_config.LUAROCKS_FORCE_CONFIG=true +site_config.LUAROCKS_SYSCONFDIR=[[C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks]] +return site_config diff --git a/Utils/luarocks/lua/luarocks/tools/patch.lua b/Utils/luarocks/lua/luarocks/tools/patch.lua new file mode 100644 index 000000000..44d00ef89 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/tools/patch.lua @@ -0,0 +1,700 @@ +--- Patch utility to apply unified diffs. +-- +-- http://lua-users.org/wiki/LuaPatch +-- +-- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license). +-- Code is heavilly based on the Python-based patch.py version 8.06-1 +-- Copyright (c) 2008 rainforce.org, MIT License +-- Project home: http://code.google.com/p/python-patch/ . +-- Version 0.1 + +local patch = {} + +local fs = require("luarocks.fs") +local util = require("luarocks.util") + +local io = io +local os = os +local string = string +local table = table +local format = string.format + +-- logging +local debugmode = false +local function debug(_) end +local function info(_) end +local function warning(s) io.stderr:write(s .. '\n') end + +-- Returns boolean whether string s2 starts with string s. +local function startswith(s, s2) + return s:sub(1, #s2) == s2 +end + +-- Returns boolean whether string s2 ends with string s. +local function endswith(s, s2) + return #s >= #s2 and s:sub(#s-#s2+1) == s2 +end + +-- Returns string s after filtering out any new-line characters from end. +local function endlstrip(s) + return s:gsub('[\r\n]+$', '') +end + +-- Returns shallow copy of table t. +local function table_copy(t) + local t2 = {} + for k,v in pairs(t) do t2[k] = v end + return t2 +end + +local function exists(filename) + local fh = io.open(filename) + local result = fh ~= nil + if fh then fh:close() end + return result +end +local function isfile() return true end --FIX? + +local function read_file(filename) + local fh, data, err, oserr + fh, err, oserr = io.open(filename, 'rb') + if not fh then return fh, err, oserr end + data, err, oserr = fh:read'*a' + fh:close() + if not data then return nil, err, oserr end + return data +end + +local function write_file(filename, data) + local fh, status, err, oserr + fh, err, oserr = io.open(filename 'wb') + if not fh then return fh, err, oserr end + status, err, oserr = fh:write(data) + fh:close() + if not status then return nil, err, oserr end + return true +end + +local function file_copy(src, dest) + local data, status, err, oserr + data, err, oserr = read_file(src) + if not data then return data, err, oserr end + status, err, oserr = write_file(dest) + if not status then return status, err, oserr end + return true +end + +local function string_as_file(s) + return { + at = 0, + str = s, + len = #s, + eof = false, + read = function(self, n) + if self.eof then return nil end + local chunk = self.str:sub(self.at, self.at + n - 1) + self.at = self.at + n + if self.at > self.len then + self.eof = true + end + return chunk + end, + close = function(self) + self.eof = true + end, + } +end + +-- +-- file_lines(f) is similar to f:lines() for file f. +-- The main difference is that read_lines includes +-- new-line character sequences ("\n", "\r\n", "\r"), +-- if any, at the end of each line. Embedded "\0" are also handled. +-- Caution: The newline behavior can depend on whether f is opened +-- in binary or ASCII mode. +-- (file_lines - version 20080913) +-- +local function file_lines(f) + local CHUNK_SIZE = 1024 + local buffer = "" + local pos_beg = 1 + return function() + local pos, chars + while 1 do + pos, chars = buffer:match('()([\r\n].)', pos_beg) + if pos or not f then + break + elseif f then + local chunk = f:read(CHUNK_SIZE) + if chunk then + buffer = buffer:sub(pos_beg) .. chunk + pos_beg = 1 + else + f = nil + end + end + end + if not pos then + pos = #buffer + elseif chars == '\r\n' then + pos = pos + 1 + end + local line = buffer:sub(pos_beg, pos) + pos_beg = pos + 1 + if #line > 0 then + return line + end + end +end + +local function match_linerange(line) + local m1, m2, m3, m4 = line:match("^@@ %-(%d+),(%d+) %+(%d+),(%d+)") + if not m1 then m1, m3, m4 = line:match("^@@ %-(%d+) %+(%d+),(%d+)") end + if not m1 then m1, m2, m3 = line:match("^@@ %-(%d+),(%d+) %+(%d+)") end + if not m1 then m1, m3 = line:match("^@@ %-(%d+) %+(%d+)") end + return m1, m2, m3, m4 +end + +function patch.read_patch(filename, data) + -- define possible file regions that will direct the parser flow + local state = 'header' + -- 'header' - comments before the patch body + -- 'filenames' - lines starting with --- and +++ + -- 'hunkhead' - @@ -R +R @@ sequence + -- 'hunkbody' + -- 'hunkskip' - skipping invalid hunk mode + + local all_ok = true + local lineends = {lf=0, crlf=0, cr=0} + local files = {source={}, target={}, hunks={}, fileends={}, hunkends={}} + local nextfileno = 0 + local nexthunkno = 0 --: even if index starts with 0 user messages + -- number hunks from 1 + + -- hunkinfo holds parsed values, hunkactual - calculated + local hunkinfo = { + startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil, + invalid=false, text={} + } + local hunkactual = {linessrc=nil, linestgt=nil} + + info(format("reading patch %s", filename)) + + local fp + if data then + fp = string_as_file(data) + else + fp = filename == '-' and io.stdin or assert(io.open(filename, "rb")) + end + local lineno = 0 + + for line in file_lines(fp) do + lineno = lineno + 1 + if state == 'header' then + if startswith(line, "--- ") then + state = 'filenames' + end + -- state is 'header' or 'filenames' + end + if state == 'hunkbody' then + -- skip hunkskip and hunkbody code until definition of hunkhead read + + if line:match"^[\r\n]*$" then + -- prepend space to empty lines to interpret them as context properly + line = " " .. line + end + + -- process line first + if line:match"^[- +\\]" then + -- gather stats about line endings + local he = files.hunkends[nextfileno] + if endswith(line, "\r\n") then + he.crlf = he.crlf + 1 + elseif endswith(line, "\n") then + he.lf = he.lf + 1 + elseif endswith(line, "\r") then + he.cr = he.cr + 1 + end + if startswith(line, "-") then + hunkactual.linessrc = hunkactual.linessrc + 1 + elseif startswith(line, "+") then + hunkactual.linestgt = hunkactual.linestgt + 1 + elseif startswith(line, "\\") then + -- nothing + else + hunkactual.linessrc = hunkactual.linessrc + 1 + hunkactual.linestgt = hunkactual.linestgt + 1 + end + table.insert(hunkinfo.text, line) + -- todo: handle \ No newline cases + else + warning(format("invalid hunk no.%d at %d for target file %s", + nexthunkno, lineno, files.target[nextfileno])) + -- add hunk status node + table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) + files.hunks[nextfileno][nexthunkno].invalid = true + all_ok = false + state = 'hunkskip' + end + + -- check exit conditions + if hunkactual.linessrc > hunkinfo.linessrc or + hunkactual.linestgt > hunkinfo.linestgt + then + warning(format("extra hunk no.%d lines at %d for target %s", + nexthunkno, lineno, files.target[nextfileno])) + -- add hunk status node + table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) + files.hunks[nextfileno][nexthunkno].invalid = true + state = 'hunkskip' + elseif hunkinfo.linessrc == hunkactual.linessrc and + hunkinfo.linestgt == hunkactual.linestgt + then + table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) + state = 'hunkskip' + + -- detect mixed window/unix line ends + local ends = files.hunkends[nextfileno] + if (ends.cr~=0 and 1 or 0) + (ends.crlf~=0 and 1 or 0) + + (ends.lf~=0 and 1 or 0) > 1 + then + warning(format("inconsistent line ends in patch hunks for %s", + files.source[nextfileno])) + end + if debugmode then + local debuglines = {crlf=ends.crlf, lf=ends.lf, cr=ends.cr, + file=files.target[nextfileno], hunk=nexthunkno} + debug(format("crlf: %(crlf)d lf: %(lf)d cr: %(cr)d\t " .. + "- file: %(file)s hunk: %(hunk)d", debuglines)) + end + end + -- state is 'hunkbody' or 'hunkskip' + end + + if state == 'hunkskip' then + if match_linerange(line) then + state = 'hunkhead' + elseif startswith(line, "--- ") then + state = 'filenames' + if debugmode and #files.source > 0 then + debug(format("- %2d hunks for %s", #files.hunks[nextfileno], + files.source[nextfileno])) + end + end + -- state is 'hunkskip', 'hunkhead', or 'filenames' + end + local advance + if state == 'filenames' then + if startswith(line, "--- ") then + if util.array_contains(files.source, nextfileno) then + all_ok = false + warning(format("skipping invalid patch for %s", + files.source[nextfileno+1])) + table.remove(files.source, nextfileno+1) + -- double source filename line is encountered + -- attempt to restart from this second line + end + -- Accept a space as a terminator, like GNU patch does. + -- Breaks patches containing filenames with spaces... + -- FIXME Figure out what does GNU patch do in those cases. + local match = line:match("^%-%-%- ([^ \t\r\n]+)") + if not match then + all_ok = false + warning(format("skipping invalid filename at line %d", lineno+1)) + state = 'header' + else + table.insert(files.source, match) + end + elseif not startswith(line, "+++ ") then + if util.array_contains(files.source, nextfileno) then + all_ok = false + warning(format("skipping invalid patch with no target for %s", + files.source[nextfileno+1])) + table.remove(files.source, nextfileno+1) + else + -- this should be unreachable + warning("skipping invalid target patch") + end + state = 'header' + else + if util.array_contains(files.target, nextfileno) then + all_ok = false + warning(format("skipping invalid patch - double target at line %d", + lineno+1)) + table.remove(files.source, nextfileno+1) + table.remove(files.target, nextfileno+1) + nextfileno = nextfileno - 1 + -- double target filename line is encountered + -- switch back to header state + state = 'header' + else + -- Accept a space as a terminator, like GNU patch does. + -- Breaks patches containing filenames with spaces... + -- FIXME Figure out what does GNU patch do in those cases. + local re_filename = "^%+%+%+ ([^ \t\r\n]+)" + local match = line:match(re_filename) + if not match then + all_ok = false + warning(format( + "skipping invalid patch - no target filename at line %d", + lineno+1)) + state = 'header' + else + table.insert(files.target, match) + nextfileno = nextfileno + 1 + nexthunkno = 0 + table.insert(files.hunks, {}) + table.insert(files.hunkends, table_copy(lineends)) + table.insert(files.fileends, table_copy(lineends)) + state = 'hunkhead' + advance = true + end + end + end + -- state is 'filenames', 'header', or ('hunkhead' with advance) + end + if not advance and state == 'hunkhead' then + local m1, m2, m3, m4 = match_linerange(line) + if not m1 then + if not util.array_contains(files.hunks, nextfileno-1) then + all_ok = false + warning(format("skipping invalid patch with no hunks for file %s", + files.target[nextfileno])) + end + state = 'header' + else + hunkinfo.startsrc = tonumber(m1) + hunkinfo.linessrc = tonumber(m2 or 1) + hunkinfo.starttgt = tonumber(m3) + hunkinfo.linestgt = tonumber(m4 or 1) + hunkinfo.invalid = false + hunkinfo.text = {} + + hunkactual.linessrc = 0 + hunkactual.linestgt = 0 + + state = 'hunkbody' + nexthunkno = nexthunkno + 1 + end + -- state is 'header' or 'hunkbody' + end + end + if state ~= 'hunkskip' then + warning(format("patch file incomplete - %s", filename)) + all_ok = false + -- os.exit(?) + else + -- duplicated message when an eof is reached + if debugmode and #files.source > 0 then + debug(format("- %2d hunks for %s", #files.hunks[nextfileno], + files.source[nextfileno])) + end + end + + local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end + info(format("total files: %d total hunks: %d", #files.source, sum)) + fp:close() + return files, all_ok +end + +local function find_hunk(file, h, hno) + for fuzz=0,2 do + local lineno = h.startsrc + for i=0,#file do + local found = true + local location = lineno + for l, hline in ipairs(h.text) do + if l > fuzz then + -- todo: \ No newline at the end of file + if startswith(hline, " ") or startswith(hline, "-") then + local line = file[lineno] + lineno = lineno + 1 + if not line or #line == 0 then + found = false + break + end + if endlstrip(line) ~= endlstrip(hline:sub(2)) then + found = false + break + end + end + end + end + if found then + local offset = location - h.startsrc - fuzz + if offset ~= 0 then + warning(format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or format(" (fuzz %d)", fuzz))) + end + h.startsrc = location + h.starttgt = h.starttgt + offset + for _=1,fuzz do + table.remove(h.text, 1) + table.remove(h.text, #h.text) + end + return true + end + lineno = i + end + end + return false +end + +local function load_file(filename) + local fp = assert(io.open(filename)) + local file = {} + local readline = file_lines(fp) + while true do + local line = readline() + if not line then break end + table.insert(file, line) + end + fp:close() + return file +end + +local function find_hunks(file, hunks) + for hno, h in ipairs(hunks) do + find_hunk(file, h, hno) + end +end + +local function check_patched(file, hunks) + local lineno = 1 + local ok, err = pcall(function() + if #file == 0 then + error('nomatch', 0) + end + for hno, h in ipairs(hunks) do + -- skip to line just before hunk starts + if #file < h.starttgt then + error('nomatch', 0) + end + lineno = h.starttgt + for _, hline in ipairs(h.text) do + -- todo: \ No newline at the end of file + if not startswith(hline, "-") and not startswith(hline, "\\") then + local line = file[lineno] + lineno = lineno + 1 + if #line == 0 then + error('nomatch', 0) + end + if endlstrip(line) ~= endlstrip(hline:sub(2)) then + warning(format("file is not patched - failed hunk: %d", hno)) + error('nomatch', 0) + end + end + end + end + end) + -- todo: display failed hunk, i.e. expected/found + return err ~= 'nomatch' +end + +local function patch_hunks(srcname, tgtname, hunks) + local src = assert(io.open(srcname, "rb")) + local tgt = assert(io.open(tgtname, "wb")) + + local src_readline = file_lines(src) + + -- todo: detect linefeeds early - in apply_files routine + -- to handle cases when patch starts right from the first + -- line and no lines are processed. At the moment substituted + -- lineends may not be the same at the start and at the end + -- of patching. Also issue a warning about mixed lineends + + local srclineno = 1 + local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0} + for hno, h in ipairs(hunks) do + debug(format("processing hunk %d for file %s", hno, tgtname)) + -- skip to line just before hunk starts + while srclineno < h.startsrc do + local line = src_readline() + -- Python 'U' mode works only with text files + if endswith(line, "\r\n") then + lineends["\r\n"] = lineends["\r\n"] + 1 + elseif endswith(line, "\n") then + lineends["\n"] = lineends["\n"] + 1 + elseif endswith(line, "\r") then + lineends["\r"] = lineends["\r"] + 1 + end + tgt:write(line) + srclineno = srclineno + 1 + end + + for _,hline in ipairs(h.text) do + -- todo: check \ No newline at the end of file + if startswith(hline, "-") or startswith(hline, "\\") then + src_readline() + srclineno = srclineno + 1 + else + if not startswith(hline, "+") then + src_readline() + srclineno = srclineno + 1 + end + local line2write = hline:sub(2) + -- detect if line ends are consistent in source file + local sum = 0 + for _,v in pairs(lineends) do if v > 0 then sum=sum+1 end end + if sum == 1 then + local newline + for k,v in pairs(lineends) do if v ~= 0 then newline = k end end + tgt:write(endlstrip(line2write) .. newline) + else -- newlines are mixed or unknown + tgt:write(line2write) + end + end + end + end + for line in src_readline do + tgt:write(line) + end + tgt:close() + src:close() + return true +end + +local function strip_dirs(filename, strip) + if strip == nil then return filename end + for _=1,strip do + filename=filename:gsub("^[^/]*/", "") + end + return filename +end + +function patch.apply_patch(the_patch, strip) + local all_ok = true + local total = #the_patch.source + for fileno, filename in ipairs(the_patch.source) do + filename = strip_dirs(filename, strip) + local continue + local f2patch = filename + if not exists(f2patch) then + f2patch = strip_dirs(the_patch.target[fileno], strip) + f2patch = fs.absolute_name(f2patch) + if not exists(f2patch) then --FIX:if f2patch nil + warning(format("source/target file does not exist\n--- %s\n+++ %s", + filename, f2patch)) + all_ok = false + continue = true + end + end + if not continue and not isfile(f2patch) then + warning(format("not a file - %s", f2patch)) + all_ok = false + continue = true + end + if not continue then + + filename = f2patch + + info(format("processing %d/%d:\t %s", fileno, total, filename)) + + -- validate before patching + local hunks = the_patch.hunks[fileno] + local file = load_file(filename) + local hunkno = 1 + local hunk = hunks[hunkno] + local hunkfind = {} + local validhunks = 0 + local canpatch = false + local hunklineno + local isbreak + local lineno = 0 + + find_hunks(file, hunks) + + for _, line in ipairs(file) do + lineno = lineno + 1 + local continue + if not hunk or lineno < hunk.startsrc then + continue = true + elseif lineno == hunk.startsrc then + hunkfind = {} + for _,x in ipairs(hunk.text) do + if x:sub(1,1) == ' ' or x:sub(1,1) == '-' then + hunkfind[#hunkfind+1] = endlstrip(x:sub(2)) + end + end + hunklineno = 1 + + -- todo \ No newline at end of file + end + -- check hunks in source file + if not continue and lineno < hunk.startsrc + #hunkfind - 1 then + if endlstrip(line) == hunkfind[hunklineno] then + hunklineno = hunklineno + 1 + else + debug(format("hunk no.%d doesn't match source file %s", + hunkno, filename)) + -- file may be already patched, but check other hunks anyway + hunkno = hunkno + 1 + if hunkno <= #hunks then + hunk = hunks[hunkno] + continue = true + else + isbreak = true; break + end + end + end + -- check if processed line is the last line + if not continue and lineno == hunk.startsrc + #hunkfind - 1 then + debug(format("file %s hunk no.%d -- is ready to be patched", + filename, hunkno)) + hunkno = hunkno + 1 + validhunks = validhunks + 1 + if hunkno <= #hunks then + hunk = hunks[hunkno] + else + if validhunks == #hunks then + -- patch file + canpatch = true + isbreak = true; break + end + end + end + end + if not isbreak then + if hunkno <= #hunks then + warning(format("premature end of source file %s at hunk %d", + filename, hunkno)) + all_ok = false + end + end + if validhunks < #hunks then + if check_patched(file, hunks) then + warning(format("already patched %s", filename)) + else + warning(format("source file is different - %s", filename)) + all_ok = false + end + end + if canpatch then + local backupname = filename .. ".orig" + if exists(backupname) then + warning(format("can't backup original file to %s - aborting", + backupname)) + all_ok = false + else + assert(os.rename(filename, backupname)) + if patch_hunks(backupname, filename, hunks) then + warning(format("successfully patched %s", filename)) + assert(os.remove(backupname)) + else + warning(format("error patching file %s", filename)) + assert(file_copy(filename, filename .. ".invalid")) + warning(format("invalid version is saved to %s", + filename .. ".invalid")) + -- todo: proper rejects + assert(os.rename(backupname, filename)) + all_ok = false + end + end + end + + end -- if not continue + end -- for + -- todo: check for premature eof + return all_ok +end + +return patch diff --git a/Utils/luarocks/lua/luarocks/tools/tar.lua b/Utils/luarocks/lua/luarocks/tools/tar.lua new file mode 100644 index 000000000..637a6c953 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/tools/tar.lua @@ -0,0 +1,150 @@ + +--- A pure-Lua implementation of untar (unpacking .tar archives) +local tar = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +local blocksize = 512 + +local function get_typeflag(flag) + if flag == "0" or flag == "\0" then return "file" + elseif flag == "1" then return "link" + elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU + elseif flag == "3" then return "character" + elseif flag == "4" then return "block" + elseif flag == "5" then return "directory" + elseif flag == "6" then return "fifo" + elseif flag == "7" then return "contiguous" -- "reserved" in POSIX, "contiguous" in GNU + elseif flag == "x" then return "next file" + elseif flag == "g" then return "global extended header" + elseif flag == "L" then return "long name" + elseif flag == "K" then return "long link name" + end + return "unknown" +end + +local function octal_to_number(octal) + local exp = 0 + local number = 0 + for i = #octal,1,-1 do + local digit = tonumber(octal:sub(i,i)) + if digit then + number = number + (digit * 8^exp) + exp = exp + 1 + end + end + return number +end + +local function checksum_header(block) + local sum = 256 + for i = 1,148 do + sum = sum + block:byte(i) + end + for i = 157,500 do + sum = sum + block:byte(i) + end + return sum +end + +local function nullterm(s) + return s:match("^[^%z]*") +end + +local function read_header_block(block) + local header = {} + header.name = nullterm(block:sub(1,100)) + header.mode = nullterm(block:sub(101,108)) + header.uid = octal_to_number(nullterm(block:sub(109,116))) + header.gid = octal_to_number(nullterm(block:sub(117,124))) + header.size = octal_to_number(nullterm(block:sub(125,136))) + header.mtime = octal_to_number(nullterm(block:sub(137,148))) + header.chksum = octal_to_number(nullterm(block:sub(149,156))) + header.typeflag = get_typeflag(block:sub(157,157)) + header.linkname = nullterm(block:sub(158,257)) + header.magic = block:sub(258,263) + header.version = block:sub(264,265) + header.uname = nullterm(block:sub(266,297)) + header.gname = nullterm(block:sub(298,329)) + header.devmajor = octal_to_number(nullterm(block:sub(330,337))) + header.devminor = octal_to_number(nullterm(block:sub(338,345))) + header.prefix = block:sub(346,500) + if header.magic ~= "ustar " and header.magic ~= "ustar\0" then + return false, "Invalid header magic "..header.magic + end + if header.version ~= "00" and header.version ~= " \0" then + return false, "Unknown version "..header.version + end + if not checksum_header(block) == header.chksum then + return false, "Failed header checksum" + end + return header +end + +function tar.untar(filename, destdir) + assert(type(filename) == "string") + assert(type(destdir) == "string") + + local tar_handle = io.open(filename, "r") + if not tar_handle then return nil, "Error opening file "..filename end + + local long_name, long_link_name + while true do + local block + repeat + block = tar_handle:read(blocksize) + until (not block) or checksum_header(block) > 256 + if not block then break end + local header, err = read_header_block(block) + if not header then + util.printerr(err) + end + + local file_data = tar_handle:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) + + if header.typeflag == "long name" then + long_name = nullterm(file_data) + elseif header.typeflag == "long link name" then + long_link_name = nullterm(file_data) + else + if long_name then + header.name = long_name + long_name = nil + end + if long_link_name then + header.name = long_link_name + long_link_name = nil + end + end + local pathname = dir.path(destdir, header.name) + if header.typeflag == "directory" then + local ok, err = fs.make_dir(pathname) + if not ok then return nil, err end + elseif header.typeflag == "file" then + local dirname = dir.dir_name(pathname) + if dirname ~= "" then + local ok, err = fs.make_dir(dirname) + if not ok then return nil, err end + end + local file_handle = io.open(pathname, "wb") + file_handle:write(file_data) + file_handle:close() + fs.set_time(pathname, header.mtime) + if fs.chmod then + fs.chmod(pathname, header.mode) + end + end + --[[ + for k,v in pairs(header) do + util.printout("[\""..tostring(k).."\"] = "..(type(v)=="number" and v or "\""..v:gsub("%z", "\\0").."\"")) + end + util.printout() + --]] + end + tar_handle:close() + return true +end + +return tar diff --git a/Utils/luarocks/lua/luarocks/tools/zip.lua b/Utils/luarocks/lua/luarocks/tools/zip.lua new file mode 100644 index 000000000..e6d9e36ae --- /dev/null +++ b/Utils/luarocks/lua/luarocks/tools/zip.lua @@ -0,0 +1,264 @@ + +--- A Lua implementation of .zip file archiving (used for creating .rock files), +-- using only lzlib or lua-lzib. +local zip = {} + +local zlib = require("zlib") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +-- zlib module can be provided by both lzlib and lua-lzib packages. +-- Create a compatibility layer. +local zlib_compress, zlib_crc32 +if zlib._VERSION:match "^lua%-zlib" then + function zlib_compress(data) + return (zlib.deflate()(data, "finish")) + end + + function zlib_crc32(data) + return zlib.crc32()(data) + end +elseif zlib._VERSION:match "^lzlib" then + function zlib_compress(data) + return zlib.compress(data) + end + + function zlib_crc32(data) + return zlib.crc32(zlib.crc32(), data) + end +else + error("unknown zlib library", 0) +end + +local function number_to_bytestring(number, nbytes) + local out = {} + for _ = 1, nbytes do + local byte = number % 256 + table.insert(out, string.char(byte)) + number = (number - byte) / 256 + end + return table.concat(out) +end + +--- Begin a new file to be stored inside the zipfile. +-- @param self handle of the zipfile being written. +-- @param filename filenome of the file to be added to the zipfile. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_open_new_file_in_zip(self, filename) + if self.in_open_file then + self:close_file_in_zip() + return nil + end + local lfh = {} + self.local_file_header = lfh + lfh.last_mod_file_time = 0 -- TODO + lfh.last_mod_file_date = 0 -- TODO + lfh.file_name_length = #filename + lfh.extra_field_length = 0 + lfh.file_name = filename:gsub("\\", "/") + lfh.external_attr = 0 -- TODO properly store permissions + self.in_open_file = true + return true +end + +--- Write data to the file currently being stored in the zipfile. +-- @param self handle of the zipfile being written. +-- @param data string containing full contents of the file. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_write_file_in_zip(self, data) + if not self.in_open_file then + return nil + end + local lfh = self.local_file_header + local compressed = zlib_compress(data):sub(3, -5) + lfh.crc32 = zlib_crc32(data) + lfh.compressed_size = #compressed + lfh.uncompressed_size = #data + self.data = compressed + return true +end + +--- Complete the writing of a file stored in the zipfile. +-- @param self handle of the zipfile being written. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_close_file_in_zip(self) + local zh = self.ziphandle + + if not self.in_open_file then + return nil + end + + -- Local file header + local lfh = self.local_file_header + lfh.offset = zh:seek() + zh:write(number_to_bytestring(0x04034b50, 4)) -- signature + zh:write(number_to_bytestring(20, 2)) -- version needed to extract: 2.0 + zh:write(number_to_bytestring(0, 2)) -- general purpose bit flag + zh:write(number_to_bytestring(8, 2)) -- compression method: deflate + zh:write(number_to_bytestring(lfh.last_mod_file_time, 2)) + zh:write(number_to_bytestring(lfh.last_mod_file_date, 2)) + zh:write(number_to_bytestring(lfh.crc32, 4)) + zh:write(number_to_bytestring(lfh.compressed_size, 4)) + zh:write(number_to_bytestring(lfh.uncompressed_size, 4)) + zh:write(number_to_bytestring(lfh.file_name_length, 2)) + zh:write(number_to_bytestring(lfh.extra_field_length, 2)) + zh:write(lfh.file_name) + + -- File data + zh:write(self.data) + + -- Data descriptor + zh:write(number_to_bytestring(lfh.crc32, 4)) + zh:write(number_to_bytestring(lfh.compressed_size, 4)) + zh:write(number_to_bytestring(lfh.uncompressed_size, 4)) + + table.insert(self.files, lfh) + self.in_open_file = false + + return true +end + +-- @return boolean or (boolean, string): true on success, +-- false and an error message on failure. +local function zipwriter_add(self, file) + local fin + local ok, err = self:open_new_file_in_zip(file) + if not ok then + err = "error in opening "..file.." in zipfile" + else + fin = io.open(fs.absolute_name(file), "rb") + if not fin then + ok = false + err = "error opening "..file.." for reading" + end + end + if ok then + local data = fin:read("*a") + if not data then + err = "error reading "..file + ok = false + else + ok = self:write_file_in_zip(data) + if not ok then + err = "error in writing "..file.." in the zipfile" + end + end + end + if fin then + fin:close() + end + if ok then + ok = self:close_file_in_zip() + if not ok then + err = "error in writing "..file.." in the zipfile" + end + end + return ok == true, err +end + +--- Complete the writing of the zipfile. +-- @param self handle of the zipfile being written. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_close(self) + local zh = self.ziphandle + + local central_directory_offset = zh:seek() + + local size_of_central_directory = 0 + -- Central directory structure + for _, lfh in ipairs(self.files) do + zh:write(number_to_bytestring(0x02014b50, 4)) -- signature + zh:write(number_to_bytestring(3, 2)) -- version made by: UNIX + zh:write(number_to_bytestring(20, 2)) -- version needed to extract: 2.0 + zh:write(number_to_bytestring(0, 2)) -- general purpose bit flag + zh:write(number_to_bytestring(8, 2)) -- compression method: deflate + zh:write(number_to_bytestring(lfh.last_mod_file_time, 2)) + zh:write(number_to_bytestring(lfh.last_mod_file_date, 2)) + zh:write(number_to_bytestring(lfh.crc32, 4)) + zh:write(number_to_bytestring(lfh.compressed_size, 4)) + zh:write(number_to_bytestring(lfh.uncompressed_size, 4)) + zh:write(number_to_bytestring(lfh.file_name_length, 2)) + zh:write(number_to_bytestring(lfh.extra_field_length, 2)) + zh:write(number_to_bytestring(0, 2)) -- file comment length + zh:write(number_to_bytestring(0, 2)) -- disk number start + zh:write(number_to_bytestring(0, 2)) -- internal file attributes + zh:write(number_to_bytestring(lfh.external_attr, 4)) -- external file attributes + zh:write(number_to_bytestring(lfh.offset, 4)) -- relative offset of local header + zh:write(lfh.file_name) + size_of_central_directory = size_of_central_directory + 46 + lfh.file_name_length + end + + -- End of central directory record + zh:write(number_to_bytestring(0x06054b50, 4)) -- signature + zh:write(number_to_bytestring(0, 2)) -- number of this disk + zh:write(number_to_bytestring(0, 2)) -- number of disk with start of central directory + zh:write(number_to_bytestring(#self.files, 2)) -- total number of entries in the central dir on this disk + zh:write(number_to_bytestring(#self.files, 2)) -- total number of entries in the central dir + zh:write(number_to_bytestring(size_of_central_directory, 4)) + zh:write(number_to_bytestring(central_directory_offset, 4)) + zh:write(number_to_bytestring(0, 2)) -- zip file comment length + zh:close() + + return true +end + +--- Return a zip handle open for writing. +-- @param name filename of the zipfile to be created. +-- @return a zip handle, or nil in case of error. +function zip.new_zipwriter(name) + + local zw = {} + + zw.ziphandle = io.open(fs.absolute_name(name), "wb") + if not zw.ziphandle then + return nil + end + zw.files = {} + zw.in_open_file = false + + zw.add = zipwriter_add + zw.close = zipwriter_close + zw.open_new_file_in_zip = zipwriter_open_new_file_in_zip + zw.write_file_in_zip = zipwriter_write_file_in_zip + zw.close_file_in_zip = zipwriter_close_file_in_zip + + return zw +end + +--- Compress files in a .zip archive. +-- @param zipfile string: pathname of .zip archive to be created. +-- @param ... Filenames to be stored in the archive are given as +-- additional arguments. +-- @return boolean or (boolean, string): true on success, +-- false and an error message on failure. +function zip.zip(zipfile, ...) + local zw = zip.new_zipwriter(zipfile) + if not zw then + return nil, "error opening "..zipfile + end + + local ok, err + for _, file in pairs({...}) do + if fs.is_dir(file) then + for _, entry in pairs(fs.find(file)) do + local fullname = dir.path(file, entry) + if fs.is_file(fullname) then + ok, err = zw:add(fullname) + if not ok then break end + end + end + else + ok, err = zw:add(file) + if not ok then break end + end + end + + ok = zw:close() + if not ok then + return false, "error closing "..zipfile + end + return ok, err +end + + +return zip diff --git a/Utils/luarocks/lua/luarocks/type_check.lua b/Utils/luarocks/lua/luarocks/type_check.lua new file mode 100644 index 000000000..63c59ca21 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/type_check.lua @@ -0,0 +1,344 @@ +--- Type-checking functions. +-- Functions and definitions for doing a basic lint check on files +-- loaded by LuaRocks. +local type_check = {} +package.loaded["luarocks.type_check"] = type_check + +local cfg = require("luarocks.cfg") +local deps = require("luarocks.deps") + +type_check.rockspec_format = "1.1" + +local string_1 = { _type = "string" } +local number_1 = { _type = "number" } +local mandatory_string_1 = { _type = "string", _mandatory = true } + +-- Syntax for type-checking tables: +-- +-- A type-checking table describes typing data for a value. +-- Any key starting with an underscore has a special meaning: +-- _type (string) is the Lua type of the value. Default is "table". +-- _version (string) is the minimum rockspec_version that supports this value. Default is "1.0". +-- _mandatory (boolean) indicates if the value is a mandatory key in its container table. Default is false. +-- For "string" types only: +-- _pattern (string) is the string-matching pattern, valid for string types only. Default is ".*". +-- For "table" types only: +-- _any (table) is the type-checking table for unspecified keys, recursively checked. +-- _more (boolean) indicates that the table accepts unspecified keys and does not type-check them. +-- Any other string keys that don't start with an underscore represent known keys and are type-checking tables, recursively checked. + +local rockspec_types = { + rockspec_format = string_1, + package = mandatory_string_1, + version = { _type = "string", _pattern = "[%w.]+-[%d]+", _mandatory = true }, + description = { + summary = string_1, + detailed = string_1, + homepage = string_1, + license = string_1, + maintainer = string_1, + }, + dependencies = { + platforms = {}, -- recursively defined below + _any = string_1, + }, + supported_platforms = { + _any = string_1, + }, + external_dependencies = { + platforms = {}, -- recursively defined below + _any = { + program = string_1, + header = string_1, + library = string_1, + } + }, + source = { + _mandatory = true, + platforms = {}, -- recursively defined below + url = mandatory_string_1, + md5 = string_1, + file = string_1, + dir = string_1, + tag = string_1, + branch = string_1, + module = string_1, + cvs_tag = string_1, + cvs_module = string_1, + }, + build = { + platforms = {}, -- recursively defined below + type = string_1, + install = { + lua = { + _more = true + }, + lib = { + _more = true + }, + conf = { + _more = true + }, + bin = { + _more = true + } + }, + copy_directories = { + _any = string_1, + }, + _more = true, + _mandatory = true + }, + hooks = { + platforms = {}, -- recursively defined below + post_install = string_1, + }, + deploy = { + _version = "1.1", + wrap_bin_scripts = { _type = "boolean", _version = "1.1" }, + } +} + +type_check.rockspec_order = {"rockspec_format", "package", "version", + { "source", { "url", "tag", "branch", "md5" } }, + { "description", {"summary", "detailed", "homepage", "license" } }, + "supported_platforms", "dependencies", "external_dependencies", + { "build", {"type", "modules", "copy_directories", "platforms"} }, + "hooks"} + +rockspec_types.build.platforms._any = rockspec_types.build +rockspec_types.dependencies.platforms._any = rockspec_types.dependencies +rockspec_types.external_dependencies.platforms._any = rockspec_types.external_dependencies +rockspec_types.source.platforms._any = rockspec_types.source +rockspec_types.hooks.platforms._any = rockspec_types.hooks + +local manifest_types = { + repository = { + _mandatory = true, + -- packages + _any = { + -- versions + _any = { + -- items + _any = { + arch = mandatory_string_1, + modules = { _any = string_1 }, + commands = { _any = string_1 }, + dependencies = { _any = string_1 }, + -- TODO: to be extended with more metadata. + } + } + } + }, + modules = { + _mandatory = true, + -- modules + _any = { + -- providers + _any = string_1 + } + }, + commands = { + _mandatory = true, + -- modules + _any = { + -- commands + _any = string_1 + } + }, + dependencies = { + -- each module + _any = { + -- each version + _any = { + -- each dependency + _any = { + name = string_1, + constraints = { + _any = { + no_upgrade = { _type = "boolean" }, + op = string_1, + version = { + string = string_1, + _any = number_1, + } + } + } + } + } + } + } +} + +local function check_version(version, typetbl, context) + local typetbl_version = typetbl._version or "1.0" + if deps.compare_versions(typetbl_version, version) then + if context == "" then + return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly." + else + return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly." + end + end + return true +end + +local type_check_table + +--- Type check an object. +-- The object is compared against an archetypical value +-- matching the expected type -- the actual values don't matter, +-- only their types. Tables are type checked recursively. +-- @param version string: The version of the item. +-- @param item any: The object being checked. +-- @param typetbl any: The type-checking table for the object. +-- @param context string: A string indicating the "context" where the +-- error occurred (the full table path), for error messages. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +-- @see type_check_table +local function type_check_item(version, item, typetbl, context) + assert(type(version) == "string") + + local ok, err = check_version(version, typetbl, context) + if not ok then + return nil, err + end + + local item_type = type(item) or "nil" + local expected_type = typetbl._type or "table" + + if expected_type == "number" then + if not tonumber(item) then + return nil, "Type mismatch on field "..context..": expected a number" + end + elseif expected_type == "string" then + if item_type ~= "string" then + return nil, "Type mismatch on field "..context..": expected a string, got "..item_type + end + if typetbl._pattern then + if not item:match("^"..typetbl._pattern.."$") then + return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'" + end + end + elseif expected_type == "table" then + if item_type ~= expected_type then + return nil, "Type mismatch on field "..context..": expected a table" + else + return type_check_table(version, item, typetbl, context) + end + elseif item_type ~= expected_type then + return nil, "Type mismatch on field "..context..": expected "..expected_type + end + return true +end + +local function mkfield(context, field) + if context == "" then + return tostring(field) + elseif type(field) == "string" then + return context.."."..field + else + return context.."["..tostring(field).."]" + end +end + +--- Type check the contents of a table. +-- The table's contents are compared against a reference table, +-- which contains the recognized fields, with archetypical values +-- matching the expected types -- the actual values of items in the +-- reference table don't matter, only their types (ie, for field x +-- in tbl that is correctly typed, type(tbl.x) == type(types.x)). +-- If the reference table contains a field called MORE, then +-- unknown fields in the checked table are accepted. +-- If it contains a field called ANY, then its type will be +-- used to check any unknown fields. If a field is prefixed +-- with MUST_, it is mandatory; its absence from the table is +-- a type error. +-- Tables are type checked recursively. +-- @param version string: The version of tbl. +-- @param tbl table: The table to be type checked. +-- @param typetbl table: The type-checking table, containing +-- values for recognized fields in the checked table. +-- @param context string: A string indicating the "context" where the +-- error occurred (such as the name of the table the item is a part of), +-- to be used by error messages. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +type_check_table = function(version, tbl, typetbl, context) + assert(type(version) == "string") + assert(type(tbl) == "table") + assert(type(typetbl) == "table") + + local ok, err = check_version(version, typetbl, context) + if not ok then + return nil, err + end + + for k, v in pairs(tbl) do + local t = typetbl[k] or typetbl._any + if t then + local ok, err = type_check_item(version, v, t, mkfield(context, k)) + if not ok then return nil, err end + elseif typetbl._more then + -- Accept unknown field + else + if not cfg.accept_unknown_fields then + return nil, "Unknown field "..k + end + end + end + for k, v in pairs(typetbl) do + if k:sub(1,1) ~= "_" and v._mandatory then + if not tbl[k] then + return nil, "Mandatory field "..mkfield(context, k).." is missing." + end + end + end + return true +end + +local function check_undeclared_globals(globals, typetbl) + local undeclared = {} + for glob, _ in pairs(globals) do + if not (typetbl[glob] or typetbl["MUST_"..glob]) then + table.insert(undeclared, glob) + end + end + if #undeclared == 1 then + return nil, "Unknown variable: "..undeclared[1] + elseif #undeclared > 1 then + return nil, "Unknown variables: "..table.concat(undeclared, ", ") + end + return true +end + +--- Type check a rockspec table. +-- Verify the correctness of elements from a +-- rockspec table, reporting on unknown fields and type +-- mismatches. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +function type_check.type_check_rockspec(rockspec, globals) + assert(type(rockspec) == "table") + if not rockspec.rockspec_format then + rockspec.rockspec_format = "1.0" + end + local ok, err = check_undeclared_globals(globals, rockspec_types) + if not ok then return nil, err end + return type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "") +end + +--- Type check a manifest table. +-- Verify the correctness of elements from a +-- manifest table, reporting on unknown fields and type +-- mismatches. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +function type_check.type_check_manifest(manifest, globals) + assert(type(manifest) == "table") + local ok, err = check_undeclared_globals(globals, manifest_types) + if not ok then return nil, err end + return type_check_table("1.0", manifest, manifest_types, "") +end + +return type_check diff --git a/Utils/luarocks/lua/luarocks/unpack.lua b/Utils/luarocks/lua/luarocks/unpack.lua new file mode 100644 index 000000000..0922f9b90 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/unpack.lua @@ -0,0 +1,166 @@ + +--- Module implementing the LuaRocks "unpack" command. +-- Unpack the contents of a rock. +local unpack = {} +package.loaded["luarocks.unpack"] = unpack + +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local build = require("luarocks.build") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +util.add_run_function(unpack) +unpack.help_summary = "Unpack the contents of a rock." +unpack.help_arguments = "[--force] {| []}" +unpack.help = [[ +Unpacks the contents of a rock in a newly created directory. +Argument may be a rock file, or the name of a rock in a rocks server. +In the latter case, the app version may be given as a second argument. + +--force Unpack files even if the output directory already exists. +]] + +--- Load a rockspec file to the given directory, fetches the source +-- files specified in the rockspec, and unpack them inside the directory. +-- @param rockspec_file string: The URL for a rockspec file. +-- @param dir_name string: The directory where to store and unpack files. +-- @return table or (nil, string): the loaded rockspec table or +-- nil and an error message. +local function unpack_rockspec(rockspec_file, dir_name) + assert(type(rockspec_file) == "string") + assert(type(dir_name) == "string") + + local rockspec, err = fetch.load_rockspec(rockspec_file) + if not rockspec then + return nil, "Failed loading rockspec "..rockspec_file..": "..err + end + local ok, err = fs.change_dir(dir_name) + if not ok then return nil, err end + local ok, sources_dir = fetch.fetch_sources(rockspec, true, ".") + if not ok then + return nil, sources_dir + end + ok, err = fs.change_dir(sources_dir) + if not ok then return nil, err end + ok, err = build.apply_patches(rockspec) + fs.pop_dir() + if not ok then return nil, err end + return rockspec +end + +--- Load a .rock file to the given directory and unpack it inside it. +-- @param rock_file string: The URL for a .rock file. +-- @param dir_name string: The directory where to unpack. +-- @param kind string: the kind of rock file, as in the second-level +-- extension in the rock filename (eg. "src", "all", "linux-x86") +-- @return table or (nil, string): the loaded rockspec table or +-- nil and an error message. +local function unpack_rock(rock_file, dir_name, kind) + assert(type(rock_file) == "string") + assert(type(dir_name) == "string") + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, dir_name) + if not ok then + return nil, "Failed unzipping rock "..rock_file, errcode + end + ok, err = fs.change_dir(dir_name) + if not ok then return nil, err end + local rockspec_file = dir_name..".rockspec" + local rockspec, err = fetch.load_rockspec(rockspec_file) + if not rockspec then + return nil, "Failed loading rockspec "..rockspec_file..": "..err + end + if kind == "src" then + if rockspec.source.file then + local ok, err = fs.unpack_archive(rockspec.source.file) + if not ok then + return nil, err + end + ok, err = fs.change_dir(rockspec.source.dir) + if not ok then return nil, err end + ok, err = build.apply_patches(rockspec) + fs.pop_dir() + if not ok then return nil, err end + end + end + return rockspec +end + +--- Create a directory and perform the necessary actions so that +-- the sources for the rock and its rockspec are unpacked inside it, +-- laid out properly so that the 'make' command is able to build the module. +-- @param file string: A rockspec or .rock URL. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +local function run_unpacker(file, force) + assert(type(file) == "string") + + local base_name = dir.base_name(file) + local dir_name, kind, extension = base_name:match("(.*)%.([^.]+)%.(rock)$") + if not extension then + dir_name, extension = base_name:match("(.*)%.(rockspec)$") + kind = "rockspec" + end + if not extension then + return nil, file.." does not seem to be a valid filename." + end + + local exists = fs.exists(dir_name) + if exists and not force then + return nil, "Directory "..dir_name.." already exists." + end + if not exists then + local ok, err = fs.make_dir(dir_name) + if not ok then return nil, err end + end + local rollback = util.schedule_function(fs.delete, fs.absolute_name(dir_name)) + + local rockspec, err + if extension == "rock" then + rockspec, err = unpack_rock(file, dir_name, kind) + elseif extension == "rockspec" then + rockspec, err = unpack_rockspec(file, dir_name) + end + if not rockspec then + return nil, err + end + if kind == "src" or kind == "rockspec" then + if rockspec.source.dir ~= "." then + local ok = fs.copy(rockspec.local_filename, rockspec.source.dir, cfg.perm_read) + if not ok then + return nil, "Failed copying unpacked rockspec into unpacked source directory." + end + end + util.printout() + util.printout("Done. You may now enter directory ") + util.printout(dir.path(dir_name, rockspec.source.dir)) + util.printout("and type 'luarocks make' to build.") + end + util.remove_scheduled_function(rollback) + return true +end + +--- Driver function for the "unpack" command. +-- @param name string: may be a rock filename, for unpacking a +-- rock file or the name of a rock to be fetched and unpacked. +-- @param version string or nil: if the name of a package is given, a +-- version may also be passed. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +function unpack.command(flags, name, version) + assert(type(version) == "string" or not version) + if type(name) ~= "string" then + return nil, "Argument missing. "..util.see_help("unpack") + end + + if name:match(".*%.rock") or name:match(".*%.rockspec") then + return run_unpacker(name, flags["force"]) + else + local search = require("luarocks.search") + return search.act_on_src_or_rockspec(run_unpacker, name:lower(), version) + end +end + +return unpack diff --git a/Utils/luarocks/lua/luarocks/upload.lua b/Utils/luarocks/lua/luarocks/upload.lua new file mode 100644 index 000000000..7c0c416ce --- /dev/null +++ b/Utils/luarocks/lua/luarocks/upload.lua @@ -0,0 +1,95 @@ + +local upload = {} + +local util = require("luarocks.util") +local fetch = require("luarocks.fetch") +local pack = require("luarocks.pack") +local cfg = require("luarocks.cfg") +local Api = require("luarocks.upload.api") + +util.add_run_function(upload) +upload.help_summary = "Upload a rockspec to the public rocks repository." +upload.help_arguments = "[--skip-pack] [--api-key=] [--force] " +upload.help = [[ + Pack a source rock file (.src.rock extension), + upload rockspec and source rock to server. +--skip-pack Do not pack and send source rock. +--api-key= Give it an API key. It will be stored for subsequent uses. +--force Replace existing rockspec if the same revision of + a module already exists. This should be used only + in case of upload mistakes: when updating a rockspec, + increment the revision number instead. +]] + +function upload.command(flags, fname) + if not fname then + return nil, "Missing rockspec. "..util.see_help("upload") + end + + local api, err = Api.new(flags) + if not api then + return nil, err + end + if cfg.verbose then + api.debug = true + end + + local rockspec, err, errcode = fetch.load_rockspec(fname) + if err then + return nil, err, errcode + end + + util.printout("Sending " .. tostring(fname) .. " ...") + local res, err = api:method("check_rockspec", { + package = rockspec.package, + version = rockspec.version + }) + if not res then return nil, err end + + if not res.module then + util.printout("Will create new module (" .. tostring(rockspec.package) .. ")") + end + if res.version and not flags["force"] then + return nil, "Revision "..rockspec.version.." already exists on the server. "..util.see_help("upload") + end + + local rock_fname + if not flags["skip-pack"] and not rockspec.version:match("^scm") then + util.printout("Packing " .. tostring(rockspec.package)) + rock_fname, err = pack.pack_source_rock(fname) + if not rock_fname then + return nil, err + end + end + + local multipart = require("luarocks.upload.multipart") + + res, err = api:method("upload", nil, { + rockspec_file = multipart.new_file(fname) + }) + if not res then return nil, err end + + if res.is_new and #res.manifests == 0 then + util.printerr("Warning: module not added to root manifest due to name taken.") + end + + local module_url = res.module_url + + if rock_fname then + if (not res.version) or (not res.version.id) then + return nil, "Invalid response from server." + end + util.printout(("Sending " .. tostring(rock_fname) .. " ...")) + res, err = api:method("upload_rock/" .. ("%d"):format(res.version.id), nil, { + rock_file = multipart.new_file(rock_fname) + }) + if not res then return nil, err end + end + + util.printout() + util.printout("Done: " .. tostring(module_url)) + util.printout() + return true +end + +return upload diff --git a/Utils/luarocks/lua/luarocks/upload/api.lua b/Utils/luarocks/lua/luarocks/upload/api.lua new file mode 100644 index 000000000..ba657186a --- /dev/null +++ b/Utils/luarocks/lua/luarocks/upload/api.lua @@ -0,0 +1,284 @@ + +local api = {} + +local cfg = require("luarocks.cfg") +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local persist = require("luarocks.persist") +local multipart = require("luarocks.upload.multipart") + +local Api = {} + +local function upload_config_file() + local conf = cfg.which_config() + if not conf.user.file then + return nil + end + return (conf.user.file:gsub("/[^/]+$", "/upload_config.lua")) +end + +function Api:load_config() + local upload_conf = upload_config_file() + if not upload_conf then return nil end + local cfg, err = persist.load_into_table(upload_conf) + return cfg +end + +function Api:save_config() + -- Test configuration before saving it. + local res, err = self:raw_method("status") + if not res then + return nil, err + end + if res.errors then + util.printerr("Server says: " .. tostring(res.errors[1])) + return + end + local upload_conf = upload_config_file() + if not upload_conf then return nil end + persist.save_from_table(upload_conf, self.config) + fs.chmod(upload_conf, "0600") +end + +function Api:check_version() + if not self._server_tool_version then + local tool_version = cfg.upload.tool_version + local res, err = self:request(tostring(self.config.server) .. "/api/tool_version", { + current = tool_version + }) + if not res then + return nil, err + end + if not res.version then + return nil, "failed to fetch tool version" + end + self._server_tool_version = res.version + if res.force_update then + return nil, "Your upload client is too out of date to continue, please upgrade LuaRocks." + end + if res.version ~= tool_version then + util.printerr("Warning: Your LuaRocks is out of date, consider upgrading.") + end + end + return true +end + +function Api:method(...) + local res, err = self:raw_method(...) + if not res then + return nil, err + end + if res.errors then + if res.errors[1] == "Invalid key" then + return nil, res.errors[1] .. " (use the --api-key flag to change)" + end + local msg = table.concat(res.errors, ", ") + return nil, "API Failed: " .. msg + end + return res +end + +function Api:raw_method(path, ...) + self:check_version() + local url = tostring(self.config.server) .. "/api/" .. tostring(cfg.upload.api_version) .. "/" .. tostring(self.config.key) .. "/" .. tostring(path) + return self:request(url, ...) +end + +local function encode_query_string(t, sep) + if sep == nil then + sep = "&" + end + local i = 0 + local buf = { } + for k, v in pairs(t) do + if type(k) == "number" and type(v) == "table" then + k, v = v[1], v[2] + end + buf[i + 1] = multipart.url_escape(k) + buf[i + 2] = "=" + buf[i + 3] = multipart.url_escape(v) + buf[i + 4] = sep + i = i + 4 + end + buf[i] = nil + return table.concat(buf) +end + +-- An ode to the multitude of JSON libraries out there... +local function require_json() + local list = { "cjson", "dkjson", "json" } + for _, lib in ipairs(list) do + local json_ok, json = pcall(require, lib) + if json_ok then + pcall(json.use_lpeg) -- optional feature in dkjson + return json_ok, json + end + end + local errmsg = "Failed loading " + for i, name in ipairs(list) do + if i == #list then + errmsg = errmsg .."and '"..name.."'. Use 'luarocks search ' to search for a library and 'luarocks install ' to install one." + else + errmsg = errmsg .."'"..name.."', " + end + end + return nil, errmsg +end + +local function redact_api_url(url) + url = tostring(url) + return (url:gsub(".*/api/[^/]+/[^/]+", "")) or "" +end + +local ltn12_ok, ltn12 = pcall(require, "ltn12") +if not ltn12_ok then -- If not using LuaSocket and/or LuaSec... + +function Api:request(url, params, post_params) + local vars = cfg.variables + local json_ok, json = require_json() + if not json_ok then return nil, "A JSON library is required for this command. "..json end + + if cfg.downloader == "wget" then + local curl_ok, err = fs.is_tool_available(vars.CURL, "curl") + if not curl_ok then + return nil, err + end + end + + if not self.config.key then + return nil, "Must have API key before performing any actions." + end + if params and next(params) then + url = url .. ("?" .. encode_query_string(params)) + end + local method = "GET" + local out + local tmpfile = fs.tmpname() + if post_params then + method = "POST" + local curl_cmd = fs.Q(vars.CURL).." -f -k -L --silent --user-agent \""..cfg.user_agent.." via curl\" " + for k,v in pairs(post_params) do + local var = v + if type(v) == "table" then + var = "@"..v.fname + end + curl_cmd = curl_cmd .. "--form \""..k.."="..var.."\" " + end + if cfg.connection_timeout and cfg.connection_timeout > 0 then + curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." " + end + local ok = fs.execute_string(curl_cmd..fs.Q(url).." -o "..fs.Q(tmpfile)) + if not ok then + return nil, "API failure: " .. redact_api_url(url) + end + else + local ok, err = fs.download(url, tmpfile) + if not ok then + return nil, "API failure: " .. tostring(err) .. " - " .. redact_api_url(url) + end + end + + local tmpfd = io.open(tmpfile) + if not tmpfd then + os.remove(tmpfile) + return nil, "API failure reading temporary file - " .. redact_api_url(url) + end + out = tmpfd:read("*a") + tmpfd:close() + os.remove(tmpfile) + + if self.debug then + util.printout("[" .. tostring(method) .. " via curl] " .. redact_api_url(url) .. " ... ") + end + + return json.decode(out) +end + +else -- use LuaSocket and LuaSec + +local warned_luasec = false + +function Api:request(url, params, post_params) + local json_ok, json = require_json() + if not json_ok then return nil, "A JSON library is required for this command. "..json end + local server = tostring(self.config.server) + local http_ok, http + local via = "luasocket" + if server:match("^https://") then + http_ok, http = pcall(require, "ssl.https") + if http_ok then + via = "luasec" + else + if not warned_luasec then + util.printerr("LuaSec is not available; using plain HTTP. Install 'luasec' to enable HTTPS.") + warned_luasec = true + end + http_ok, http = pcall(require, "socket.http") + url = url:gsub("^https", "http") + via = "luasocket" + end + else + http_ok, http = pcall(require, "socket.http") + end + if not http_ok then + return nil, "Failed loading socket library!" + end + + if not self.config.key then + return nil, "Must have API key before performing any actions." + end + local body + local headers = {} + if params and next(params) then + url = url .. ("?" .. encode_query_string(params)) + end + if post_params then + local boundary + body, boundary = multipart.encode(post_params) + headers["Content-length"] = #body + headers["Content-type"] = "multipart/form-data; boundary=" .. tostring(boundary) + end + local method = post_params and "POST" or "GET" + if self.debug then + util.printout("[" .. tostring(method) .. " via "..via.."] " .. redact_api_url(url) .. " ... ") + end + local out = {} + local _, status = http.request({ + url = url, + headers = headers, + method = method, + sink = ltn12.sink.table(out), + source = body and ltn12.source.string(body) + }) + if self.debug then + util.printout(tostring(status)) + end + if status ~= 200 then + return nil, "API returned " .. tostring(status) .. " - " .. redact_api_url(url) + end + return json.decode(table.concat(out)) +end + +end + +function api.new(flags) + local self = {} + setmetatable(self, { __index = Api }) + self.config = self:load_config() or {} + self.config.server = flags["server"] or self.config.server or cfg.upload.server + self.config.version = self.config.version or cfg.upload.version + self.config.key = flags["api-key"] or self.config.key + self.debug = flags["debug"] + if not self.config.key then + return nil, "You need an API key to upload rocks.\n" .. + "Navigate to "..self.config.server.."/settings to get a key\n" .. + "and then pass it through the --api-key= flag." + end + if flags["api-key"] then + self:save_config() + end + return self +end + +return api + diff --git a/Utils/luarocks/lua/luarocks/upload/multipart.lua b/Utils/luarocks/lua/luarocks/upload/multipart.lua new file mode 100644 index 000000000..aad2e4398 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/upload/multipart.lua @@ -0,0 +1,111 @@ + +local multipart = {} + +local File = {} + +local unpack = unpack or table.unpack + +math.randomseed(os.time()) + +-- socket.url.escape(s) from LuaSocket 3.0rc1 +function multipart.url_escape(s) + return (string.gsub(s, "([^A-Za-z0-9_])", function(c) + return string.format("%%%02x", string.byte(c)) + end)) +end + +function File:mime() + if not self.mimetype then + local mimetypes_ok, mimetypes = pcall(require, "mimetypes") + if mimetypes_ok then + self.mimetype = mimetypes.guess(self.fname) + end + self.mimetype = self.mimetype or "application/octet-stream" + end + return self.mimetype +end + +function File:content() + local fd = io.open(self.fname, "rb") + if not fd then + return nil, "Failed to open file: "..self.fname + end + local data = fd:read("*a") + fd:close() + return data +end + +local function rand_string(len) + local shuffled = {} + for i = 1, len do + local r = math.random(97, 122) + if math.random() >= 0.5 then + r = r - 32 + end + shuffled[i] = r + end + return string.char(unpack(shuffled)) +end + +-- multipart encodes params +-- returns encoded string,boundary +-- params is an a table of tuple tables: +-- params = { +-- {key1, value2}, +-- {key2, value2}, +-- key3: value3 +-- } +function multipart.encode(params) + local tuples = { } + for i = 1, #params do + tuples[i] = params[i] + end + for k,v in pairs(params) do + if type(k) == "string" then + table.insert(tuples, {k, v}) + end + end + local chunks = {} + for _, tuple in ipairs(tuples) do + local k,v = unpack(tuple) + k = multipart.url_escape(k) + local buffer = { 'Content-Disposition: form-data; name="' .. k .. '"' } + local content + if type(v) == "table" and v.__class == File then + buffer[1] = buffer[1] .. ('; filename="' .. v.fname:gsub(".*/", "") .. '"') + table.insert(buffer, "Content-type: " .. v:mime()) + content = v:content() + else + content = v + end + table.insert(buffer, "") + table.insert(buffer, content) + table.insert(chunks, table.concat(buffer, "\r\n")) + end + local boundary + while not boundary do + boundary = "Boundary" .. rand_string(16) + for _, chunk in ipairs(chunks) do + if chunk:find(boundary) then + boundary = nil + break + end + end + end + local inner = "\r\n--" .. boundary .. "\r\n" + return table.concat({ "--", boundary, "\r\n", + table.concat(chunks, inner), + "\r\n", "--", boundary, "--", "\r\n" }), boundary +end + +function multipart.new_file(fname, mime) + local self = {} + setmetatable(self, { __index = File }) + self.__class = File + self.fname = fname + self.mimetype = mime + return self +end + +return multipart + diff --git a/Utils/luarocks/lua/luarocks/util.lua b/Utils/luarocks/lua/luarocks/util.lua new file mode 100644 index 000000000..c9fb7d637 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/util.lua @@ -0,0 +1,714 @@ + +--- Assorted utilities for managing tables, plus a scheduler for rollback functions. +-- Does not requires modules directly (only as locals +-- inside specific functions) to avoid interdependencies, +-- as this is used in the bootstrapping stage of luarocks.cfg. + +local util = {} + +local unpack = unpack or table.unpack + +local scheduled_functions = {} +local debug = require("debug") + +--- Schedule a function to be executed upon program termination. +-- This is useful for actions such as deleting temporary directories +-- or failure rollbacks. +-- @param f function: Function to be executed. +-- @param ... arguments to be passed to function. +-- @return table: A token representing the scheduled execution, +-- which can be used to remove the item later from the list. +function util.schedule_function(f, ...) + assert(type(f) == "function") + + local item = { fn = f, args = {...} } + table.insert(scheduled_functions, item) + return item +end + +--- Unschedule a function. +-- This is useful for cancelling a rollback of a completed operation. +-- @param item table: The token representing the scheduled function that was +-- returned from the schedule_function call. +function util.remove_scheduled_function(item) + for k, v in pairs(scheduled_functions) do + if v == item then + table.remove(scheduled_functions, k) + return + end + end +end + +--- Execute scheduled functions. +-- Some calls create temporary files and/or directories and register +-- corresponding cleanup functions. Calling this function will run +-- these function, erasing temporaries. +-- Functions are executed in the inverse order they were scheduled. +function util.run_scheduled_functions() + local fs = require("luarocks.fs") + fs.change_dir_to_root() + for i = #scheduled_functions, 1, -1 do + local item = scheduled_functions[i] + item.fn(unpack(item.args)) + end +end + +--- Produce a Lua pattern that matches precisely the given string +-- (this is suitable to be concatenating to other patterns, +-- so it does not include beginning- and end-of-string markers (^$) +-- @param s string: The input string +-- @return string: The equivalent pattern +function util.matchquote(s) + return (s:gsub("[?%-+*%[%].%%()$^]","%%%1")) +end + +--- List of supported arguments. +-- Arguments that take no parameters are marked with the boolean true. +-- Arguments that take a parameter are marked with a descriptive string. +-- Arguments that may take an empty string are described in quotes, +-- (as in the value for --detailed=""). +-- For all other string values, it means the parameter is mandatory. +local supported_flags = { + ["all"] = true, + ["api-key"] = "", + ["append"] = true, + ["arch"] = "", + ["bin"] = true, + ["binary"] = true, + ["branch"] = "", + ["debug"] = true, + ["deps"] = true, + ["deps-mode"] = "", + ["detailed"] = "\"\"", + ["force"] = true, + ["force-fast"] = true, + ["from"] = "", + ["help"] = true, + ["home"] = true, + ["homepage"] = "\"\"", + ["keep"] = true, + ["lib"] = "", + ["license"] = "\"\"", + ["list"] = true, + ["local"] = true, + ["local-tree"] = true, + ["lr-bin"] = true, + ["lr-cpath"] = true, + ["lr-path"] = true, + ["lua-version"] = "", + ["lua-ver"] = true, + ["lua-incdir"] = true, + ["lua-libdir"] = true, + ["modules"] = true, + ["mversion"] = true, + ["no-refresh"] = true, + ["nodeps"] = true, + ["old-versions"] = true, + ["only-deps"] = true, + ["only-from"] = "", + ["only-server"] = "", + ["only-sources"] = "", + ["only-sources-from"] = "", + ["outdated"] = true, + ["output"] = "", + ["pack-binary-rock"] = true, + ["porcelain"] = true, + ["quick"] = true, + ["rock-dir"] = true, + ["rock-tree"] = true, + ["rock-trees"] = true, + ["rockspec"] = true, + ["rockspec-format"] = "", + ["server"] = "", + ["skip-pack"] = true, + ["source"] = true, + ["summary"] = "\"\"", + ["system-config"] = true, + ["tag"] = "", + ["timeout"] = "", + ["to"] = "", + ["tree"] = "", + ["user-config"] = true, + ["verbose"] = true, + ["version"] = true, +} + +--- Extract flags from an arguments list. +-- Given string arguments, extract flag arguments into a flags set. +-- For example, given "foo", "--tux=beep", "--bla", "bar", "--baz", +-- it would return the following: +-- {["bla"] = true, ["tux"] = "beep", ["baz"] = true}, "foo", "bar". +function util.parse_flags(...) + local args = {...} + local flags = {} + local i = 1 + local out = {} + local ignore_flags = false + while i <= #args do + local flag = args[i]:match("^%-%-(.*)") + if flag == "--" then + ignore_flags = true + end + if flag and not ignore_flags then + local var,val = flag:match("([a-z_%-]*)=(.*)") + if val then + local vartype = supported_flags[var] + if type(vartype) == "string" then + if val == "" and vartype:sub(1,1) ~= '"' then + return { ERROR = "Invalid argument: parameter to flag --"..var.."="..vartype.." cannot be empty." } + end + flags[var] = val + else + if vartype then + return { ERROR = "Invalid argument: flag --"..var.." does not take an parameter." } + else + return { ERROR = "Invalid argument: unknown flag --"..var.."." } + end + end + else + local var = flag + local vartype = supported_flags[var] + if type(vartype) == "string" then + i = i + 1 + local val = args[i] + if not val then + return { ERROR = "Invalid argument: flag --"..var.."="..vartype.." expects a parameter." } + end + if val:match("^%-%-.*") then + return { ERROR = "Invalid argument: flag --"..var.."="..vartype.." expects a parameter (if you really want to pass "..val.." as an argument to --"..var..", use --"..var.."="..val..")." } + else + if val == "" and vartype:sub(1,1) ~= '"' then + return { ERROR = "Invalid argument: parameter to flag --"..var.."="..vartype.." cannot be empty." } + end + flags[var] = val + end + elseif vartype == true then + flags[var] = true + else + return { ERROR = "Invalid argument: unknown flag --"..var.."." } + end + end + else + table.insert(out, args[i]) + end + i = i + 1 + end + return flags, unpack(out) +end + +-- Adds legacy 'run' function to a command module. +-- @param command table: command module with 'command' function, +-- the added 'run' function calls it after parseing command-line arguments. +function util.add_run_function(command) + command.run = function(...) return command.command(util.parse_flags(...)) end +end + +--- Merges contents of src on top of dst's contents. +-- @param dst Destination table, which will receive src's contents. +-- @param src Table which provides new contents to dst. +-- @see platform_overrides +function util.deep_merge(dst, src) + for k, v in pairs(src) do + if type(v) == "table" then + if not dst[k] then + dst[k] = {} + end + if type(dst[k]) == "table" then + util.deep_merge(dst[k], v) + else + dst[k] = v + end + else + dst[k] = v + end + end +end + +--- Perform platform-specific overrides on a table. +-- Overrides values of table with the contents of the appropriate +-- subset of its "platforms" field. The "platforms" field should +-- be a table containing subtables keyed with strings representing +-- platform names. Names that match the contents of the global +-- cfg.platforms setting are used. For example, if +-- cfg.platforms= {"foo"}, then the fields of +-- tbl.platforms.foo will overwrite those of tbl with the same +-- names. For table values, the operation is performed recursively +-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of +-- tbl.x are preserved). +-- @param tbl table or nil: Table which may contain a "platforms" field; +-- if it doesn't (or if nil is passed), this function does nothing. +function util.platform_overrides(tbl) + assert(type(tbl) == "table" or not tbl) + + local cfg = require("luarocks.cfg") + + if not tbl then return end + + if tbl.platforms then + for _, platform in ipairs(cfg.platforms) do + local platform_tbl = tbl.platforms[platform] + if platform_tbl then + util.deep_merge(tbl, platform_tbl) + end + end + end + tbl.platforms = nil +end + +local var_format_pattern = "%$%((%a[%a%d_]+)%)" + +--- Create a new shallow copy of a table: a new table with +-- the same keys and values. Keys point to the same objects as +-- the original table (ie, does not copy recursively). +-- @param tbl table: the input table +-- @return table: a new table with the same contents. +function util.make_shallow_copy(tbl) + local copy = {} + for k,v in pairs(tbl) do + copy[k] = v + end + return copy +end + +-- Check if a set of needed variables are referenced +-- somewhere in a list of definitions, warning the user +-- about any unused ones. Each key in needed_set should +-- appear as a $(XYZ) variable at least once as a +-- substring of some value of var_defs. +-- @param var_defs: a table with string keys and string +-- values, containing variable definitions. +-- @param needed_set: a set where keys are the names of +-- needed variables. +-- @param msg string: the warning message to display. +function util.warn_if_not_used(var_defs, needed_set, msg) + needed_set = util.make_shallow_copy(needed_set) + for _, val in pairs(var_defs) do + for used in val:gmatch(var_format_pattern) do + needed_set[used] = nil + end + end + for var, _ in pairs(needed_set) do + util.warning(msg:format(var)) + end +end + +-- Output any entries that might remain in $(XYZ) format, +-- warning the user that substitutions have failed. +-- @param line string: the input string +local function warn_failed_matches(line) + local any_failed = false + if line:match(var_format_pattern) then + for unmatched in line:gmatch(var_format_pattern) do + util.warning("unmatched variable " .. unmatched) + any_failed = true + end + end + return any_failed +end + +--- Perform make-style variable substitutions on string values of a table. +-- For every string value tbl.x which contains a substring of the format +-- "$(XYZ)" will have this substring replaced by vars["XYZ"], if that field +-- exists in vars. Only string values are processed; this function +-- does not scan subtables recursively. +-- @param tbl table: Table to have its string values modified. +-- @param vars table: Table containing string-string key-value pairs +-- representing variables to replace in the strings values of tbl. +function util.variable_substitutions(tbl, vars) + assert(type(tbl) == "table") + assert(type(vars) == "table") + + local updated = {} + for k, v in pairs(tbl) do + if type(v) == "string" then + updated[k] = v:gsub(var_format_pattern, vars) + if warn_failed_matches(updated[k]) then + updated[k] = updated[k]:gsub(var_format_pattern, "") + end + end + end + for k, v in pairs(updated) do + tbl[k] = v + end +end + +--- Return an array of keys of a table. +-- @param tbl table: The input table. +-- @return table: The array of keys. +function util.keys(tbl) + local ks = {} + for k,_ in pairs(tbl) do + table.insert(ks, k) + end + return ks +end + +local function default_sort(a, b) + local ta = type(a) + local tb = type(b) + if ta == "number" and tb == "number" then + return a < b + elseif ta == "number" then + return true + elseif tb == "number" then + return false + else + return tostring(a) < tostring(b) + end +end + +--- A table iterator generator that returns elements sorted by key, +-- to be used in "for" loops. +-- @param tbl table: The table to be iterated. +-- @param sort_function function or table or nil: An optional comparison function +-- to be used by table.sort when sorting keys, or an array listing an explicit order +-- for keys. If a value itself is an array, it is taken so that the first element +-- is a string representing the field name, and the second element is a priority table +-- for that key, which is returned by the iterator as the third value after the key +-- and the value. +-- @return function: the iterator function. +function util.sortedpairs(tbl, sort_function) + sort_function = sort_function or default_sort + local keys = util.keys(tbl) + local sub_orders = {} + + if type(sort_function) == "function" then + table.sort(keys, sort_function) + else + local order = sort_function + local ordered_keys = {} + local all_keys = keys + keys = {} + + for _, order_entry in ipairs(order) do + local key, sub_order + if type(order_entry) == "table" then + key = order_entry[1] + sub_order = order_entry[2] + else + key = order_entry + end + + if tbl[key] then + ordered_keys[key] = true + sub_orders[key] = sub_order + table.insert(keys, key) + end + end + + table.sort(all_keys, default_sort) + for _, key in ipairs(all_keys) do + if not ordered_keys[key] then + table.insert(keys, key) + end + end + end + + local i = 1 + return function() + local key = keys[i] + i = i + 1 + return key, tbl[key], sub_orders[key] + end +end + +function util.lua_versions() + local versions = { "5.1", "5.2", "5.3" } + local i = 0 + return function() + i = i + 1 + return versions[i] + end +end + +function util.starts_with(s, prefix) + return s:sub(1,#prefix) == prefix +end + +--- Print a line to standard output +function util.printout(...) + io.stdout:write(table.concat({...},"\t")) + io.stdout:write("\n") +end + +--- Print a line to standard error +function util.printerr(...) + io.stderr:write(table.concat({...},"\t")) + io.stderr:write("\n") +end + +--- Display a warning message. +-- @param msg string: the warning message +function util.warning(msg) + util.printerr("Warning: "..msg) +end + +function util.title(msg, porcelain, underline) + if porcelain then return end + util.printout() + util.printout(msg) + util.printout((underline or "-"):rep(#msg)) + util.printout() +end + +function util.this_program(default) + local i = 1 + local last, cur = default, default + while i do + local dbg = debug.getinfo(i,"S") + if not dbg then break end + last = cur + cur = dbg.source + i=i+1 + end + return last:sub(2) +end + +function util.deps_mode_help(program) + local cfg = require("luarocks.cfg") + return [[ +--deps-mode= How to handle dependencies. Four modes are supported: + * all - use all trees from the rocks_trees list + for finding dependencies + * one - use only the current tree (possibly set + with --tree) + * order - use trees based on order (use the current + tree and all trees below it on the rocks_trees list) + * none - ignore dependencies altogether. + The default mode may be set with the deps_mode entry + in the configuration file. + The current default is "]]..cfg.deps_mode..[[". + Type ']]..util.this_program(program or "luarocks")..[[' with no arguments to see + your list of rocks trees. +]] +end + +function util.see_help(command, program) + return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." +end + +function util.announce_install(rockspec) + local cfg = require("luarocks.cfg") + local path = require("luarocks.path") + + local suffix = "" + if rockspec.description and rockspec.description.license then + suffix = " (license: "..rockspec.description.license..")" + end + + local root_dir = path.root_dir(cfg.rocks_dir) + util.printout(rockspec.name.." "..rockspec.version.." is now installed in "..root_dir..suffix) + util.printout() +end + +--- Collect rockspecs located in a subdirectory. +-- @param versions table: A table mapping rock names to newest rockspec versions. +-- @param paths table: A table mapping rock names to newest rockspec paths. +-- @param unnamed_paths table: An array of rockspec paths that don't contain rock +-- name and version in regular format. +-- @param subdir string: path to subdirectory. +local function collect_rockspecs(versions, paths, unnamed_paths, subdir) + local fs = require("luarocks.fs") + local dir = require("luarocks.dir") + local path = require("luarocks.path") + local deps = require("luarocks.deps") + + if fs.is_dir(subdir) then + for file in fs.dir(subdir) do + file = dir.path(subdir, file) + + if file:match("rockspec$") and fs.is_file(file) then + local rock, version = path.parse_name(file) + + if rock then + if not versions[rock] or deps.compare_versions(version, versions[rock]) then + versions[rock] = version + paths[rock] = file + end + else + table.insert(unnamed_paths, file) + end + end + end + end +end + +--- Get default rockspec name for commands that take optional rockspec name. +-- @return string or (nil, string): path to the rockspec or nil and error message. +function util.get_default_rockspec() + local versions, paths, unnamed_paths = {}, {}, {} + -- Look for rockspecs in some common locations. + collect_rockspecs(versions, paths, unnamed_paths, ".") + collect_rockspecs(versions, paths, unnamed_paths, "rockspec") + collect_rockspecs(versions, paths, unnamed_paths, "rockspecs") + + if #unnamed_paths > 0 then + -- There are rockspecs not following "name-version.rockspec" format. + -- More than one are ambiguous. + if #unnamed_paths > 1 then + return nil, "Please specify which rockspec file to use." + else + return unnamed_paths[1] + end + else + local rock = next(versions) + + if rock then + -- If there are rockspecs for multiple rocks it's ambiguous. + if next(versions, rock) then + return nil, "Please specify which rockspec file to use." + else + return paths[rock] + end + else + return nil, "Argument missing: please specify a rockspec to use on current directory." + end + end +end + +-- from http://lua-users.org/wiki/SplitJoin +-- by PhilippeLhoste +function util.split_string(str, delim, maxNb) + -- Eliminate bad cases... + if string.find(str, delim) == nil then + return { str } + end + if maxNb == nil or maxNb < 1 then + maxNb = 0 -- No limit + end + local result = {} + local pat = "(.-)" .. delim .. "()" + local nb = 0 + local lastPos + for part, pos in string.gmatch(str, pat) do + nb = nb + 1 + result[nb] = part + lastPos = pos + if nb == maxNb then break end + end + -- Handle the last field + if nb ~= maxNb then + result[nb + 1] = string.sub(str, lastPos) + end + return result +end + +--- Remove repeated entries from a path-style string. +-- Example: given ("a;b;c;a;b;d", ";"), returns "a;b;c;d". +-- @param list string: A path string (from $PATH or package.path) +-- @param sep string: The separator +function util.remove_path_dupes(list, sep) + assert(type(list) == "string") + assert(type(sep) == "string") + local parts = util.split_string(list, sep) + local final, entries = {}, {} + for _, part in ipairs(parts) do + part = part:gsub("//", "/") + if not entries[part] then + table.insert(final, part) + entries[part] = true + end + end + return table.concat(final, sep) +end + +--- +-- Formats tables with cycles recursively to any depth. +-- References to other tables are shown as values. +-- Self references are indicated. +-- The string returned is "Lua code", which can be procesed +-- (in the case in which indent is composed by spaces or "--"). +-- Userdata and function keys and values are shown as strings, +-- which logically are exactly not equivalent to the original code. +-- This routine can serve for pretty formating tables with +-- proper indentations, apart from printing them: +-- io.write(table.show(t, "t")) -- a typical use +-- Written by Julio Manuel Fernandez-Diaz, +-- Heavily based on "Saving tables with cycles", PIL2, p. 113. +-- @param t table: is the table. +-- @param name string: is the name of the table (optional) +-- @param indent string: is a first indentation (optional). +-- @return string: the pretty-printed table +function util.show_table(t, name, indent) + local cart -- a container + local autoref -- for self references + + local function isemptytable(t) return next(t) == nil end + + local function basicSerialize (o) + local so = tostring(o) + if type(o) == "function" then + local info = debug.getinfo(o, "S") + -- info.name is nil because o is not a calling level + if info.what == "C" then + return ("%q"):format(so .. ", C function") + else + -- the information is defined through lines + return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) + end + elseif type(o) == "number" then + return so + else + return ("%q"):format(so) + end + end + + local function addtocart (value, name, indent, saved, field) + indent = indent or "" + saved = saved or {} + field = field or name + + cart = cart .. indent .. field + + if type(value) ~= "table" then + cart = cart .. " = " .. basicSerialize(value) .. ";\n" + else + if saved[value] then + cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n" + autoref = autoref .. name .. " = " .. saved[value] .. ";\n" + else + saved[value] = name + --if tablecount(value) == 0 then + if isemptytable(value) then + cart = cart .. " = {};\n" + else + cart = cart .. " = {\n" + for k, v in pairs(value) do + k = basicSerialize(k) + local fname = ("%s[%s]"):format(name, k) + field = ("[%s]"):format(k) + -- three spaces between levels + addtocart(v, fname, indent .. " ", saved, field) + end + cart = cart .. indent .. "};\n" + end + end + end + end + + name = name or "__unnamed__" + if type(t) ~= "table" then + return name .. " = " .. basicSerialize(t) + end + cart, autoref = "", "" + addtocart(t, name, indent) + return cart .. autoref +end + +function util.array_contains(tbl, value) + for _, v in ipairs(tbl) do + if v == value then + return true + end + end + return false +end + +-- Quote Lua string, analogous to fs.Q. +-- @param s A string, such as "hello" +-- @return string: A quoted string, such as '"hello"' +function util.LQ(s) + return ("%q"):format(s) +end + +return util diff --git a/Utils/luarocks/lua/luarocks/validate.lua b/Utils/luarocks/lua/luarocks/validate.lua new file mode 100644 index 000000000..c4570aa4b --- /dev/null +++ b/Utils/luarocks/lua/luarocks/validate.lua @@ -0,0 +1,159 @@ + +--- Sandboxed test of build/install of all packages in a repository (unfinished and disabled). +local validate = {} +package.loaded["luarocks.validate"] = validate + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local path = require("luarocks.path") +local cfg = require("luarocks.cfg") +local build = require("luarocks.build") +local install = require("luarocks.install") +local util = require("luarocks.util") + +util.add_run_function(validate) +validate.help_summary = "Sandboxed test of build/install of all packages in a repository." + +validate.help = [[ +, if given, is a local repository pathname. +]] + +local function save_settings(repo) + local protocol, path = dir.split_url(repo) + table.insert(cfg.rocks_servers, 1, protocol.."://"..path) + return { + root_dir = cfg.root_dir, + rocks_dir = cfg.rocks_dir, + deploy_bin_dir = cfg.deploy_bin_dir, + deploy_lua_dir = cfg.deploy_lua_dir, + deploy_lib_dir = cfg.deploy_lib_dir, + } +end + +local function restore_settings(settings) + cfg.root_dir = settings.root_dir + cfg.rocks_dir = settings.rocks_dir + cfg.deploy_bin_dir = settings.deploy_bin_dir + cfg.deploy_lua_dir = settings.deploy_lua_dir + cfg.deploy_lib_dir = settings.deploy_lib_dir + cfg.variables.ROCKS_TREE = settings.rocks_dir + cfg.variables.SCRIPTS_DIR = settings.deploy_bin_dir + table.remove(cfg.rocks_servers, 1) +end + +local function prepare_sandbox(file) + local root_dir = fs.make_temp_dir(file):gsub("/+$", "") + cfg.root_dir = root_dir + cfg.rocks_dir = path.rocks_dir(root_dir) + cfg.deploy_bin_dir = path.deploy_bin_dir(root_dir) + cfg.variables.ROCKS_TREE = cfg.rocks_dir + cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir + return root_dir +end + +local function validate_rockspec(file) + local ok, err, errcode = build.build_rockspec(file, true, "one") + if not ok then + util.printerr(err) + end + return ok, err, errcode +end + +local function validate_src_rock(file) + local ok, err, errcode = build.build_rock(file, false, "one") + if not ok then + util.printerr(err) + end + return ok, err, errcode +end + +local function validate_rock(file) + local ok, err, errcode = install.install_binary_rock(file, "one") + if not ok then + util.printerr(err) + end + return ok, err, errcode +end + +function validate.command(flags, repo) + repo = repo or cfg.rocks_dir + + util.printout("Verifying contents of "..repo) + + local results = { + ok = {} + } + local settings = save_settings(repo) + local sandbox + if flags["quick"] then + sandbox = prepare_sandbox("luarocks_validate") + end + if not fs.exists(repo) then + return nil, repo.." is not a local repository." + end + for file in fs.dir(repo) do for _=1,1 do + if file == "manifest" or file == "index.html" then + break -- continue for + end + local pathname = fs.absolute_name(dir.path(repo, file)) + if not flags["quick"] then + sandbox = prepare_sandbox(file) + end + local ok, err, errcode + util.printout() + util.printout("Verifying "..pathname) + if file:match("%.rockspec$") then + ok, err, errcode = validate_rockspec(pathname, "one") + elseif file:match("%.src%.rock$") then + ok, err, errcode = validate_src_rock(pathname) + elseif file:match("%.rock$") then + ok, err, errcode = validate_rock(pathname) + end + if ok then + table.insert(results.ok, {file=file} ) + else + if not errcode then + errcode = "misc" + end + if not results[errcode] then + results[errcode] = {} + end + table.insert(results[errcode], {file=file, err=err} ) + end + util.run_scheduled_functions() + if not flags["quick"] then + fs.delete(sandbox) + end + repeat until not fs.pop_dir() + end end + if flags["quick"] then + fs.delete(sandbox) + end + restore_settings(settings) + util.title("Results:") + util.printout("OK: "..tostring(#results.ok)) + for _, entry in ipairs(results.ok) do + util.printout(entry.file) + end + for errcode, errors in pairs(results) do + if errcode ~= "ok" then + util.printout() + util.printout(errcode.." errors: "..tostring(#errors)) + for _, entry in ipairs(errors) do + util.printout(entry.file, entry.err) + end + end + end + + util.title("Summary:") + local total = 0 + for errcode, errors in pairs(results) do + util.printout(errcode..": "..tostring(#errors)) + total = total + #errors + end + util.printout("Total: "..total) + return true +end + + +return validate diff --git a/Utils/luarocks/lua/luarocks/write_rockspec.lua b/Utils/luarocks/lua/luarocks/write_rockspec.lua new file mode 100644 index 000000000..33edeb1b4 --- /dev/null +++ b/Utils/luarocks/lua/luarocks/write_rockspec.lua @@ -0,0 +1,375 @@ + +local write_rockspec = {} +package.loaded["luarocks.write_rockspec"] = write_rockspec + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local path = require("luarocks.path") +local persist = require("luarocks.persist") +local type_check = require("luarocks.type_check") +local util = require("luarocks.util") + +util.add_run_function(write_rockspec) +write_rockspec.help_summary = "Write a template for a rockspec file." +write_rockspec.help_arguments = "[--output= ...] [] [] [|]" +write_rockspec.help = [[ +This command writes an initial version of a rockspec file, +based on a name, a version, and a location (an URL or a local path). +If only two arguments are given, the first one is considered the name and the +second one is the location. +If only one argument is given, it must be the location. +If no arguments are given, current directory is used as location. +LuaRocks will attempt to infer name and version if not given, +using 'scm' as default version. + +Note that the generated file is a _starting point_ for writing a +rockspec, and is not guaranteed to be complete or correct. + +--output= Write the rockspec with the given filename. + If not given, a file is written in the current + directory with a filename based on given name and version. +--license="" A license string, such as "MIT/X11" or "GNU GPL v3". +--summary="" A short one-line description summary. +--detailed="" A longer description string. +--homepage= Project homepage. +--lua-version= Supported Lua versions. Accepted values are "5.1", "5.2", + "5.3", "5.1,5.2", "5.2,5.3", or "5.1,5.2,5.3". +--rockspec-format= Rockspec format version, such as "1.0" or "1.1". +--tag= Tag to use. Will attempt to extract version number from it. +--lib=[,] A comma-separated list of libraries that C files need to + link to. +]] + +local function open_file(name) + return io.open(dir.path(fs.current_dir(), name), "r") +end + +local function get_url(rockspec) + local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false) + if err_code == "source.dir" then + file, temp_dir = err_file, err_temp_dir + elseif not file then + util.warning("Could not fetch sources - "..temp_dir) + return false + end + util.printout("File successfully downloaded. Making checksum and checking base dir...") + if fetch.is_basic_protocol(rockspec.source.protocol) then + rockspec.source.md5 = fs.get_md5(file) + end + local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url) + return true, found_dir or inferred_dir, temp_dir +end + +local function configure_lua_version(rockspec, luaver) + if luaver == "5.1" then + table.insert(rockspec.dependencies, "lua ~> 5.1") + elseif luaver == "5.2" then + table.insert(rockspec.dependencies, "lua ~> 5.2") + elseif luaver == "5.3" then + table.insert(rockspec.dependencies, "lua ~> 5.3") + elseif luaver == "5.1,5.2" then + table.insert(rockspec.dependencies, "lua >= 5.1, < 5.3") + elseif luaver == "5.2,5.3" then + table.insert(rockspec.dependencies, "lua >= 5.2, < 5.4") + elseif luaver == "5.1,5.2,5.3" then + table.insert(rockspec.dependencies, "lua >= 5.1, < 5.4") + else + util.warning("Please specify supported Lua version with --lua-version=. "..util.see_help("write_rockspec")) + end +end + +local function detect_description() + local fd = open_file("README.md") or open_file("README") + if not fd then return end + local data = fd:read("*a") + fd:close() + local paragraph = data:match("\n\n([^%[].-)\n\n") + if not paragraph then paragraph = data:match("\n\n(.*)") end + local summary, detailed + if paragraph then + detailed = paragraph + + if #paragraph < 80 then + summary = paragraph:gsub("\n", "") + else + summary = paragraph:gsub("\n", " "):match("([^.]*%.) ") + end + end + return summary, detailed +end + +local function detect_mit_license(data) + local strip_copyright = (data:gsub("Copyright [^\n]*\n", "")) + local sum = 0 + for i = 1, #strip_copyright do + local num = string.byte(strip_copyright:sub(i,i)) + if num > 32 and num <= 128 then + sum = sum + num + end + end + return sum == 78656 +end + +local simple_scm_protocols = { + git = true, ["git+http"] = true, ["git+https"] = true, + hg = true, ["hg+http"] = true, ["hg+https"] = true +} + +local function detect_url_from_command(program, args, directory) + local command = fs.Q(cfg.variables[program:upper()]).. " "..args + local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command))) + if not pipe then return nil end + local url = pipe:read("*a"):match("^([^\r\n]+)") + pipe:close() + if not url then return nil end + if not util.starts_with(url, program.."://") then + url = program.."+"..url + end + + if simple_scm_protocols[dir.split_url(url)] then + return url + end +end + +local function detect_scm_url(directory) + return detect_url_from_command("git", "config --get remote.origin.url", directory) or + detect_url_from_command("hg", "paths default", directory) +end + +local function show_license(rockspec) + local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt") + if not fd then return nil end + local data = fd:read("*a") + fd:close() + local is_mit = detect_mit_license(data) + util.title("License for "..rockspec.package..":") + util.printout(data) + util.printout() + return is_mit +end + +local function get_cmod_name(file) + local fd = open_file(file) + if not fd then return nil end + local data = fd:read("*a") + fd:close() + return (data:match("int%s+luaopen_([a-zA-Z0-9_]+)")) +end + +local luamod_blacklist = { + test = true, + tests = true, +} + +local function fill_as_builtin(rockspec, libs) + rockspec.build.type = "builtin" + rockspec.build.modules = {} + local prefix = "" + + for _, parent in ipairs({"src", "lua"}) do + if fs.is_dir(parent) then + fs.change_dir(parent) + prefix = parent.."/" + break + end + end + + local incdirs, libdirs + if libs then + incdirs, libdirs = {}, {} + for _, lib in ipairs(libs) do + local upper = lib:upper() + incdirs[#incdirs+1] = "$("..upper.."_INCDIR)" + libdirs[#libdirs+1] = "$("..upper.."_LIBDIR)" + end + end + + for _, file in ipairs(fs.find()) do + local luamod = file:match("(.*)%.lua$") + if luamod and not luamod_blacklist[luamod] then + rockspec.build.modules[path.path_to_module(file)] = prefix..file + else + local cmod = file:match("(.*)%.c$") + if cmod then + local modname = get_cmod_name(file) or path.path_to_module(file:gsub("%.c$", ".lua")) + rockspec.build.modules[modname] = { + sources = prefix..file, + libraries = libs, + incdirs = incdirs, + libdirs = libdirs, + } + end + end + end + + for _, directory in ipairs({ "doc", "docs", "samples", "tests" }) do + if fs.is_dir(directory) then + if not rockspec.build.copy_directories then + rockspec.build.copy_directories = {} + end + table.insert(rockspec.build.copy_directories, directory) + end + end + + if prefix ~= "" then + fs.pop_dir() + end +end + +local function rockspec_cleanup(rockspec) + rockspec.source.file = nil + rockspec.source.protocol = nil + rockspec.variables = nil + rockspec.name = nil +end + +function write_rockspec.command(flags, name, version, url_or_dir) + if not name then + url_or_dir = "." + elseif not version then + url_or_dir = name + name = nil + elseif not url_or_dir then + url_or_dir = version + version = nil + end + + if flags["tag"] then + if not version then + version = flags["tag"]:gsub("^v", "") + end + end + + local protocol, pathname = dir.split_url(url_or_dir) + if protocol == "file" then + if pathname == "." then + name = name or dir.base_name(fs.current_dir()) + end + elseif fetch.is_basic_protocol(protocol) then + local filename = dir.base_name(url_or_dir) + local newname, newversion = filename:match("(.*)-([^-]+)") + if newname then + name = name or newname + version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "") + end + else + name = name or dir.base_name(url_or_dir):gsub("%.[^.]+$", "") + end + + if not name then + return nil, "Could not infer rock name. "..util.see_help("write_rockspec") + end + version = version or "scm" + + local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") + + local rockspec = { + rockspec_format = flags["rockspec-format"], + package = name, + name = name:lower(), + version = version.."-1", + source = { + url = "*** please add URL for source tarball, zip or repository here ***", + tag = flags["tag"], + }, + description = { + summary = flags["summary"] or "*** please specify description summary ***", + detailed = flags["detailed"] or "*** please enter a detailed description ***", + homepage = flags["homepage"] or "*** please enter a project homepage ***", + license = flags["license"] or "*** please specify a license ***", + }, + dependencies = {}, + build = {}, + } + path.configure_paths(rockspec) + rockspec.source.protocol = protocol + + configure_lua_version(rockspec, flags["lua-version"]) + + local local_dir = url_or_dir + + if url_or_dir:match("://") then + rockspec.source.url = url_or_dir + rockspec.source.file = dir.base_name(url_or_dir) + rockspec.source.dir = "dummy" + if not fetch.is_basic_protocol(rockspec.source.protocol) then + if version ~= "scm" then + rockspec.source.tag = flags["tag"] or "v" .. version + end + end + rockspec.source.dir = nil + local ok, base_dir, temp_dir = get_url(rockspec) + if ok then + if base_dir ~= dir.base_name(url_or_dir) then + rockspec.source.dir = base_dir + end + end + if base_dir then + local_dir = dir.path(temp_dir, base_dir) + else + local_dir = nil + end + else + rockspec.source.url = detect_scm_url(local_dir) or rockspec.source.url + end + + if not local_dir then + local_dir = "." + end + + if not flags["homepage"] then + local url_protocol, url_path = dir.split_url(rockspec.source.url) + + if simple_scm_protocols[url_protocol] then + for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do + if util.starts_with(url_path, domain) then + rockspec.description.homepage = "https://"..url_path:gsub("%.git$", "") + break + end + end + end + end + + local libs = nil + if flags["lib"] then + libs = {} + rockspec.external_dependencies = {} + for lib in flags["lib"]:gmatch("([^,]+)") do + table.insert(libs, lib) + rockspec.external_dependencies[lib:upper()] = { + library = lib + } + end + end + + local ok, err = fs.change_dir(local_dir) + if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end + + if (not flags["summary"]) or (not flags["detailed"]) then + local summary, detailed = detect_description() + rockspec.description.summary = flags["summary"] or summary + rockspec.description.detailed = flags["detailed"] or detailed + end + + local is_mit = show_license(rockspec) + + if is_mit and not flags["license"] then + rockspec.description.license = "MIT" + end + + fill_as_builtin(rockspec, libs) + + rockspec_cleanup(rockspec) + + persist.save_from_table(filename, rockspec, type_check.rockspec_order) + + util.printout() + util.printout("Wrote template at "..filename.." -- you should now edit and finish it.") + util.printout() + + return true +end + +return write_rockspec diff --git a/Utils/luarocks/lua5.1.dll b/Utils/luarocks/lua5.1.dll new file mode 100644 index 000000000..b87f3b661 Binary files /dev/null and b/Utils/luarocks/lua5.1.dll differ diff --git a/Utils/luarocks/lua5.1.exe b/Utils/luarocks/lua5.1.exe new file mode 100644 index 000000000..dc1c2c35c Binary files /dev/null and b/Utils/luarocks/lua5.1.exe differ diff --git a/Utils/luarocks/lua5.1.lib b/Utils/luarocks/lua5.1.lib new file mode 100644 index 000000000..df9882765 Binary files /dev/null and b/Utils/luarocks/lua5.1.lib differ diff --git a/Utils/luarocks/lua51.dll b/Utils/luarocks/lua51.dll new file mode 100644 index 000000000..27ab26542 Binary files /dev/null and b/Utils/luarocks/lua51.dll differ diff --git a/Utils/luarocks/lua51.lib b/Utils/luarocks/lua51.lib new file mode 100644 index 000000000..74bcf3fb4 Binary files /dev/null and b/Utils/luarocks/lua51.lib differ diff --git a/Utils/luarocks/luac5.1.exe b/Utils/luarocks/luac5.1.exe new file mode 100644 index 000000000..6f87524e2 Binary files /dev/null and b/Utils/luarocks/luac5.1.exe differ diff --git a/Utils/luarocks/luarocks-admin.bat b/Utils/luarocks/luarocks-admin.bat new file mode 100644 index 000000000..e7bd4d12b --- /dev/null +++ b/Utils/luarocks/luarocks-admin.bat @@ -0,0 +1,43 @@ +@ECHO OFF +SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS + +SET "LUA_PATH=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?\init.lua;%LUA_PATH%" +IF NOT "%LUA_PATH_5_2%"=="" ( + SET "LUA_PATH_5_2=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?\init.lua;%LUA_PATH_5_2%" +) +IF NOT "%LUA_PATH_5_3%"=="" ( + SET "LUA_PATH_5_3=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?\init.lua;%LUA_PATH_5_3%" +) +SET "PATH=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks;%PATH%" +"C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua5.1" "C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\luarocks-admin.lua" %* +SET EXITCODE=%ERRORLEVEL% +IF NOT "%EXITCODE%"=="2" GOTO EXITLR + +REM Permission denied error, try and auto elevate... +REM already an admin? (checking to prevent loops) +NET SESSION >NUL 2>&1 +IF "%ERRORLEVEL%"=="0" GOTO EXITLR + +REM Do we have PowerShell available? +PowerShell /? >NUL 2>&1 +IF NOT "%ERRORLEVEL%"=="0" GOTO EXITLR + +:GETTEMPNAME +SET TMPFILE=%TEMP%\LuaRocks-Elevator-%RANDOM%.bat +IF EXIST "%TMPFILE%" GOTO :GETTEMPNAME + +ECHO @ECHO OFF > "%TMPFILE%" +ECHO CHDIR /D %CD% >> "%TMPFILE%" +ECHO ECHO %0 %* >> "%TMPFILE%" +ECHO ECHO. >> "%TMPFILE%" +ECHO CALL %0 %* >> "%TMPFILE%" +ECHO ECHO. >> "%TMPFILE%" +ECHO ECHO Press any key to close this window... >> "%TMPFILE%" +ECHO PAUSE ^> NUL >> "%TMPFILE%" +ECHO DEL "%TMPFILE%" >> "%TMPFILE%" + +ECHO Now retrying as a privileged user... +PowerShell -Command (New-Object -com 'Shell.Application').ShellExecute('%TMPFILE%', '', '', 'runas') + +:EXITLR +exit /b %EXITCODE% diff --git a/Utils/luarocks/luarocks-admin.lua b/Utils/luarocks/luarocks-admin.lua new file mode 100644 index 000000000..2890d1f19 --- /dev/null +++ b/Utils/luarocks/luarocks-admin.lua @@ -0,0 +1,19 @@ +#!/usr/bin/env lua + +-- this should be loaded first. +local cfg = require("luarocks.cfg") + +local loader = require("luarocks.loader") +local command_line = require("luarocks.command_line") + +program_description = "LuaRocks repository administration interface" + +commands = { + help = "luarocks.help", + make_manifest = "luarocks.make_manifest", + add = "luarocks.add", + remove = "luarocks.admin_remove", + refresh_cache = "luarocks.refresh_cache", +} + +command_line.run_command(...) diff --git a/Utils/luarocks/luarocks.bat b/Utils/luarocks/luarocks.bat new file mode 100644 index 000000000..373068966 --- /dev/null +++ b/Utils/luarocks/luarocks.bat @@ -0,0 +1,43 @@ +@ECHO OFF +SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS + +SET "LUA_PATH=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?\init.lua;%LUA_PATH%" +IF NOT "%LUA_PATH_5_2%"=="" ( + SET "LUA_PATH_5_2=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?\init.lua;%LUA_PATH_5_2%" +) +IF NOT "%LUA_PATH_5_3%"=="" ( + SET "LUA_PATH_5_3=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua\?\init.lua;%LUA_PATH_5_3%" +) +SET "PATH=C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks;%PATH%" +"C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\lua5.1" "C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\luarocks.lua" %* +SET EXITCODE=%ERRORLEVEL% +IF NOT "%EXITCODE%"=="2" GOTO EXITLR + +REM Permission denied error, try and auto elevate... +REM already an admin? (checking to prevent loops) +NET SESSION >NUL 2>&1 +IF "%ERRORLEVEL%"=="0" GOTO EXITLR + +REM Do we have PowerShell available? +PowerShell /? >NUL 2>&1 +IF NOT "%ERRORLEVEL%"=="0" GOTO EXITLR + +:GETTEMPNAME +SET TMPFILE=%TEMP%\LuaRocks-Elevator-%RANDOM%.bat +IF EXIST "%TMPFILE%" GOTO :GETTEMPNAME + +ECHO @ECHO OFF > "%TMPFILE%" +ECHO CHDIR /D %CD% >> "%TMPFILE%" +ECHO ECHO %0 %* >> "%TMPFILE%" +ECHO ECHO. >> "%TMPFILE%" +ECHO CALL %0 %* >> "%TMPFILE%" +ECHO ECHO. >> "%TMPFILE%" +ECHO ECHO Press any key to close this window... >> "%TMPFILE%" +ECHO PAUSE ^> NUL >> "%TMPFILE%" +ECHO DEL "%TMPFILE%" >> "%TMPFILE%" + +ECHO Now retrying as a privileged user... +PowerShell -Command (New-Object -com 'Shell.Application').ShellExecute('%TMPFILE%', '', '', 'runas') + +:EXITLR +exit /b %EXITCODE% diff --git a/Utils/luarocks/luarocks.lua b/Utils/luarocks/luarocks.lua new file mode 100644 index 000000000..be6c2b811 --- /dev/null +++ b/Utils/luarocks/luarocks.lua @@ -0,0 +1,33 @@ +#!/usr/bin/env lua + +-- this should be loaded first. +local cfg = require("luarocks.cfg") + +local loader = require("luarocks.loader") +local command_line = require("luarocks.command_line") + +program_description = "LuaRocks main command-line interface" + +commands = { + help = "luarocks.help", + pack = "luarocks.pack", + unpack = "luarocks.unpack", + build = "luarocks.build", + install = "luarocks.install", + search = "luarocks.search", + list = "luarocks.list", + remove = "luarocks.remove", + make = "luarocks.make", + download = "luarocks.download", + path = "luarocks.path_cmd", + show = "luarocks.show", + new_version = "luarocks.new_version", + lint = "luarocks.lint", + write_rockspec = "luarocks.write_rockspec", + purge = "luarocks.purge", + doc = "luarocks.doc", + upload = "luarocks.upload", + config = "luarocks.config_cmd", +} + +command_line.run_command(...) diff --git a/Utils/luarocks/luarocksw.bat b/Utils/luarocks/luarocksw.bat new file mode 100644 index 000000000..8ac029209 --- /dev/null +++ b/Utils/luarocks/luarocksw.bat @@ -0,0 +1,49 @@ +@echo off +setlocal +SET MYPATH=%~dp0 + +IF NOT [%1]==[] GOTO LETSGO +ECHO Same as 'luarocks' command, except this +ECHO command will pause after completion, allowing for +ECHO examination of output. +ECHO. +ECHO For LuaRocks help use: +ECHO LUAROCKS HELP +ECHO. +ECHO OPTIONS specific for LUAROCKSW: +ECHO REMOVEALL is a command specific to this batch file +ECHO the option takes a FULL ROCKSPEC filename and then +ECHO it will strip path, version and extension info from +ECHO it before executing the LUAROCKS REMOVE command +ECHO Example: +ECHO luarocksw remove "c:\somedir\modulename-1.0-1.rockspec" +ECHO will execute: +ECHO luarocks remove "c:\somedir\modulename-1.0-1.rockspec" +ECHO and will only remove the specific version 1.0 from the +ECHO system. +ECHO luarocksw removeall "c:\somedir\modulename-1.0-1.rockspec" +ECHO will execute: +ECHO luarocks remove modulename +ECHO and will remove all versions of this package +ECHO. +GOTO END + +:LETSGO +REM if REMOVEALL command then info must be stripped from the parameter +if [%1]==[removeall] goto REMOVEALL + +REM execute LuaRocks and wait for results +echo executing: luarocks %* +call "%MYPATH%luarocks" %* +pause +goto END + +:REMOVEALL +for /f "delims=-" %%a in ("%~n2") do ( + echo executing: luarocks remove %%a + "%MYPATH%luarocks" remove "%%a" + pause + goto END +) + +:END \ No newline at end of file diff --git a/Utils/luarocks/msvcm80.dll b/Utils/luarocks/msvcm80.dll new file mode 100644 index 000000000..c751385bd Binary files /dev/null and b/Utils/luarocks/msvcm80.dll differ diff --git a/Utils/luarocks/msvcp80.dll b/Utils/luarocks/msvcp80.dll new file mode 100644 index 000000000..f0b52ebf1 Binary files /dev/null and b/Utils/luarocks/msvcp80.dll differ diff --git a/Utils/luarocks/msvcr80.dll b/Utils/luarocks/msvcr80.dll new file mode 100644 index 000000000..53c005efc Binary files /dev/null and b/Utils/luarocks/msvcr80.dll differ diff --git a/Utils/luarocks/rclauncher.c b/Utils/luarocks/rclauncher.c new file mode 100644 index 000000000..77459f464 --- /dev/null +++ b/Utils/luarocks/rclauncher.c @@ -0,0 +1,139 @@ + +/* +** Simple Lua interpreter. +** This program is used to run a Lua file embedded as a resource. +** It creates a Lua state, opens all its standard libraries, and run +** the Lua file in a protected environment just to redirect the error +** messages to stdout and stderr. +** +** $Id: rclauncher.c,v 1.1 2008/06/30 14:29:59 carregal Exp $ +*/ + +#include +#include + +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#include +#include +#include + +/* +** Report error message. +** Assumes that the error message is on top of the stack. +*/ +static int report (lua_State *L) { + fprintf (stderr, "lua: fatal error: `%s'\n", lua_tostring (L, -1)); + fflush (stderr); + printf ("Content-type: text/plain\n\nConfiguration fatal error: see error log!\n"); + printf ("%s", lua_tostring(L, -1)); + return 1; +} + +static int runlua (lua_State *L, const char *lua_string, int argc, char *argv[]) { + int err_func; + int err; + + lua_getglobal(L, "debug"); + lua_pushliteral(L, "traceback"); + lua_gettable(L, -2); + err_func = lua_gettop (L); + err = luaL_loadstring (L, lua_string); + if(!err) { + int i; + // fill global arg table + lua_getglobal(L, "arg"); + for(i = 1; i < argc; i++) + { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i); + } + lua_pop(L, 1); + // fill parameters (in vararg '...') + for(i = 1; i < argc; i++) + lua_pushstring(L, argv[i]); + return lua_pcall (L, argc - 1, LUA_MULTRET, err_func); + } else return err; +} + +static DWORD GetModulePath( HINSTANCE hInst, LPTSTR pszBuffer, DWORD dwSize ) +// +// Return the size of the path in bytes. +{ + DWORD dwLength = GetModuleFileName( hInst, pszBuffer, dwSize ); + if( dwLength ) + { + while( dwLength && pszBuffer[ dwLength ] != '.' ) + { + dwLength--; + } + + if( dwLength ) + pszBuffer[ dwLength ] = '\000'; + } + return dwLength; +} + + +/* +** MAIN +*/ +int main (int argc, char *argv[]) { + char name[ MAX_PATH ]; + DWORD dwLength; + int size; + luaL_Buffer b; + int i; +#ifdef UNICODE + TCHAR lua_wstring[4098]; +#endif + char lua_string[4098]; + lua_State *L = luaL_newstate(); + (void)argc; /* avoid "unused parameter" warning */ + luaL_openlibs(L); + lua_newtable(L); // create arg table + lua_pushstring(L, argv[0]); // add interpreter to arg table + lua_rawseti(L, -2, -1); + dwLength = GetModulePath( NULL, name, MAX_PATH ); + if(dwLength) { /* Optional bootstrap */ + strcat(name, ".lua"); + lua_pushstring(L, name); // add lua script to arg table + lua_rawseti(L, -2, 0); + lua_setglobal(L,"arg"); // set global arg table + if(!luaL_loadfile (L, name)) { + if(lua_pcall (L, 0, LUA_MULTRET, 0)) { + report (L); + lua_close (L); + return EXIT_FAILURE; + } + } + } + else + { + lua_pushstring(L, argv[0]); // no lua script, so add interpreter again, now as lua script + lua_rawseti(L, -2, 0); + lua_setglobal(L,"arg"); // set global arg table + } + + luaL_buffinit(L, &b); + for(i = 1; ; i++) { +#ifdef UNICODE + size = LoadString(GetModuleHandle(NULL), i, lua_wstring, + sizeof(lua_string)/sizeof(TCHAR)); + if(size > 0) wcstombs(lua_string, lua_wstring, size + 1); +#else + size = LoadString(GetModuleHandle(NULL), i, lua_string, + sizeof(lua_string)/sizeof(char)); +#endif + if(size) luaL_addlstring(&b, lua_string, size); else break; + } + luaL_pushresult(&b); + if (runlua (L, lua_tostring(L, -1), argc, argv)) { + report (L); + lua_close (L); + return EXIT_FAILURE; + } + lua_close (L); + return EXIT_SUCCESS; +} diff --git a/Utils/luarocks/systree/bin/luadocumentor.bat b/Utils/luarocks/systree/bin/luadocumentor.bat new file mode 100644 index 000000000..e16f6f7e9 --- /dev/null +++ b/Utils/luarocks/systree/bin/luadocumentor.bat @@ -0,0 +1,3 @@ +@echo off +"C:\Users\Hugues\Documents\GitHub\MOOSE\Utils\luarocks\lua5.1" -e "package.path=\"C:\\Users\\Hugues\\AppData\\Roaming/luarocks/share/lua/5.1/?.lua;C:\\Users\\Hugues\\AppData\\Roaming/luarocks/share/lua/5.1/?/init.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\\systree/share/lua/5.1/?.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\\systree/share/lua/5.1/?/init.lua;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks/lua/?.lua;\"..package.path; package.cpath=\"C:\\Users\\Hugues\\AppData\\Roaming/luarocks/lib/lua/5.1/?.dll;C:/Users/Hugues/Documents/GitHub/MOOSE/Utils/luarocks\\systree/lib/lua/5.1/?.dll;\"..package.cpath" -e "local k,l,_=pcall(require,\"luarocks.loader\") _=k and l.add_context(\"luadocumentor\",\"0.1.5-1\")" "C:\Users\Hugues\Documents\GitHub\MOOSE\Utils\luarocks\systree\lib\luarocks\rocks\luadocumentor\0.1.5-1\bin\luadocumentor" %* +exit /b %ERRORLEVEL% diff --git a/Utils/luarocks/systree/lib/lua/5.1/checks.dll b/Utils/luarocks/systree/lib/lua/5.1/checks.dll new file mode 100644 index 000000000..9959cdc01 Binary files /dev/null and b/Utils/luarocks/systree/lib/lua/5.1/checks.dll differ diff --git a/Utils/luarocks/systree/lib/lua/5.1/lfs.dll b/Utils/luarocks/systree/lib/lua/5.1/lfs.dll new file mode 100644 index 000000000..9249ec0eb Binary files /dev/null and b/Utils/luarocks/systree/lib/lua/5.1/lfs.dll differ diff --git a/Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/checks/1.0-1/checks-1.0-1.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/checks/1.0-1/rock_manifest similarity index 63% rename from Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/checks/1.0-1/rock_manifest index 07ae2133a..b45de952e 100644 --- a/Utils/lua/5.1/lib/luarocks/rocks/checks/1.0-1/rock_manifest +++ b/Utils/luarocks/systree/lib/luarocks/rocks/checks/1.0-1/rock_manifest @@ -1,6 +1,6 @@ rock_manifest = { ["checks-1.0-1.rockspec"] = "70af2f5dd173774a16b9e7cfdfd12ecd", lib = { - ["checks.dll"] = "5342726d76176ca95ebe25c7b07ca6ac" + ["checks.dll"] = "2f86fd2ab34447e9e211836fd56939ae" } } diff --git a/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/bin/luadocumentor b/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/bin/luadocumentor new file mode 100644 index 000000000..dccc8df18 --- /dev/null +++ b/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/bin/luadocumentor @@ -0,0 +1,178 @@ +#!/usr/bin/lua +-------------------------------------------------------------------------------- +-- Copyright (c) 2012-2014 Sierra Wireless. +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v1.0 +-- which accompanies this distribution, and is available at +-- http://www.eclipse.org/legal/epl-v10.html +-- +-- Contributors: +-- Kevin KIN-FOO +-- - initial API and implementation and initial documentation +-------------------------------------------------------------------------------- + +-- Check interpreter version +if _VERSION ~= "Lua 5.1" then + print("Luadocumentor is only compatible with Lua 5.1") + return +end + +-- +-- Defining help message. +-- + +-- This message is compliant to 'lapp', which will match options and arguments +-- from command line. +local help = [[luadocumentor v0.1.4: tool for Lua Documentation Language + -f, --format (default doc) Define output format : + * doc: Will produce HTML documentation from specified file(s) or directories. + * api: Will produce API file(s) from specified file(s) or directories. + -d, --dir (default docs) Define an output directory. If the given directory doesn't exist, it will be created. + -h, --help Display the help. + -n, --noheuristic Do not use code analysis, use only comments to generate documentation. + -s, --style (default !) The path of your own css file, if you don't want to use the default one. (usefull only for the doc format) + [directories|files] Define the paths or the directories of inputs files. Only Lua or C files containing a @module tag will be considered. +]] +local docgenerator = require 'docgenerator' +local lddextractor = require 'lddextractor' +local lapp = require 'pl.lapp' +local args = lapp( help ) + +if not args or #args < 1 then + print('No directory provided') + return +elseif args.help then + -- Just print help + print( help ) + return +end + +-- +-- define css file name +-- +local cssfilename = "stylesheet.css" + +-- +-- Parse files from given folders +-- + +-- Check if all folders exist +local fs = require 'fs.lfs' +local allpresent, missing = fs.checkdirectory(args) + +-- Some of given directories are absent +if missing then + -- List missing directories + print 'Unable to open' + for _, file in ipairs( missing ) do + print('\t'.. file) + end + return +end + +-- Get files from given directories +local filestoparse, error = fs.filelist( args ) +if not filestoparse then + print ( error ) + return +end + +-- +-- Generate documentation only files +-- +if args.format == 'api' then + for _, filename in ipairs( filestoparse ) do + + -- Loading file content + print('Dealing with "'..filename..'".') + local file, error = io.open(filename, 'r') + if not file then + print ('Unable to open "'..filename.."'.\n"..error) + else + local code = file:read('*all') + file:close() + + -- + -- Creating comment file + -- + local commentfile, error = lddextractor.generatecommentfile(filename, code) + + -- Getting module name + -- Optimize me + local module, moduleerror = lddextractor.generateapimodule(filename, code) + if not commentfile then + print('Unable to create documentation file for "'..filename..'"\n'..error) + elseif not module or not module.name then + local error = moduleerror and '\n'..moduleerror or '' + print('Unable to compute module name for "'..filename..'".'..error) + else + -- + -- Flush documentation file on disk + -- + local path = args.dir..fs.separator..module.name..'.lua' + local status, err = fs.fill(path, commentfile) + if not status then + print(err) + end + end + end + end + print('Done') + return +end + +-- Deal only supported output types +if args.format ~= 'doc' then + print ('"'..args.format..'" format is not handled.') + return +end +-- Generate html form files +local parsedfiles, unparsed = docgenerator.generatedocforfiles(filestoparse, cssfilename,args.noheuristic) + +-- Show warnings on unparsed files +if #unparsed > 0 then + for _, faultyfile in ipairs( unparsed ) do + print( faultyfile ) + end +end +-- This loop is just for counting parsed files +-- TODO: Find a more elegant way to do it +local parsedfilescount = 0 +for _, p in pairs(parsedfiles) do + parsedfilescount = parsedfilescount + 1 +end +print (parsedfilescount .. ' file(s) parsed.') + +-- Create html files +local generated = 0 +for _, apifile in pairs ( parsedfiles ) do + local status, err = fs.fill(args.dir..fs.separator..apifile.name..'.html', apifile.body) + if status then + generated = generated + 1 + else + print( 'Unable to create '..apifile.name..'.html on disk.') + end +end +print (generated .. ' file(s) generated.') + +-- Copying css +local csscontent +if args.style == '!' then + csscontent = require 'defaultcss' +else + local css, error = io.open(args.style, 'r') + if not css then + print('Unable to open "'..args.style .. '".\n'..error) + return + end + csscontent = css:read("*all") + css:close() +end + +local status, error = fs.fill(args.dir..fs.separator..cssfilename, csscontent) +if not status then + print(error) + return +end +print('Adding css') +print('Done') diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE b/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE rename to Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/LICENSE diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md b/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md rename to Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/doc/README.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/luadocumentor-0.1.5-1.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/luadocumentor/0.1.5-1/rock_manifest diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/doc.css diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/examples.html diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/index.html diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/license.html diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/luafilesystem.png diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/doc/us/manual.html diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/luafilesystem-1.6.3-2.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest similarity index 91% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest index b0f7b6332..1b646b631 100644 --- a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest +++ b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/rock_manifest @@ -10,7 +10,7 @@ rock_manifest = { } }, lib = { - ["lfs.dll"] = "165694685cffa6014be4ca8cbb7d920b" + ["lfs.dll"] = "bb5e7f0d82350913063363393fafb3e3" }, ["luafilesystem-1.6.3-2.rockspec"] = "eb0ef7c190516892eb8357af799eea5f", tests = { diff --git a/Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua b/Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua rename to Utils/luarocks/systree/lib/luarocks/rocks/luafilesystem/1.6.3-2/tests/test.lua diff --git a/Utils/lua/5.1/lib/luarocks/rocks/manifest b/Utils/luarocks/systree/lib/luarocks/rocks/manifest similarity index 99% rename from Utils/lua/5.1/lib/luarocks/rocks/manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/manifest index 3b022bd4f..b3bae3c19 100644 --- a/Utils/lua/5.1/lib/luarocks/rocks/manifest +++ b/Utils/luarocks/systree/lib/luarocks/rocks/manifest @@ -31,7 +31,8 @@ dependencies = { } }, name = "lua" - }, { + }, + { constraints = { { op = "~>", @@ -41,7 +42,8 @@ dependencies = { } }, name = "luafilesystem" - }, { + }, + { constraints = { { op = "~>", @@ -51,7 +53,8 @@ dependencies = { } }, name = "markdown" - }, { + }, + { constraints = { { op = "~>", @@ -61,7 +64,8 @@ dependencies = { } }, name = "metalua-compiler" - }, { + }, + { constraints = { { op = "~>", @@ -116,7 +120,8 @@ dependencies = { } }, name = "lua" - }, { + }, + { constraints = { { op = "~>", @@ -126,7 +131,8 @@ dependencies = { } }, name = "luafilesystem" - }, { + }, + { constraints = { { op = ">=", diff --git a/Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/markdown/0.32-2/markdown-0.32-2.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/markdown/0.32-2/rock_manifest similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/markdown/0.32-2/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/markdown/0.32-2/rock_manifest diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-compiler.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README-parser.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/doc/README.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/metalua-compiler-0.7.3-1.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-compiler/0.7.3-1/rock_manifest diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-compiler.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README-parser.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/doc/README.md diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/metalua-parser-0.7.3-2.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/metalua-parser/0.7.3-2/rock_manifest diff --git a/Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec b/Utils/luarocks/systree/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec rename to Utils/luarocks/systree/lib/luarocks/rocks/penlight/0.9.8-1/penlight-0.9.8-1.rockspec diff --git a/Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest b/Utils/luarocks/systree/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest similarity index 100% rename from Utils/lua/5.1/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest rename to Utils/luarocks/systree/lib/luarocks/rocks/penlight/0.9.8-1/rock_manifest diff --git a/Utils/lua/5.1/share/lua/5.1/defaultcss.lua b/Utils/luarocks/systree/share/lua/5.1/defaultcss.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/defaultcss.lua rename to Utils/luarocks/systree/share/lua/5.1/defaultcss.lua diff --git a/Utils/lua/5.1/share/lua/5.1/docgenerator.lua b/Utils/luarocks/systree/share/lua/5.1/docgenerator.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/docgenerator.lua rename to Utils/luarocks/systree/share/lua/5.1/docgenerator.lua diff --git a/Utils/lua/5.1/share/lua/5.1/extractors.lua b/Utils/luarocks/systree/share/lua/5.1/extractors.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/extractors.lua rename to Utils/luarocks/systree/share/lua/5.1/extractors.lua diff --git a/Utils/lua/5.1/share/lua/5.1/fs/lfs.lua b/Utils/luarocks/systree/share/lua/5.1/fs/lfs.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/fs/lfs.lua rename to Utils/luarocks/systree/share/lua/5.1/fs/lfs.lua diff --git a/Utils/lua/5.1/share/lua/5.1/lddextractor.lua b/Utils/luarocks/systree/share/lua/5.1/lddextractor.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/lddextractor.lua rename to Utils/luarocks/systree/share/lua/5.1/lddextractor.lua diff --git a/Utils/lua/5.1/share/lua/5.1/markdown.lua b/Utils/luarocks/systree/share/lua/5.1/markdown.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/markdown.lua rename to Utils/luarocks/systree/share/lua/5.1/markdown.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/ast_to_src.mlua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/ast_to_src.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/ast_to_src.mlua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/ast_to_src.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/compile.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/compile.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/compile.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/compile.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lcode.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/lcode.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lcode.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/lcode.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/ldump.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/ldump.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/ldump.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/ldump.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/bytecode/lopcodes.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/globals.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/globals.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/globals.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/globals.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/generator.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/annot/generator.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/generator.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/annot/generator.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/annot/grammar.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/expr.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/expr.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/expr.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/expr.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/ext.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/ext.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/ext.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/ext.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/lexer.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/lexer.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/lexer.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/lexer.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/meta.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/meta.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/meta.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/meta.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/misc.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/misc.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/misc.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/misc.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/stat.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/stat.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/stat.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/stat.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/table.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/table.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/compiler/parser/table.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/compiler/parser/table.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/extension/comprehension.mlua b/Utils/luarocks/systree/share/lua/5.1/metalua/extension/comprehension.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/extension/comprehension.mlua rename to Utils/luarocks/systree/share/lua/5.1/metalua/extension/comprehension.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/extension/match.mlua b/Utils/luarocks/systree/share/lua/5.1/metalua/extension/match.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/extension/match.mlua rename to Utils/luarocks/systree/share/lua/5.1/metalua/extension/match.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/grammar/generator.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/grammar/generator.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/grammar/generator.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/grammar/generator.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/grammar/lexer.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/grammar/lexer.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/grammar/lexer.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/grammar/lexer.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/loader.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/loader.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/loader.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/loader.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/pprint.lua b/Utils/luarocks/systree/share/lua/5.1/metalua/pprint.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/pprint.lua rename to Utils/luarocks/systree/share/lua/5.1/metalua/pprint.lua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/repl.mlua b/Utils/luarocks/systree/share/lua/5.1/metalua/repl.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/repl.mlua rename to Utils/luarocks/systree/share/lua/5.1/metalua/repl.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/treequery.mlua b/Utils/luarocks/systree/share/lua/5.1/metalua/treequery.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/treequery.mlua rename to Utils/luarocks/systree/share/lua/5.1/metalua/treequery.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/metalua/treequery/walk.mlua b/Utils/luarocks/systree/share/lua/5.1/metalua/treequery/walk.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/metalua/treequery/walk.mlua rename to Utils/luarocks/systree/share/lua/5.1/metalua/treequery/walk.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/models/apimodel.lua b/Utils/luarocks/systree/share/lua/5.1/models/apimodel.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/models/apimodel.lua rename to Utils/luarocks/systree/share/lua/5.1/models/apimodel.lua diff --git a/Utils/lua/5.1/share/lua/5.1/models/apimodelbuilder.lua b/Utils/luarocks/systree/share/lua/5.1/models/apimodelbuilder.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/models/apimodelbuilder.lua rename to Utils/luarocks/systree/share/lua/5.1/models/apimodelbuilder.lua diff --git a/Utils/lua/5.1/share/lua/5.1/models/internalmodel.lua b/Utils/luarocks/systree/share/lua/5.1/models/internalmodel.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/models/internalmodel.lua rename to Utils/luarocks/systree/share/lua/5.1/models/internalmodel.lua diff --git a/Utils/lua/5.1/share/lua/5.1/models/internalmodelbuilder.mlua b/Utils/luarocks/systree/share/lua/5.1/models/internalmodelbuilder.mlua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/models/internalmodelbuilder.mlua rename to Utils/luarocks/systree/share/lua/5.1/models/internalmodelbuilder.mlua diff --git a/Utils/lua/5.1/share/lua/5.1/models/ldparser.lua b/Utils/luarocks/systree/share/lua/5.1/models/ldparser.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/models/ldparser.lua rename to Utils/luarocks/systree/share/lua/5.1/models/ldparser.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/Date.lua b/Utils/luarocks/systree/share/lua/5.1/pl/Date.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/Date.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/Date.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/List.lua b/Utils/luarocks/systree/share/lua/5.1/pl/List.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/List.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/List.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/Map.lua b/Utils/luarocks/systree/share/lua/5.1/pl/Map.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/Map.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/Map.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/MultiMap.lua b/Utils/luarocks/systree/share/lua/5.1/pl/MultiMap.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/MultiMap.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/MultiMap.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/OrderedMap.lua b/Utils/luarocks/systree/share/lua/5.1/pl/OrderedMap.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/OrderedMap.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/OrderedMap.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/Set.lua b/Utils/luarocks/systree/share/lua/5.1/pl/Set.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/Set.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/Set.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/app.lua b/Utils/luarocks/systree/share/lua/5.1/pl/app.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/app.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/app.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/array2d.lua b/Utils/luarocks/systree/share/lua/5.1/pl/array2d.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/array2d.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/array2d.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/class.lua b/Utils/luarocks/systree/share/lua/5.1/pl/class.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/class.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/class.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/comprehension.lua b/Utils/luarocks/systree/share/lua/5.1/pl/comprehension.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/comprehension.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/comprehension.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/config.lua b/Utils/luarocks/systree/share/lua/5.1/pl/config.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/config.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/config.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/data.lua b/Utils/luarocks/systree/share/lua/5.1/pl/data.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/data.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/data.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/dir.lua b/Utils/luarocks/systree/share/lua/5.1/pl/dir.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/dir.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/dir.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/file.lua b/Utils/luarocks/systree/share/lua/5.1/pl/file.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/file.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/file.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/func.lua b/Utils/luarocks/systree/share/lua/5.1/pl/func.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/func.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/func.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/init.lua b/Utils/luarocks/systree/share/lua/5.1/pl/init.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/init.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/init.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/input.lua b/Utils/luarocks/systree/share/lua/5.1/pl/input.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/input.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/input.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/lapp.lua b/Utils/luarocks/systree/share/lua/5.1/pl/lapp.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/lapp.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/lapp.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/lexer.lua b/Utils/luarocks/systree/share/lua/5.1/pl/lexer.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/lexer.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/lexer.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/luabalanced.lua b/Utils/luarocks/systree/share/lua/5.1/pl/luabalanced.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/luabalanced.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/luabalanced.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/operator.lua b/Utils/luarocks/systree/share/lua/5.1/pl/operator.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/operator.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/operator.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/path.lua b/Utils/luarocks/systree/share/lua/5.1/pl/path.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/path.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/path.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/permute.lua b/Utils/luarocks/systree/share/lua/5.1/pl/permute.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/permute.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/permute.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/platf/luajava.lua b/Utils/luarocks/systree/share/lua/5.1/pl/platf/luajava.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/platf/luajava.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/platf/luajava.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/pretty.lua b/Utils/luarocks/systree/share/lua/5.1/pl/pretty.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/pretty.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/pretty.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/seq.lua b/Utils/luarocks/systree/share/lua/5.1/pl/seq.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/seq.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/seq.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/sip.lua b/Utils/luarocks/systree/share/lua/5.1/pl/sip.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/sip.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/sip.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/strict.lua b/Utils/luarocks/systree/share/lua/5.1/pl/strict.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/strict.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/strict.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/stringio.lua b/Utils/luarocks/systree/share/lua/5.1/pl/stringio.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/stringio.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/stringio.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/stringx.lua b/Utils/luarocks/systree/share/lua/5.1/pl/stringx.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/stringx.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/stringx.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/tablex.lua b/Utils/luarocks/systree/share/lua/5.1/pl/tablex.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/tablex.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/tablex.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/template.lua b/Utils/luarocks/systree/share/lua/5.1/pl/template.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/template.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/template.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/test.lua b/Utils/luarocks/systree/share/lua/5.1/pl/test.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/test.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/test.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/text.lua b/Utils/luarocks/systree/share/lua/5.1/pl/text.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/text.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/text.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/utils.lua b/Utils/luarocks/systree/share/lua/5.1/pl/utils.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/utils.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/utils.lua diff --git a/Utils/lua/5.1/share/lua/5.1/pl/xml.lua b/Utils/luarocks/systree/share/lua/5.1/pl/xml.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/pl/xml.lua rename to Utils/luarocks/systree/share/lua/5.1/pl/xml.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/file.lua b/Utils/luarocks/systree/share/lua/5.1/template/file.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/file.lua rename to Utils/luarocks/systree/share/lua/5.1/template/file.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/index.lua b/Utils/luarocks/systree/share/lua/5.1/template/index.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/index.lua rename to Utils/luarocks/systree/share/lua/5.1/template/index.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/index/recordtypedef.lua b/Utils/luarocks/systree/share/lua/5.1/template/index/recordtypedef.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/index/recordtypedef.lua rename to Utils/luarocks/systree/share/lua/5.1/template/index/recordtypedef.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/item.lua b/Utils/luarocks/systree/share/lua/5.1/template/item.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/item.lua rename to Utils/luarocks/systree/share/lua/5.1/template/item.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/page.lua b/Utils/luarocks/systree/share/lua/5.1/template/page.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/page.lua rename to Utils/luarocks/systree/share/lua/5.1/template/page.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/recordtypedef.lua b/Utils/luarocks/systree/share/lua/5.1/template/recordtypedef.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/recordtypedef.lua rename to Utils/luarocks/systree/share/lua/5.1/template/recordtypedef.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/usage.lua b/Utils/luarocks/systree/share/lua/5.1/template/usage.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/usage.lua rename to Utils/luarocks/systree/share/lua/5.1/template/usage.lua diff --git a/Utils/lua/5.1/share/lua/5.1/template/utils.lua b/Utils/luarocks/systree/share/lua/5.1/template/utils.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/template/utils.lua rename to Utils/luarocks/systree/share/lua/5.1/template/utils.lua diff --git a/Utils/lua/5.1/share/lua/5.1/templateengine.lua b/Utils/luarocks/systree/share/lua/5.1/templateengine.lua similarity index 100% rename from Utils/lua/5.1/share/lua/5.1/templateengine.lua rename to Utils/luarocks/systree/share/lua/5.1/templateengine.lua diff --git a/Utils/luarocks/tools/7z.dll b/Utils/luarocks/tools/7z.dll new file mode 100644 index 000000000..c0ff7fbe6 Binary files /dev/null and b/Utils/luarocks/tools/7z.dll differ diff --git a/Utils/luarocks/tools/7z.exe b/Utils/luarocks/tools/7z.exe new file mode 100644 index 000000000..5e3d6f9cf Binary files /dev/null and b/Utils/luarocks/tools/7z.exe differ diff --git a/Utils/luarocks/tools/cp.exe b/Utils/luarocks/tools/cp.exe new file mode 100644 index 000000000..0ef4fe85e Binary files /dev/null and b/Utils/luarocks/tools/cp.exe differ diff --git a/Utils/luarocks/tools/find.exe b/Utils/luarocks/tools/find.exe new file mode 100644 index 000000000..85192fbf4 Binary files /dev/null and b/Utils/luarocks/tools/find.exe differ diff --git a/Utils/luarocks/tools/libeay32.dll b/Utils/luarocks/tools/libeay32.dll new file mode 100644 index 000000000..8d31f8668 Binary files /dev/null and b/Utils/luarocks/tools/libeay32.dll differ diff --git a/Utils/luarocks/tools/libiconv2.dll b/Utils/luarocks/tools/libiconv2.dll new file mode 100644 index 000000000..544dd92f5 Binary files /dev/null and b/Utils/luarocks/tools/libiconv2.dll differ diff --git a/Utils/luarocks/tools/libintl3.dll b/Utils/luarocks/tools/libintl3.dll new file mode 100644 index 000000000..ec11e6b19 Binary files /dev/null and b/Utils/luarocks/tools/libintl3.dll differ diff --git a/Utils/luarocks/tools/libssl32.dll b/Utils/luarocks/tools/libssl32.dll new file mode 100644 index 000000000..a30ff0e9e Binary files /dev/null and b/Utils/luarocks/tools/libssl32.dll differ diff --git a/Utils/luarocks/tools/ls.exe b/Utils/luarocks/tools/ls.exe new file mode 100644 index 000000000..96ff2e574 Binary files /dev/null and b/Utils/luarocks/tools/ls.exe differ diff --git a/Utils/luarocks/tools/md5sum.exe b/Utils/luarocks/tools/md5sum.exe new file mode 100644 index 000000000..4ae9f74ff Binary files /dev/null and b/Utils/luarocks/tools/md5sum.exe differ diff --git a/Utils/luarocks/tools/mkdir.exe b/Utils/luarocks/tools/mkdir.exe new file mode 100644 index 000000000..83e57d97a Binary files /dev/null and b/Utils/luarocks/tools/mkdir.exe differ diff --git a/Utils/luarocks/tools/mv.exe b/Utils/luarocks/tools/mv.exe new file mode 100644 index 000000000..9fb65bb97 Binary files /dev/null and b/Utils/luarocks/tools/mv.exe differ diff --git a/Utils/luarocks/tools/pwd.exe b/Utils/luarocks/tools/pwd.exe new file mode 100644 index 000000000..7dd114de1 Binary files /dev/null and b/Utils/luarocks/tools/pwd.exe differ diff --git a/Utils/luarocks/tools/rmdir.exe b/Utils/luarocks/tools/rmdir.exe new file mode 100644 index 000000000..6a85c3c4b Binary files /dev/null and b/Utils/luarocks/tools/rmdir.exe differ diff --git a/Utils/luarocks/tools/test.exe b/Utils/luarocks/tools/test.exe new file mode 100644 index 000000000..94c95f9e4 Binary files /dev/null and b/Utils/luarocks/tools/test.exe differ diff --git a/Utils/luarocks/tools/uname.exe b/Utils/luarocks/tools/uname.exe new file mode 100644 index 000000000..3e2f4cf8f Binary files /dev/null and b/Utils/luarocks/tools/uname.exe differ diff --git a/Utils/luarocks/tools/wget.exe b/Utils/luarocks/tools/wget.exe new file mode 100644 index 000000000..54b372e6b Binary files /dev/null and b/Utils/luarocks/tools/wget.exe differ diff --git a/Utils/luarocks/wlua5.1.exe b/Utils/luarocks/wlua5.1.exe new file mode 100644 index 000000000..7be8c3a71 Binary files /dev/null and b/Utils/luarocks/wlua5.1.exe differ diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html index 5e65668f3..f8b0437fc 100644 --- a/docs/Documentation/AI_Balancer.html +++ b/docs/Documentation/AI_Balancer.html @@ -31,6 +31,21 @@

  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/AI_Cap.html b/docs/Documentation/AI_Cap.html index 425bec51b..82c499fda 100644 --- a/docs/Documentation/AI_Cap.html +++ b/docs/Documentation/AI_Cap.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/AI_Cas.html b/docs/Documentation/AI_Cas.html index 255b3646d..d4ebfc38b 100644 --- a/docs/Documentation/AI_Cas.html +++ b/docs/Documentation/AI_Cas.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index 0f68f6d16..74249623a 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • @@ -914,6 +933,9 @@ Use the method AIPATROLZONE.M + +

    This table contains the targets detected during patrol.

    +
    diff --git a/docs/Documentation/Account.html b/docs/Documentation/Account.html index 69239c4d4..5d97ad3a9 100644 --- a/docs/Documentation/Account.html +++ b/docs/Documentation/Account.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Airbase.html b/docs/Documentation/Airbase.html index 40b70c5df..3fce202ab 100644 --- a/docs/Documentation/Airbase.html +++ b/docs/Documentation/Airbase.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/AirbasePolice.html b/docs/Documentation/AirbasePolice.html index 3bfe030d8..697a7f431 100644 --- a/docs/Documentation/AirbasePolice.html +++ b/docs/Documentation/AirbasePolice.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Assign.html b/docs/Documentation/Assign.html index 039ba460e..609590883 100644 --- a/docs/Documentation/Assign.html +++ b/docs/Documentation/Assign.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Base.html b/docs/Documentation/Base.html index 2a833045d..7d2ff740c 100644 --- a/docs/Documentation/Base.html +++ b/docs/Documentation/Base.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index e811fa80c..d3e6dcf81 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/CleanUp.html b/docs/Documentation/CleanUp.html index 7cdcb71be..56a491705 100644 --- a/docs/Documentation/CleanUp.html +++ b/docs/Documentation/CleanUp.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Client.html b/docs/Documentation/Client.html index 748b7c484..136b4cd21 100644 --- a/docs/Documentation/Client.html +++ b/docs/Documentation/Client.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/CommandCenter.html b/docs/Documentation/CommandCenter.html index ae6d16afd..bcf129710 100644 --- a/docs/Documentation/CommandCenter.html +++ b/docs/Documentation/CommandCenter.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Controllable.html b/docs/Documentation/Controllable.html index 0e34ab8f8..be444f9a9 100644 --- a/docs/Documentation/Controllable.html +++ b/docs/Documentation/Controllable.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/DCSAirbase.html b/docs/Documentation/DCSAirbase.html index d47a0d2d4..860fab349 100644 --- a/docs/Documentation/DCSAirbase.html +++ b/docs/Documentation/DCSAirbase.html @@ -18,6 +18,9 @@

    Type coalition

    -

    Field(s)

    -
    -
    - - #coalition.side - -coalition.side - -
    -
    - - - -
    -
    - -

    Type coalition.side

    -

    Field(s)

    -
    -
    - - -coalition.side.BLUE - -
    -
    - - - -
    -
    -
    -
    - - -coalition.side.NEUTRAL - -
    -
    - - - -
    -
    -
    -
    - - -coalition.side.RED - -
    -
    - - - -
    -
    - +

    Type country.id

    diff --git a/docs/Documentation/DCSCommand.html b/docs/Documentation/DCSCommand.html index 50c815ce8..72b05130d 100644 --- a/docs/Documentation/DCSCommand.html +++ b/docs/Documentation/DCSCommand.html @@ -18,6 +18,9 @@ @@ -365,6 +384,12 @@ The following iterator methods are currently available within the DATABASE:

    DATABASE:GetGroupTemplateFromUnitName(UnitName) + + + + DATABASE:GetStaticUnitTemplate(StaticName) + + @@ -377,6 +402,12 @@ The following iterator methods are currently available within the DATABASE:

    DATABASE.NavPoints + + + + DATABASE.Navpoints + + @@ -473,6 +504,12 @@ The following iterator methods are currently available within the DATABASE:

    DATABASE:_RegisterClients()

    Private method that registers all Units of skill Client or Player within in the mission.

    + + + + DATABASE:_RegisterGroupTemplate(GroupTemplate, CoalitionID, CategoryID, CountryID) + +

    Private method that registers new Group Templates within the DATABASE Object.

    @@ -488,15 +525,15 @@ The following iterator methods are currently available within the DATABASE:

    - DATABASE:_RegisterStatics() + DATABASE:_RegisterStaticTemplate(GroupTemplate, StaticTemplate, CoalitionID, CategoryID, CountryID) - +

    Private method that registers new Static Templates within the DATABASE Object.

    - DATABASE:_RegisterTemplate(GroupTemplate, CoalitionID, CategoryID, CountryID) + DATABASE:_RegisterStatics() -

    Private method that registers new Group Templates within the DATABASE Object.

    + @@ -1459,6 +1496,27 @@ self

    + +DATABASE:GetStaticUnitTemplate(StaticName) + +
    +
    + + + +

    Parameter

    +
      +
    • + +

      StaticName :

      + +
    • +
    +
    +
    +
    +
    + DATABASE:GetStatusGroup(GroupName) @@ -1489,6 +1547,20 @@ self

    + +
    +
    +
    + + + +DATABASE.Navpoints + +
    +
    + + +
    @@ -1800,57 +1872,8 @@ self

    - -DATABASE:_RegisterGroupsAndUnits() - -
    -
    - -

    Private method that registers all Groups and Units within in the mission.

    - -

    Return value

    - -

    #DATABASE: -self

    - -
    -
    -
    -
    - - -DATABASE:_RegisterPlayers() - -
    -
    - -

    Private method that registers all alive players in the mission.

    - -

    Return value

    - -

    #DATABASE: -self

    - -
    -
    -
    -
    - - -DATABASE:_RegisterStatics() - -
    -
    - - - -
    -
    -
    -
    - - -DATABASE:_RegisterTemplate(GroupTemplate, CoalitionID, CategoryID, CountryID) + +DATABASE:_RegisterGroupTemplate(GroupTemplate, CoalitionID, CategoryID, CountryID)
    @@ -1885,6 +1908,101 @@ self

    #DATABASE: self

    +
    +
    +
    +
    + + +DATABASE:_RegisterGroupsAndUnits() + +
    +
    + +

    Private method that registers all Groups and Units within in the mission.

    + +

    Return value

    + +

    #DATABASE: +self

    + +
    +
    +
    +
    + + +DATABASE:_RegisterPlayers() + +
    +
    + +

    Private method that registers all alive players in the mission.

    + +

    Return value

    + +

    #DATABASE: +self

    + +
    +
    +
    +
    + + +DATABASE:_RegisterStaticTemplate(GroupTemplate, StaticTemplate, CoalitionID, CategoryID, CountryID) + +
    +
    + +

    Private method that registers new Static Templates within the DATABASE Object.

    + +

    Parameters

    +
      +
    • + +

      #table GroupTemplate :

      + +
    • +
    • + +

      StaticTemplate :

      + +
    • +
    • + +

      CoalitionID :

      + +
    • +
    • + +

      CategoryID :

      + +
    • +
    • + +

      CountryID :

      + +
    • +
    +

    Return value

    + +

    #DATABASE: +self

    + +
    +
    +
    +
    + + +DATABASE:_RegisterStatics() + +
    +
    + + +
    diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index c1db43d89..f4ef292c5 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • @@ -85,8 +104,25 @@

    DETECTION classes facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnassance Units). DETECTION uses the in-built detection capabilities of DCS World, but adds new functionalities.

    -

    Please watch this youtube video that explains the detection concepts.

    +

    Find the DETECTION classes documentation further in this document in the globals section.

    +
    + +

    Demo Missions

    + +

    DETECTION Demo Missions and Source Code

    + +

    DETECTION Demo Missions, only for Beta Testers

    + +

    ALL Demo Missions pack of the Latest Release

    + +
    + +

    YouTube Channel

    + +

    DETECTION YouTube Channel

    + +

    Contributions:

    @@ -112,7 +148,9 @@ DETECTION uses the in-built detection capabilities of DCS World, but adds new fu DETECTION_BASE +

    DETECTION_BASE class, extends Fsm#FSM

    +

    The DETECTION_BASE class defines the core functions to administer detected objects.

    @@ -306,12 +344,6 @@ DETECTION uses the in-built detection capabilities of DCS World, but adds new fu DETECTION_BASE.AlphaAngleProbability - - - - DETECTION_BASE.ClassName - - @@ -456,6 +488,23 @@ DETECTION uses the in-built detection capabilities of DCS World, but adds new fu DETECTION_BASE.DistanceProbability + + + + DETECTION_BASE:FilterCategories(<, FilterCategories) + +

    Filter the detected units based on Unit.Category
    +The different values of Unit.Category can be:

    + +
      +
    • Unit.Category.AIRPLANE
    • +
    • Unit.Category.GROUND_UNIT
    • +
    • Unit.Category.HELICOPTER
    • +
    • Unit.Category.SHIP
    • +
    • Unit.Category.STRUCTURE
    • +
    + +

    Multiple Unit.Category entries can be given as a table and then these will be evaluated as an OR expression.

    @@ -1047,7 +1096,233 @@ DETECTION uses the in-built detection capabilities of DCS World, but adds new fu
    +

    DETECTION_BASE class, extends Fsm#FSM

    +

    The DETECTION_BASE class defines the core functions to administer detected objects.

    + + +

    The DETECTION_BASE class will detect objects within the battle zone for a list of Groups detecting targets following (a) detection method(s).

    + +

    DETECTION_BASE constructor

    + +

    Construct a new DETECTION_BASE instance using the DETECTION_BASE.New() method.

    + +

    Initialization

    + +

    By default, detection will return detected objects with all the detection sensors available. +However, you can ask how the objects were found with specific detection methods. +If you use one of the below methods, the detection will work with the detection method specified. +You can specify to apply multiple detection methods.

    + +

    Use the following functions to report the objects it detected using the methods Visual, Optical, Radar, IRST, RWR, DLINK:

    + + + +

    Filter detected units based on category of the unit

    + +

    Filter the detected units based on Unit.Category using the method DETECTION_BASE.FilterCategories().
    +The different values of Unit.Category can be:

    + +
      +
    • Unit.Category.AIRPLANE
    • +
    • Unit.Category.GROUND_UNIT
    • +
    • Unit.Category.HELICOPTER
    • +
    • Unit.Category.SHIP
    • +
    • Unit.Category.STRUCTURE
    • +
    + +

    Multiple Unit.Category entries can be given as a table and then these will be evaluated as an OR expression.

    + +

    Example to filter a single category (Unit.Category.AIRPLANE).

    + +
    DetectionObject:FilterCategories( Unit.Category.AIRPLANE ) 
    +
    + +

    Example to filter multiple categories (Unit.Category.AIRPLANE, Unit.Category.HELICOPTER). Note the {}.

    + +
    DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
    +
    + + +

    DETECTION_ derived classes group the detected units into a DetectedItems[] list

    + +

    DETECTIONBASE derived classes build a list called DetectedItems[], which is essentially a first later +of grouping of detected units. Each DetectedItem within the DetectedItems[] list contains +a SETUNIT object that contains the detected units that belong to that group.

    + +

    Derived classes will apply different methods to group the detected units. +Examples are per area, per quadrant, per distance, per type. +See further the derived DETECTION classes on which grouping methods are currently supported.

    + +

    Various methods exist how to retrieve the grouped items from a DETECTION_BASE derived class:

    + +
      +
    • The method Detection#DETECTION_BASE.GetDetectedItems() retrieves the DetectedItems[] list.
    • +
    • A DetectedItem from the DetectedItems[] list can be retrieved using the method Detection#DETECTION_BASE.GetDetectedItem( DetectedItemIndex ). + Note that this method returns a DetectedItem element from the list, that contains a Set variable and further information + about the DetectedItem that is set by the DETECTION_BASE derived classes, used to group the DetectedItem.
    • +
    • A DetectedSet from the DetectedItems[] list can be retrieved using the method Detection#DETECTION_BASE.GetDetectedSet( DetectedItemIndex ). + This method retrieves the Set from a DetectedItem element from the DetectedItem list (DetectedItems[ DetectedItemIndex ].Set ).
    • +
    + +

    Visual filters to fine-tune the probability of the detected objects

    + +

    By default, DCS World will return any object that is in LOS and within "visual reach", or detectable through one of the electronic detection means. +That being said, the DCS World detection algorithm can sometimes be unrealistic. +Especially for a visual detection, DCS World is able to report within 1 second a detailed detection of a group of 20 units (including types of the units) that are 10 kilometers away, using only visual capabilities. +Additionally, trees and other obstacles are not accounted during the DCS World detection.

    + +

    Therefore, an additional (optional) filtering has been built into the DETECTION_BASE class, that can be set for visual detected units. +For electronic detection, this filtering is not applied, only for visually detected targets.

    + +

    The following additional filtering can be applied for visual filtering:

    + +
      +
    • A probability factor per kilometer distance.
    • +
    • A probability factor based on the alpha angle between the detected object and the unit detecting. + A detection from a higher altitude allows for better detection than when on the ground.
    • +
    • Define a probability factor for "cloudy zones", which are zones where forests or villages are located. In these zones, detection will be much more difficult. + The mission designer needs to define these cloudy zones within the mission, and needs to register these zones in the DETECTION_ objects additing a probability factor per zone.
    • +
    + +

    I advise however, that, when you first use the DETECTION derived classes, that you don't use these filters. +Only when you experience unrealistic behaviour in your missions, these filters could be applied.

    + + +

    Distance visual detection probability

    + +

    Upon a visual detection, the further away a detected object is, the less likely it is to be detected properly. +Also, the speed of accurate detection plays a role.

    + +

    A distance probability factor between 0 and 1 can be given, that will model a linear extrapolated probability over 10 km distance.

    + +

    For example, if a probability factor of 0.6 (60%) is given, the extrapolated probabilities over 15 kilometers would like like: +1 km: 96%, 2 km: 92%, 3 km: 88%, 4 km: 84%, 5 km: 80%, 6 km: 76%, 7 km: 72%, 8 km: 68%, 9 km: 64%, 10 km: 60%, 11 km: 56%, 12 km: 52%, 13 km: 48%, 14 km: 44%, 15 km: 40%.

    + +

    Note that based on this probability factor, not only the detection but also the type of the unit will be applied!

    + +

    Use the method Detection#DETECTION_BASE.SetDistanceProbability() to set the probability factor upon a 10 km distance.

    + +

    Alpha Angle visual detection probability

    + +

    Upon a visual detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly. +A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct.

    + +

    A probability factor between 0 and 1 can be given, that will model a progressive extrapolated probability if the target would be detected at a 0° angle.

    + +

    For example, if a alpha angle probability factor of 0.7 is given, the extrapolated probabilities of the different angles would look like: +0°: 70%, 10°: 75,21%, 20°: 80,26%, 30°: 85%, 40°: 89,28%, 50°: 92,98%, 60°: 95,98%, 70°: 98,19%, 80°: 99,54%, 90°: 100%

    + +

    Use the method Detection#DETECTION_BASE.SetAlphaAngleProbability() to set the probability factor if 0°.

    + +

    Cloudy Zones detection probability

    + +

    Upon a visual detection, the more a detected unit is within a cloudy zone, the less likely the detected unit is to be detected successfully. +The Cloudy Zones work with the ZONE_BASE derived classes. The mission designer can define within the mission +zones that reflect cloudy areas where detected units may not be so easily visually detected.

    + +

    Use the method Detection#DETECTION_BASE.SetZoneProbability() to set for a defined number of zones, the probability factors.

    + +

    Note however, that the more zones are defined to be "cloudy" within a detection, the more performance it will take +from the DETECTIONBASE to calculate the presence of the detected unit within each zone. +Expecially for ZONEPOLYGON, try to limit the amount of nodes of the polygon!

    + +

    Typically, this kind of filter would be applied for very specific areas were a detection needs to be very realisting for +AI not to detect so easily targets within a forrest or village rich area.

    + +

    Accept / Reject detected units

    + +

    DETECTION_BASE can accept or reject successful detections based on the location of the detected object, +if it is located in range or located inside or outside of specific zones.

    + +

    Detection acceptance of within range limit

    + +

    A range can be set that will limit a successful detection for a unit. +Use the method Detection#DETECTION_BASE.SetAcceptRange() to apply a range in meters till where detected units will be accepted.

    + +
     local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers.
    +
    + -- Build a detect object.
    + local Detection = DETECTION_BASE:New( SetGroup )
    +
    + -- This will accept detected units if the range is below 5000 meters.
    + Detection:SetAcceptRange( 5000 ) 
    +
    + -- Start the Detection.
    + Detection:Start()
    +
    + + +

    Detection acceptance if within zone(s).

    + +

    Specific ZONEBASE object(s) can be given as a parameter, which will only accept a detection if the unit is within the specified ZONEBASE object(s). +Use the method Detection#DETECTION_BASE.SetAcceptZones() will accept detected units if they are within the specified zones.

    + +
     local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers.
    +
    + -- Search fo the zones where units are to be accepted.
    + local ZoneAccept1 = ZONE:New( "AcceptZone1" )
    + local ZoneAccept2 = ZONE:New( "AcceptZone2" )
    +
    + -- Build a detect object.
    + local Detection = DETECTION_BASE:New( SetGroup )
    +
    + -- This will accept detected units by Detection when the unit is within ZoneAccept1 OR ZoneAccept2.
    + Detection:SetAcceptZones( { ZoneAccept1, ZoneAccept2 } ) 
    +
    + -- Start the Detection.
    + Detection:Start()
    +
    + +

    Detection rejectance if within zone(s).

    + +

    Specific ZONEBASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONEBASE object(s). +Use the method Detection#DETECTION_BASE.SetRejectZones() will reject detected units if they are within the specified zones. +An example of how to use the method is shown below.

    + +
     local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers.
    +
    + -- Search fo the zones where units are to be rejected.
    + local ZoneReject1 = ZONE:New( "RejectZone1" )
    + local ZoneReject2 = ZONE:New( "RejectZone2" )
    +
    + -- Build a detect object.
    + local Detection = DETECTION_BASE:New( SetGroup )
    +
    + -- This will reject detected units by Detection when the unit is within ZoneReject1 OR ZoneReject2.
    + Detection:SetRejectZones( { ZoneReject1, ZoneReject2 } ) 
    +
    + -- Start the Detection.
    + Detection:Start()
    +
    + +

    DETECTION_BASE is a Finite State Machine

    + +

    Various Events and State Transitions can be tailored using DETECTION_BASE.

    + +

    DETECTION_BASE States

    + +
      +
    • Detecting: The detection is running.
    • +
    • Stopped: The detection is stopped.
    • +
    + +

    DETECTION_BASE Events

    + +
      +
    • Start: Start the detection process.
    • +
    • Detect: Detect new units.
    • +
    • Detected: New units have been detected.
    • +
    • Stop: Stop the detection process. +
    • +
    @@ -1530,209 +1805,7 @@ self

    Type DETECTION_BASE

    - -

    1) DETECTION_BASE class, extends Fsm#FSM

    - -

    The DETECTION_BASE class defines the core functions to administer detected objects.

    - - -

    The DETECTION_BASE class will detect objects within the battle zone for a list of Groups detecting targets following (a) detection method(s).

    - -

    1.1) DETECTION_BASE constructor

    - -

    Construct a new DETECTION_BASE instance using the DETECTION_BASE.New() method.

    - -

    1.2) DETECTION_BASE initialization

    - -

    By default, detection will return detected objects with all the detection sensors available. -However, you can ask how the objects were found with specific detection methods. -If you use one of the below methods, the detection will work with the detection method specified. -You can specify to apply multiple detection methods.

    - -

    Use the following functions to report the objects it detected using the methods Visual, Optical, Radar, IRST, RWR, DLINK:

    - - - -

    1.3) DETECTION_BASE derived classes group the detected units into a DetectedItems[] list

    - -

    DETECTIONBASE derived classes build a list called DetectedItems[], which is essentially a first later -of grouping of detected units. Each DetectedItem within the DetectedItems[] list contains -a SETUNIT object that contains the detected units that belong to that group.

    - -

    Derived classes will apply different methods to group the detected units. -Examples are per area, per quadrant, per distance, per type. -See further the derived DETECTION classes on which grouping methods are currently supported.

    - -

    Various methods exist how to retrieve the grouped items from a DETECTION_BASE derived class:

    - -
      -
    • The method Detection#DETECTION_BASE.GetDetectedItems() retrieves the DetectedItems[] list.
    • -
    • A DetectedItem from the DetectedItems[] list can be retrieved using the method Detection#DETECTION_BASE.GetDetectedItem( DetectedItemIndex ). - Note that this method returns a DetectedItem element from the list, that contains a Set variable and further information - about the DetectedItem that is set by the DETECTION_BASE derived classes, used to group the DetectedItem.
    • -
    • A DetectedSet from the DetectedItems[] list can be retrieved using the method Detection#DETECTION_BASE.GetDetectedSet( DetectedItemIndex ). - This method retrieves the Set from a DetectedItem element from the DetectedItem list (DetectedItems[ DetectedItemIndex ].Set ).
    • -
    - -

    1.4) Apply additional Filters to fine-tune the detected objects

    - -

    By default, DCS World will return any object that is in LOS and within "visual reach", or detectable through one of the electronic detection means. -That being said, the DCS World detection algorithm can sometimes be unrealistic. -Especially for a visual detection, DCS World is able to report within 1 second a detailed detection of a group of 20 units (including types of the units) that are 10 kilometers away, using only visual capabilities. -Additionally, trees and other obstacles are not accounted during the DCS World detection.

    - -

    Therefore, an additional (optional) filtering has been built into the DETECTION_BASE class, that can be set for visual detected units. -For electronic detection, this filtering is not applied, only for visually detected targets.

    - -

    The following additional filtering can be applied for visual filtering:

    - -
      -
    • A probability factor per kilometer distance.
    • -
    • A probability factor based on the alpha angle between the detected object and the unit detecting. - A detection from a higher altitude allows for better detection than when on the ground.
    • -
    • Define a probability factor for "cloudy zones", which are zones where forests or villages are located. In these zones, detection will be much more difficult. - The mission designer needs to define these cloudy zones within the mission, and needs to register these zones in the DETECTION_ objects additing a probability factor per zone.
    • -
    - -

    I advise however, that, when you first use the DETECTION derived classes, that you don't use these filters. -Only when you experience unrealistic behaviour in your missions, these filters could be applied.

    - -

    1.4.1 ) Distance visual detection probability

    - -

    Upon a visual detection, the further away a detected object is, the less likely it is to be detected properly. -Also, the speed of accurate detection plays a role.

    - -

    A distance probability factor between 0 and 1 can be given, that will model a linear extrapolated probability over 10 km distance.

    - -

    For example, if a probability factor of 0.6 (60%) is given, the extrapolated probabilities over 15 kilometers would like like: -1 km: 96%, 2 km: 92%, 3 km: 88%, 4 km: 84%, 5 km: 80%, 6 km: 76%, 7 km: 72%, 8 km: 68%, 9 km: 64%, 10 km: 60%, 11 km: 56%, 12 km: 52%, 13 km: 48%, 14 km: 44%, 15 km: 40%.

    - -

    Note that based on this probability factor, not only the detection but also the type of the unit will be applied!

    - -

    Use the method Detection#DETECTION_BASE.SetDistanceProbability() to set the probability factor upon a 10 km distance.

    - -

    1.4.2 ) Alpha Angle visual detection probability

    - -

    Upon a visual detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly. -A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct.

    - -

    A probability factor between 0 and 1 can be given, that will model a progressive extrapolated probability if the target would be detected at a 0° angle.

    - -

    For example, if a alpha angle probability factor of 0.7 is given, the extrapolated probabilities of the different angles would look like: -0°: 70%, 10°: 75,21%, 20°: 80,26%, 30°: 85%, 40°: 89,28%, 50°: 92,98%, 60°: 95,98%, 70°: 98,19%, 80°: 99,54%, 90°: 100%

    - -

    Use the method Detection#DETECTION_BASE.SetAlphaAngleProbability() to set the probability factor if 0°.

    - -

    1.4.3 ) Cloudy Zones detection probability

    - -

    Upon a visual detection, the more a detected unit is within a cloudy zone, the less likely the detected unit is to be detected successfully. -The Cloudy Zones work with the ZONE_BASE derived classes. The mission designer can define within the mission -zones that reflect cloudy areas where detected units may not be so easily visually detected.

    - -

    Use the method Detection#DETECTION_BASE.SetZoneProbability() to set for a defined number of zones, the probability factors.

    - -

    Note however, that the more zones are defined to be "cloudy" within a detection, the more performance it will take -from the DETECTIONBASE to calculate the presence of the detected unit within each zone. -Expecially for ZONEPOLYGON, try to limit the amount of nodes of the polygon!

    - -

    Typically, this kind of filter would be applied for very specific areas were a detection needs to be very realisting for -AI not to detect so easily targets within a forrest or village rich area.

    - -

    1.5 ) Accept / Reject detected units

    - -

    DETECTION_BASE can accept or reject successful detections based on the location of the detected object, -if it is located in range or located inside or outside of specific zones.

    - -

    1.5.1 ) Detection acceptance of within range limit

    - -

    A range can be set that will limit a successful detection for a unit. -Use the method Detection#DETECTION_BASE.SetAcceptRange() to apply a range in meters till where detected units will be accepted.

    - -
     local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers.
    -
    - -- Build a detect object.
    - local Detection = DETECTION_BASE:New( SetGroup )
    -
    - -- This will accept detected units if the range is below 5000 meters.
    - Detection:SetAcceptRange( 5000 ) 
    -
    - -- Start the Detection.
    - Detection:Start()
    -
    - - -

    1.5.2 ) Detection acceptance if within zone(s).

    - -

    Specific ZONEBASE object(s) can be given as a parameter, which will only accept a detection if the unit is within the specified ZONEBASE object(s). -Use the method Detection#DETECTION_BASE.SetAcceptZones() will accept detected units if they are within the specified zones.

    - -
     local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers.
    -
    - -- Search fo the zones where units are to be accepted.
    - local ZoneAccept1 = ZONE:New( "AcceptZone1" )
    - local ZoneAccept2 = ZONE:New( "AcceptZone2" )
    -
    - -- Build a detect object.
    - local Detection = DETECTION_BASE:New( SetGroup )
    -
    - -- This will accept detected units by Detection when the unit is within ZoneAccept1 OR ZoneAccept2.
    - Detection:SetAcceptZones( { ZoneAccept1, ZoneAccept2 } ) 
    -
    - -- Start the Detection.
    - Detection:Start()
    -
    - -

    1.5.3 ) Detection rejectance if within zone(s).

    - -

    Specific ZONEBASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONEBASE object(s). -Use the method Detection#DETECTION_BASE.SetRejectZones() will reject detected units if they are within the specified zones. -An example of how to use the method is shown below.

    - -
     local SetGroup = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterStart() -- Build a SetGroup of Forward Air Controllers.
    -
    - -- Search fo the zones where units are to be rejected.
    - local ZoneReject1 = ZONE:New( "RejectZone1" )
    - local ZoneReject2 = ZONE:New( "RejectZone2" )
    -
    - -- Build a detect object.
    - local Detection = DETECTION_BASE:New( SetGroup )
    -
    - -- This will reject detected units by Detection when the unit is within ZoneReject1 OR ZoneReject2.
    - Detection:SetRejectZones( { ZoneReject1, ZoneReject2 } ) 
    -
    - -- Start the Detection.
    - Detection:Start()
    -
    - -

    1.6) DETECTION_BASE is a Finite State Machine

    - -

    Various Events and State Transitions can be tailored using DETECTION_BASE.

    - -

    1.6.1) DETECTION_BASE States

    - -
      -
    • Detecting: The detection is running.
    • -
    • Stopped: The detection is stopped.
    • -
    - -

    1.6.2) DETECTION_BASE Events

    - -
      -
    • Start: Start the detection process.
    • -
    • Detect: Detect new units.
    • -
    • Detected: New units have been detected.
    • -
    • Stop: Stop the detection process.
    • -
    - - -

    Field(s)

    +

    Field(s)

    @@ -1949,20 +2022,6 @@ The index of the DetectedItem.

    - -
    -
    -
    - - #string - -DETECTION_BASE.ClassName - -
    -
    - - -
    @@ -2318,6 +2377,62 @@ self

    + +
    +
    +
    + + +DETECTION_BASE:FilterCategories(<, FilterCategories) + +
    +
    + +

    Filter the detected units based on Unit.Category
    +The different values of Unit.Category can be:

    + +
      +
    • Unit.Category.AIRPLANE
    • +
    • Unit.Category.GROUND_UNIT
    • +
    • Unit.Category.HELICOPTER
    • +
    • Unit.Category.SHIP
    • +
    • Unit.Category.STRUCTURE
    • +
    + +

    Multiple Unit.Category entries can be given as a table and then these will be evaluated as an OR expression.

    + + + +

    Example to filter a single category (Unit.Category.AIRPLANE).

    + +
    DetectionObject:FilterCategories( Unit.Category.AIRPLANE ) 
    +
    + +

    Example to filter multiple categories (Unit.Category.AIRPLANE, Unit.Category.HELICOPTER). Note the {}.

    + +
    DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
    +
    + + +

    Parameters

    +
      +
    • + +

      #list < : +cs.DCSUnit#Unit> FilterCategories The Categories entries

      + +
    • +
    • + +

      FilterCategories :

      + +
    • +
    +

    Return value

    + +

    #DETECTION_BASE: +self

    +
    @@ -4430,6 +4545,8 @@ self

    Type DETECTION_UNITS.DetectedItem

    +

    Type list

    + diff --git a/docs/Documentation/DetectionManager.html b/docs/Documentation/DetectionManager.html index 542edf755..601843371 100644 --- a/docs/Documentation/DetectionManager.html +++ b/docs/Documentation/DetectionManager.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Escort.html b/docs/Documentation/Escort.html index bc481cf03..2a5aadb20 100644 --- a/docs/Documentation/Escort.html +++ b/docs/Documentation/Escort.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Event.html b/docs/Documentation/Event.html index 6c74344c9..e69de29bb 100644 --- a/docs/Documentation/Event.html +++ b/docs/Documentation/Event.html @@ -1,2641 +0,0 @@ - - - - - - -
    -
    - -
    -
    -
    -
    - -
    -

    Module Event

    - -

    Core - EVENT models DCS event dispatching using a publish-subscribe model.

    - - - -

    Banner Image

    - -
    - -

    1) Event Handling Overview

    - -

    Objects

    - -

    Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc. -This module provides a mechanism to dispatch those events occuring within your running mission, to the different objects orchestrating your mission.

    - -

    Objects

    - -

    Objects can subscribe to different events. The Event dispatcher will publish the received DCS events to the subscribed MOOSE objects, in a specified order. -In this way, the subscribed MOOSE objects are kept in sync with your evolving running mission.

    - -

    1.1) Event Dispatching

    - -

    Objects

    - -

    The _EVENTDISPATCHER object is automatically created within MOOSE, -and handles the dispatching of DCS Events occurring -in the simulator to the subscribed objects -in the correct processing order.

    - -

    Objects

    - -

    There are 5 levels of kind of objects that the _EVENTDISPATCHER services:

    - -
      -
    • _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
    • -
    • SET_ derived classes: Subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
    • -
    • UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to teh subscribed UNIT object.
    • -
    • GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
    • -
    • Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
    • -
    - -

    Objects

    - -

    For most DCS events, the above order of updating will be followed.

    - -

    Objects

    - -

    But for some DCS events, the publishing order is reversed. This is due to the fact that objects need to be erased instead of added.

    - -

    1.2) Event Handling

    - -

    Objects

    - -

    The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the BASE class, UNIT class and GROUP class. -The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE.

    - -

    Objects

    - -

    The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, -and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently.

    - -

    1.2.1 Subscribe / Unsubscribe to DCS Events

    - -

    At first, the mission designer will need to Subscribe to a specific DCS event for the class. -So, when the DCS event occurs, the class will be notified of that event. -There are two functions which you use to subscribe to or unsubscribe from an event.

    - - - -

    Note that for a UNIT, the event will be handled for that UNIT only! -Note that for a GROUP, the event will be handled for all the UNITs in that GROUP only!

    - -

    For all objects of other classes, the subscribed events will be handled for all UNITs within the Mission! -So if a UNIT within the mission has the subscribed event for that object, -then the object event handler will receive the event for that UNIT!

    - -

    1.3.2 Event Handling of DCS Events

    - -

    Once the class is subscribed to the event, an Event Handling method on the object or class needs to be written that will be called -when the DCS event occurs. The Event Handling method receives an Event#EVENTDATA structure, which contains a lot of information -about the event that occurred.

    - -

    Find below an example of the prototype how to write an event handling function for two units:

    - -
     local Tank1 = UNIT:FindByName( "Tank A" )
    - local Tank2 = UNIT:FindByName( "Tank B" )
    -
    - -- Here we subscribe to the Dead events. So, if one of these tanks dies, the Tank1 or Tank2 objects will be notified.
    - Tank1:HandleEvent( EVENTS.Dead )
    - Tank2:HandleEvent( EVENTS.Dead )
    -
    - --- This function is an Event Handling function that will be called when Tank1 is Dead.
    - -- @param Wrapper.Unit#UNIT self 
    - -- @param Core.Event#EVENTDATA EventData
    - function Tank1:OnEventDead( EventData )
    -
    -   self:SmokeGreen()
    - end
    -
    - --- This function is an Event Handling function that will be called when Tank2 is Dead.
    - -- @param Wrapper.Unit#UNIT self 
    - -- @param Core.Event#EVENTDATA EventData
    - function Tank2:OnEventDead( EventData )
    -
    -   self:SmokeBlue()
    - end
    -
    - -

    1.3.3 Event Handling methods that are automatically called upon subscribed DCS events

    - -

    Objects

    - -

    The following list outlines which EVENTS item in the structure corresponds to which Event Handling method. -Always ensure that your event handling methods align with the events being subscribed to, or nothing will be executed.

    - -

    2) EVENTS type

    - -

    The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the -Base#BASE.HandleEvent() method.

    - -

    3) EVENTDATA type

    - -

    The Event#EVENTDATA structure contains all the fields that are populated with event information before -an Event Handler method is being called by the event dispatcher. -The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events. -There are basically 4 main categories of information stored in the EVENTDATA structure:

    - -
      -
    • Initiator Unit data: Several fields documenting the initiator unit related to the event.

    • -
    • Target Unit data: Several fields documenting the target unit related to the event.

    • -
    • Weapon data: Certain events populate weapon information.

    • -
    • Place data: Certain events populate place information.

      - -

      --- This function is an Event Handling function that will be called when Tank1 is Dead. - -- EventData is an EVENTDATA structure. - -- We use the EventData.IniUnit to smoke the tank Green. - -- @param Wrapper.Unit#UNIT self - -- @param Core.Event#EVENTDATA EventData - function Tank1:OnEventDead( EventData )

      - -

      EventData.IniUnit:SmokeGreen() - end

    • -
    - - -

    Find below an overview which events populate which information categories:

    - -

    Objects

    - -

    IMPORTANT NOTE: Some events can involve not just UNIT objects, but also STATIC objects!!! -In that case the initiator or target unit fields will refer to a STATIC object! -In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated. -The fields IniObjectCategory and TgtObjectCategory contain the indicator which kind of object is involved in the event. -You can use the enumerator Object.Category.UNIT and Object.Category.STATIC to check on IniObjectCategory and TgtObjectCategory. -Example code snippet:

    - -
     if Event.IniObjectCategory == Object.Category.UNIT then
    -  ...
    - end
    - if Event.IniObjectCategory == Object.Category.STATIC then
    -  ...
    - end 
    -
    - -

    When a static object is involved in the event, the Group and Player fields won't be populated.

    - -
    - -

    API CHANGE HISTORY

    - -

    The underlying change log documents the API changes. Please read this carefully. The following notation is used:

    - -
      -
    • Added parts are expressed in bold type face.
    • -
    • Removed parts are expressed in italic type face.
    • -
    - -

    YYYY-MM-DD: CLASS:NewFunction( Params ) replaces CLASS:OldFunction( Params ) -YYYY-MM-DD: CLASS:NewFunction( Params ) added

    - -

    Hereby the change log:

    - -
      -
    • 2017-03-07: Added the correct event dispatching in case the event is subscribed by a GROUP.

    • -
    • 2017-02-07: Did a complete revision of the Event Handing API and underlying mechanisms.

    • -
    - -
    - -

    AUTHORS and CONTRIBUTIONS

    - -

    Contributions:

    - -

    Authors:

    - - - - -

    Global(s)

    - - - - - - - - - - - - - -
    EVENT - -
    EVENTHANDLER - -
    EVENTS - -
    -

    Type EVENT

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    EVENT.ClassID - -
    EVENT.ClassName - -
    EVENT:CreateEventDeleteCargo(Cargo) -

    Creation of a Cargo Deletion Event.

    -
    EVENT:CreateEventNewCargo(Cargo) -

    Creation of a New Cargo Event.

    -
    EVENT:EventText(EventID) - -
    EVENT.Events - -
    EVENT:Init(EventID, EventClass) -

    Initializes the Events structure for the event

    -
    EVENT:New() - -
    EVENT:OnBirthForTemplate(EventGroup, EventFunction, EventClass, EventTemplate) -

    Create an OnBirth event handler for a group

    -
    EVENT:OnCrashForTemplate(EventGroup, EventFunction, EventClass, EventTemplate) -

    Create an OnCrash event handler for a group

    -
    EVENT:OnDeadForTemplate(EventGroup, EventFunction, EventClass, EventTemplate) -

    Create an OnDead event handler for a group

    -
    EVENT:OnEngineShutDownForTemplate(EventTemplate, EventFunction, EventClass) -

    Create an OnDead event handler for a group

    -
    EVENT:OnEventForGroup(GroupName, EventFunction, EventClass, EventID) -

    Set a new listener for an SEVENTX event for a GROUP.

    -
    EVENT:OnEventForTemplate(EventTemplate, EventFunction, EventClass, OnEventFunction, EventID) -

    Create an OnDead event handler for a group

    -
    EVENT:OnEventForUnit(UnitName, EventFunction, EventClass, EventID) -

    Set a new listener for an SEVENTX event for a UNIT.

    -
    EVENT:OnEventGeneric(EventFunction, EventClass, EventID) -

    Set a new listener for an SEVENTX event independent from a unit or a weapon.

    -
    EVENT:OnLandForTemplate(EventTemplate, EventFunction, EventClass) - -
    EVENT:OnTakeOffForTemplate(EventTemplate, EventFunction, EventClass) - -
    EVENT:Remove(EventClass, EventID) -

    Removes an Events entry

    -
    EVENT:RemoveAll(EventObject) -

    Clears all event subscriptions for a Base#BASE derived object.

    -
    EVENT:RemoveForGroup(GroupName, EventClass, EventID) -

    Removes an Events entry for a GROUP.

    -
    EVENT:RemoveForUnit(UnitName, EventClass, EventID) -

    Removes an Events entry for a UNIT.

    -
    EVENT:onEvent(Event) - -
    - -

    Type EVENT.Events

    - - - - - -
    EVENT.Events.IniUnit - -
    - -

    Type EVENTDATA

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    EVENTDATA.Cargo - -
    EVENTDATA.CargoName - -
    EVENTDATA.IniCategory -

    (UNIT) The category of the initiator.

    -
    EVENTDATA.IniCoalition -

    (UNIT) The coalition of the initiator.

    -
    EVENTDATA.IniDCSGroup -

    (UNIT) The initiating {DCSGroup#Group}.

    -
    EVENTDATA.IniDCSGroupName -

    (UNIT) The initiating Group name.

    -
    EVENTDATA.IniDCSUnit -

    (UNIT/STATIC) The initiating DCSUnit#Unit or DCSStaticObject#StaticObject.

    -
    EVENTDATA.IniDCSUnitName -

    (UNIT/STATIC) The initiating Unit name.

    -
    EVENTDATA.IniGroup -

    (UNIT) The initiating MOOSE wrapper Group#GROUP of the initiator Group object.

    -
    EVENTDATA.IniGroupName -

    UNIT) The initiating GROUP name (same as IniDCSGroupName).

    -
    EVENTDATA.IniObjectCategory -

    (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).

    -
    EVENTDATA.IniPlayerName -

    (UNIT) The name of the initiating player in case the Unit is a client or player slot.

    -
    EVENTDATA.IniTypeName -

    (UNIT) The type name of the initiator.

    - -
    EVENTDATA.IniUnit -

    (UNIT/STATIC) The initiating MOOSE wrapper Unit#UNIT of the initiator Unit object.

    -
    EVENTDATA.IniUnitName -

    (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).

    -
    EVENTDATA.TgtCategory -

    (UNIT) The category of the target.

    -
    EVENTDATA.TgtCoalition -

    (UNIT) The coalition of the target.

    -
    EVENTDATA.TgtDCSGroup -

    (UNIT) The target {DCSGroup#Group}.

    -
    EVENTDATA.TgtDCSGroupName -

    (UNIT) The target Group name.

    -
    EVENTDATA.TgtDCSUnit -

    (UNIT/STATIC) The target DCSUnit#Unit or DCSStaticObject#StaticObject.

    -
    EVENTDATA.TgtDCSUnitName -

    (UNIT/STATIC) The target Unit name.

    -
    EVENTDATA.TgtGroup -

    (UNIT) The target MOOSE wrapper Group#GROUP of the target Group object.

    -
    EVENTDATA.TgtGroupName -

    (UNIT) The target GROUP name (same as TgtDCSGroupName).

    -
    EVENTDATA.TgtObjectCategory -

    (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).

    -
    EVENTDATA.TgtPlayerName -

    (UNIT) The name of the target player in case the Unit is a client or player slot.

    -
    EVENTDATA.TgtTypeName -

    (UNIT) The type name of the target.

    - -
    EVENTDATA.TgtUnit -

    (UNIT/STATIC) The target MOOSE wrapper Unit#UNIT of the target Unit object.

    -
    EVENTDATA.TgtUnitName -

    (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).

    -
    EVENTDATA.Weapon - -
    EVENTDATA.WeaponCategory - -
    EVENTDATA.WeaponCoalition - -
    EVENTDATA.WeaponName - -
    EVENTDATA.WeaponPlayerName - -
    EVENTDATA.WeaponTgtDCSUnit - -
    EVENTDATA.WeaponTypeName - -
    EVENTDATA.WeaponUNIT - -
    EVENTDATA.id -

    The identifier of the event.

    - -
    EVENTDATA.initiator -

    (UNIT/STATIC/SCENERY) The initiating Dcs.DCSUnit#Unit or Dcs.DCSStaticObject#StaticObject.

    -
    EVENTDATA.target -

    (UNIT/STATIC) The target Dcs.DCSUnit#Unit or DCSStaticObject#StaticObject.

    -
    EVENTDATA.weapon -

    The weapon used during the event.

    -
    - -

    Type EVENTHANDLER

    - - - - - - - - - - - - - -
    EVENTHANDLER.ClassID - -
    EVENTHANDLER.ClassName - -
    EVENTHANDLER:New() -

    The EVENTHANDLER constructor

    -
    - -

    Type EVENTS

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    EVENTS.BaseCaptured - -
    EVENTS.Birth - -
    EVENTS.Crash - -
    EVENTS.Dead - -
    EVENTS.DeleteCargo - -
    EVENTS.Ejection - -
    EVENTS.EngineShutdown - -
    EVENTS.EngineStartup - -
    EVENTS.Hit - -
    EVENTS.HumanFailure - -
    EVENTS.Land - -
    EVENTS.MissionEnd - -
    EVENTS.MissionStart - -
    EVENTS.NewCargo - -
    EVENTS.PilotDead - -
    EVENTS.PlayerComment - -
    EVENTS.PlayerEnterUnit - -
    EVENTS.PlayerLeaveUnit - -
    EVENTS.Refueling - -
    EVENTS.RefuelingStop - -
    EVENTS.ShootingEnd - -
    EVENTS.ShootingStart - -
    EVENTS.Shot - -
    EVENTS.Takeoff - -
    EVENTS.TookControl - -
    - -

    Global(s)

    -
    -
    - - #EVENT - -EVENT - -
    -
    - - - -
    -
    -
    -
    - - #EVENTHANDLER - -EVENTHANDLER - -
    -
    - - - -
    -
    -
    -
    - - #EVENTS - -EVENTS - -
    -
    - - - -
    -
    -

    Type Event

    - -

    Type EVENT

    - -

    The EVENT structure

    - -

    Field(s)

    -
    -
    - - #number - -EVENT.ClassID - -
    -
    - - - -
    -
    -
    -
    - - #string - -EVENT.ClassName - -
    -
    - - - -
    -
    -
    -
    - - -EVENT:CreateEventDeleteCargo(Cargo) - -
    -
    - -

    Creation of a Cargo Deletion Event.

    - -

    Parameter

    - -
    -
    -
    -
    - - -EVENT:CreateEventNewCargo(Cargo) - -
    -
    - -

    Creation of a New Cargo Event.

    - -

    Parameter

    - -
    -
    -
    -
    - - -EVENT:EventText(EventID) - -
    -
    - - - -

    Parameter

    -
      -
    • - -

      EventID :

      - -
    • -
    -
    -
    -
    -
    - - #EVENT.Events - -EVENT.Events - -
    -
    - - - -
    -
    -
    -
    - - -EVENT:Init(EventID, EventClass) - -
    -
    - -

    Initializes the Events structure for the event

    - -

    Parameters

    - -

    Return value

    - -

    #EVENT.Events:

    - - -
    -
    -
    -
    - - -EVENT:New() - -
    -
    - - - -
    -
    -
    -
    - - -EVENT:OnBirthForTemplate(EventGroup, EventFunction, EventClass, EventTemplate) - -
    -
    - -

    Create an OnBirth event handler for a group

    - -

    Parameters

    -
      -
    • - -

      Wrapper.Group#GROUP EventGroup :

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the unit.

      - -
    • -
    • - -

      EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      EventTemplate :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnCrashForTemplate(EventGroup, EventFunction, EventClass, EventTemplate) - -
    -
    - -

    Create an OnCrash event handler for a group

    - -

    Parameters

    -
      -
    • - -

      Wrapper.Group#GROUP EventGroup :

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the unit.

      - -
    • -
    • - -

      EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      EventTemplate :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnDeadForTemplate(EventGroup, EventFunction, EventClass, EventTemplate) - -
    -
    - -

    Create an OnDead event handler for a group

    - -

    Parameters

    -
      -
    • - -

      Wrapper.Group#GROUP EventGroup :

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the unit.

      - -
    • -
    • - -

      EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      EventTemplate :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnEngineShutDownForTemplate(EventTemplate, EventFunction, EventClass) - -
    -
    - -

    Create an OnDead event handler for a group

    - -

    Parameters

    -
      -
    • - -

      #table EventTemplate :

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the unit.

      - -
    • -
    • - -

      EventClass : -The self instance of the class for which the event is.

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnEventForGroup(GroupName, EventFunction, EventClass, EventID) - -
    -
    - -

    Set a new listener for an SEVENTX event for a GROUP.

    - -

    Parameters

    -
      -
    • - -

      #string GroupName : -The name of the GROUP.

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the GROUP.

      - -
    • -
    • - -

      Core.Base#BASE EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      EventID :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnEventForTemplate(EventTemplate, EventFunction, EventClass, OnEventFunction, EventID) - -
    -
    - -

    Create an OnDead event handler for a group

    - -

    Parameters

    -
      -
    • - -

      #table EventTemplate :

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the unit.

      - -
    • -
    • - -

      EventClass : -The instance of the class for which the event is.

      - -
    • -
    • - -

      #function OnEventFunction :

      - -
    • -
    • - -

      EventID :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnEventForUnit(UnitName, EventFunction, EventClass, EventID) - -
    -
    - -

    Set a new listener for an SEVENTX event for a UNIT.

    - -

    Parameters

    -
      -
    • - -

      #string UnitName : -The name of the UNIT.

      - -
    • -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the GROUP.

      - -
    • -
    • - -

      Core.Base#BASE EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      EventID :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnEventGeneric(EventFunction, EventClass, EventID) - -
    -
    - -

    Set a new listener for an SEVENTX event independent from a unit or a weapon.

    - -

    Parameters

    -
      -
    • - -

      #function EventFunction : -The function to be called when the event occurs for the unit.

      - -
    • -
    • - -

      Core.Base#BASE EventClass : -The self instance of the class for which the event is captured. When the event happens, the event process will be called in this class provided.

      - -
    • -
    • - -

      EventID :

      - -
    • -
    -

    Return value

    - -

    #EVENT:

    - - -
    -
    -
    -
    - - -EVENT:OnLandForTemplate(EventTemplate, EventFunction, EventClass) - -
    -
    - - - -

    Parameters

    -
      -
    • - -

      EventTemplate :

      - -
    • -
    • - -

      EventFunction :

      - -
    • -
    • - -

      EventClass :

      - -
    • -
    -
    -
    -
    -
    - - -EVENT:OnTakeOffForTemplate(EventTemplate, EventFunction, EventClass) - -
    -
    - - - -

    Parameters

    -
      -
    • - -

      EventTemplate :

      - -
    • -
    • - -

      EventFunction :

      - -
    • -
    • - -

      EventClass :

      - -
    • -
    -
    -
    -
    -
    - - -EVENT:Remove(EventClass, EventID) - -
    -
    - -

    Removes an Events entry

    - -

    Parameters

    - -

    Return value

    - -

    #EVENT.Events:

    - - -
    -
    -
    -
    - - -EVENT:RemoveAll(EventObject) - -
    -
    - -

    Clears all event subscriptions for a Base#BASE derived object.

    - -

    Parameter

    - -
    -
    -
    -
    - - -EVENT:RemoveForGroup(GroupName, EventClass, EventID) - -
    -
    - -

    Removes an Events entry for a GROUP.

    - -

    Parameters

    -
      -
    • - -

      #string GroupName : -The name of the GROUP.

      - -
    • -
    • - -

      Core.Base#BASE EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      Dcs.DCSWorld#world.event EventID :

      - -
    • -
    -

    Return value

    - -

    #EVENT.Events:

    - - -
    -
    -
    -
    - - -EVENT:RemoveForUnit(UnitName, EventClass, EventID) - -
    -
    - -

    Removes an Events entry for a UNIT.

    - -

    Parameters

    -
      -
    • - -

      #string UnitName : -The name of the UNIT.

      - -
    • -
    • - -

      Core.Base#BASE EventClass : -The self instance of the class for which the event is.

      - -
    • -
    • - -

      Dcs.DCSWorld#world.event EventID :

      - -
    • -
    -

    Return value

    - -

    #EVENT.Events:

    - - -
    -
    -
    -
    - - -EVENT:onEvent(Event) - -
    -
    - - - -

    Parameter

    - -
    -
    - -

    Type EVENT.Events

    - -

    The Events structure

    - -

    Field(s)

    -
    -
    - - #number - -EVENT.Events.IniUnit - -
    -
    - - - -
    -
    - -

    Type EVENTDATA

    - -

    The Event structure -Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:

    - -
      -
    • A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
    • -
    - - -
      -
    • A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ -
    • -
    - -

    Field(s)

    -
    -
    - - - -EVENTDATA.Cargo - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTDATA.CargoName - -
    -
    - - - -
    -
    -
    -
    - - Dcs.DCSUnit#Unit.Category - -EVENTDATA.IniCategory - -
    -
    - -

    (UNIT) The category of the initiator.

    - -
    -
    -
    -
    - - Dcs.DCScoalition#coalition.side - -EVENTDATA.IniCoalition - -
    -
    - -

    (UNIT) The coalition of the initiator.

    - -
    -
    -
    -
    - - Dcs.DCSGroup#Group - -EVENTDATA.IniDCSGroup - -
    -
    - -

    (UNIT) The initiating {DCSGroup#Group}.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.IniDCSGroupName - -
    -
    - -

    (UNIT) The initiating Group name.

    - -
    -
    -
    -
    - - Dcs.DCSUnit#Unit - -EVENTDATA.IniDCSUnit - -
    -
    - -

    (UNIT/STATIC) The initiating DCSUnit#Unit or DCSStaticObject#StaticObject.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.IniDCSUnitName - -
    -
    - -

    (UNIT/STATIC) The initiating Unit name.

    - -
    -
    -
    -
    - - Wrapper.Group#GROUP - -EVENTDATA.IniGroup - -
    -
    - -

    (UNIT) The initiating MOOSE wrapper Group#GROUP of the initiator Group object.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.IniGroupName - -
    -
    - -

    UNIT) The initiating GROUP name (same as IniDCSGroupName).

    - -
    -
    -
    -
    - - Dcs.DCSObject#Object.Category - -EVENTDATA.IniObjectCategory - -
    -
    - -

    (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).

    - -
    -
    -
    -
    - - #string - -EVENTDATA.IniPlayerName - -
    -
    - -

    (UNIT) The name of the initiating player in case the Unit is a client or player slot.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.IniTypeName - -
    -
    - -

    (UNIT) The type name of the initiator.

    - - -
    -
    -
    -
    - - Wrapper.Unit#UNIT - -EVENTDATA.IniUnit - -
    -
    - -

    (UNIT/STATIC) The initiating MOOSE wrapper Unit#UNIT of the initiator Unit object.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.IniUnitName - -
    -
    - -

    (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).

    - -
    -
    -
    -
    - - Dcs.DCSUnit#Unit.Category - -EVENTDATA.TgtCategory - -
    -
    - -

    (UNIT) The category of the target.

    - -
    -
    -
    -
    - - Dcs.DCScoalition#coalition.side - -EVENTDATA.TgtCoalition - -
    -
    - -

    (UNIT) The coalition of the target.

    - -
    -
    -
    -
    - - Dcs.DCSGroup#Group - -EVENTDATA.TgtDCSGroup - -
    -
    - -

    (UNIT) The target {DCSGroup#Group}.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.TgtDCSGroupName - -
    -
    - -

    (UNIT) The target Group name.

    - -
    -
    -
    -
    - - Dcs.DCSUnit#Unit - -EVENTDATA.TgtDCSUnit - -
    -
    - -

    (UNIT/STATIC) The target DCSUnit#Unit or DCSStaticObject#StaticObject.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.TgtDCSUnitName - -
    -
    - -

    (UNIT/STATIC) The target Unit name.

    - -
    -
    -
    -
    - - Wrapper.Group#GROUP - -EVENTDATA.TgtGroup - -
    -
    - -

    (UNIT) The target MOOSE wrapper Group#GROUP of the target Group object.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.TgtGroupName - -
    -
    - -

    (UNIT) The target GROUP name (same as TgtDCSGroupName).

    - -
    -
    -
    -
    - - Dcs.DCSObject#Object.Category - -EVENTDATA.TgtObjectCategory - -
    -
    - -

    (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).

    - -
    -
    -
    -
    - - #string - -EVENTDATA.TgtPlayerName - -
    -
    - -

    (UNIT) The name of the target player in case the Unit is a client or player slot.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.TgtTypeName - -
    -
    - -

    (UNIT) The type name of the target.

    - - -
    -
    -
    -
    - - Wrapper.Unit#UNIT - -EVENTDATA.TgtUnit - -
    -
    - -

    (UNIT/STATIC) The target MOOSE wrapper Unit#UNIT of the target Unit object.

    - -
    -
    -
    -
    - - #string - -EVENTDATA.TgtUnitName - -
    -
    - -

    (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).

    - -
    -
    -
    -
    - - -EVENTDATA.Weapon - -
    -
    - - - -
    -
    -
    -
    - - -EVENTDATA.WeaponCategory - -
    -
    - - - -
    -
    -
    -
    - - -EVENTDATA.WeaponCoalition - -
    -
    - - - -
    -
    -
    -
    - - -EVENTDATA.WeaponName - -
    -
    - - - -
    -
    -
    -
    - - -EVENTDATA.WeaponPlayerName - -
    -
    - - - -
    -
    -
    -
    - - -EVENTDATA.WeaponTgtDCSUnit - -
    -
    - - - -
    -
    -
    -
    - - -EVENTDATA.WeaponTypeName - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTDATA.WeaponUNIT - -
    -
    - - - - -

    Sometimes, the weapon is a player unit!

    - -
    -
    -
    -
    - - #number - -EVENTDATA.id - -
    -
    - -

    The identifier of the event.

    - - -
    -
    -
    -
    - - Dcs.DCSUnit#Unit - -EVENTDATA.initiator - -
    -
    - -

    (UNIT/STATIC/SCENERY) The initiating Dcs.DCSUnit#Unit or Dcs.DCSStaticObject#StaticObject.

    - -
    -
    -
    -
    - - Dcs.DCSUnit#Unit - -EVENTDATA.target - -
    -
    - -

    (UNIT/STATIC) The target Dcs.DCSUnit#Unit or DCSStaticObject#StaticObject.

    - -
    -
    -
    -
    - - -EVENTDATA.weapon - -
    -
    - -

    The weapon used during the event.

    - -
    -
    - -

    Type EVENTHANDLER

    - -

    The EVENTHANDLER structure

    - -

    Field(s)

    -
    -
    - - #number - -EVENTHANDLER.ClassID - -
    -
    - - - -
    -
    -
    -
    - - #string - -EVENTHANDLER.ClassName - -
    -
    - - - -
    -
    -
    -
    - - -EVENTHANDLER:New() - -
    -
    - -

    The EVENTHANDLER constructor

    - -

    Return value

    - -

    #EVENTHANDLER:

    - - -
    -
    - -

    Type EVENTS

    - -

    The different types of events supported by MOOSE.

    - - -

    Use this structure to subscribe to events using the Base#BASE.HandleEvent() method.

    - -

    Field(s)

    -
    -
    - - - -EVENTS.BaseCaptured - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Birth - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Crash - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Dead - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.DeleteCargo - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Ejection - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.EngineShutdown - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.EngineStartup - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Hit - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.HumanFailure - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Land - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.MissionEnd - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.MissionStart - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.NewCargo - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.PilotDead - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.PlayerComment - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.PlayerEnterUnit - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.PlayerLeaveUnit - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Refueling - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.RefuelingStop - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.ShootingEnd - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.ShootingStart - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Shot - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.Takeoff - -
    -
    - - - -
    -
    -
    -
    - - - -EVENTS.TookControl - -
    -
    - - - -
    -
    - -
    - -
    - - diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index 371f24214..9c7864cf4 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Group.html b/docs/Documentation/Group.html index 2d7620f40..3c04c3719 100644 --- a/docs/Documentation/Group.html +++ b/docs/Documentation/Group.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • @@ -423,6 +442,12 @@ GROUP:Register(GroupName)

    Create a new GROUP from a DCSGroup

    + + + + GROUP:ResetEvents() + +

    Reset the subscriptions.

    @@ -1624,6 +1649,24 @@ The DCS Group name

    #GROUP: self

    + +
    +
    +
    + + +GROUP:ResetEvents() + +
    +
    + +

    Reset the subscriptions.

    + +

    Return value

    + +

    #GROUP:

    + +
    diff --git a/docs/Documentation/Identifiable.html b/docs/Documentation/Identifiable.html index 79739cbf9..98830226c 100644 --- a/docs/Documentation/Identifiable.html +++ b/docs/Documentation/Identifiable.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/MOVEMENT.html b/docs/Documentation/MOVEMENT.html index 2c3773f5f..c8bfd7123 100644 --- a/docs/Documentation/MOVEMENT.html +++ b/docs/Documentation/MOVEMENT.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Menu.html b/docs/Documentation/Menu.html index c09255510..fbea1030e 100644 --- a/docs/Documentation/Menu.html +++ b/docs/Documentation/Menu.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Message.html b/docs/Documentation/Message.html index e2a7642c8..24d3bd5dc 100644 --- a/docs/Documentation/Message.html +++ b/docs/Documentation/Message.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/MissileTrainer.html b/docs/Documentation/MissileTrainer.html index da77a2948..b3e9f1343 100644 --- a/docs/Documentation/MissileTrainer.html +++ b/docs/Documentation/MissileTrainer.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Mission.html b/docs/Documentation/Mission.html index dfc09bc46..c40133f87 100644 --- a/docs/Documentation/Mission.html +++ b/docs/Documentation/Mission.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Object.html b/docs/Documentation/Object.html index 3f7299c86..67b078a51 100644 --- a/docs/Documentation/Object.html +++ b/docs/Documentation/Object.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Point.html b/docs/Documentation/Point.html index add1d6996..d01447df5 100644 --- a/docs/Documentation/Point.html +++ b/docs/Documentation/Point.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • @@ -1348,6 +1367,7 @@ The new calculated POINT_VEC2.

    + POINT_VEC2.z diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index 178f980de..1073789e9 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Process_JTAC.html b/docs/Documentation/Process_JTAC.html index 11d6329e6..5520fb76d 100644 --- a/docs/Documentation/Process_JTAC.html +++ b/docs/Documentation/Process_JTAC.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Process_Pickup.html b/docs/Documentation/Process_Pickup.html index 36f9db817..12ecdef87 100644 --- a/docs/Documentation/Process_Pickup.html +++ b/docs/Documentation/Process_Pickup.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Radio.html b/docs/Documentation/Radio.html index 0b4642d0f..b52f23dfe 100644 --- a/docs/Documentation/Radio.html +++ b/docs/Documentation/Radio.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • @@ -78,7 +97,7 @@ -

    --- bitmap

    +

    Banner Image


    @@ -111,7 +130,7 @@ If a FC3 airacraft is used, it will hear every communication, whatever t
    -

    Authors: Hugues "Grey_Echo" Bousquet

    +

    Author: Hugues "Grey_Echo" Bousquet

    Global(s)

    @@ -275,9 +294,9 @@ If a FC3 airacraft is used, it will hear every communication, whatever t

    Methods to set relevant parameters for both a Unit#UNIT or a Group#GROUP or any other Positionable#POSITIONABLE

    @@ -296,7 +315,7 @@ If a FC3 airacraft is used, it will hear every communication, whatever t
  • RADIO.NewUnitTransmission() : Shortcut to set all the relevant parameters in one method call
  • -

    Additional Methods to set relevant parameters if the transmiter is any other Wrapper.Positionable#POSITIONABLE

    +

    Additional Methods to set relevant parameters if the transmiter is any other Positionable#POSITIONABLE

    diff --git a/docs/Documentation/Scenery.html b/docs/Documentation/Scenery.html index 40fabb2c9..1ef03a861 100644 --- a/docs/Documentation/Scenery.html +++ b/docs/Documentation/Scenery.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/ScheduleDispatcher.html b/docs/Documentation/ScheduleDispatcher.html index b6b78ec9d..469faadf1 100644 --- a/docs/Documentation/ScheduleDispatcher.html +++ b/docs/Documentation/ScheduleDispatcher.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Scheduler.html b/docs/Documentation/Scheduler.html index c1908a711..d3e10ff41 100644 --- a/docs/Documentation/Scheduler.html +++ b/docs/Documentation/Scheduler.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Scoring.html b/docs/Documentation/Scoring.html index 14fa802da..13927d8ea 100644 --- a/docs/Documentation/Scoring.html +++ b/docs/Documentation/Scoring.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Sead.html b/docs/Documentation/Sead.html index 08f2cf461..93b017bb7 100644 --- a/docs/Documentation/Sead.html +++ b/docs/Documentation/Sead.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Set.html b/docs/Documentation/Set.html index 7a31dc2e8..ce2588b24 100644 --- a/docs/Documentation/Set.html +++ b/docs/Documentation/Set.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Smoke.html b/docs/Documentation/Smoke.html index db3f97156..798744966 100644 --- a/docs/Documentation/Smoke.html +++ b/docs/Documentation/Smoke.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index d0b095a1d..f963faca2 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,135 +85,39 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • Module Spawn

    -

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:All --
    -Spawn groups of units dynamically in your missions.

    +

    Functional -- Spawn dynamically new GROUPs in your missions.

    -

    Banner Image

    + +

    +Banner Image


    -

    1) #SPAWN class, extends Base#BASE

    +

    The documentation of the SPAWN class can be found further in this document.

    -

    The #SPAWN class allows to spawn dynamically new groups, based on pre-defined initialization settings, modifying the behaviour when groups are spawned.

    +
    - -

    For each group to be spawned, within the mission editor, a group has to be created with the "late activation flag" set. We call this group the "Spawn Template" of the SPAWN object. -A reference to this Spawn Template needs to be provided when constructing the SPAWN object, by indicating the name of the group within the mission editor in the constructor methods.

    +

    Demo Missions

    -

    Within the SPAWN object, there is an internal index that keeps track of which group from the internal group list was spawned. -When new groups get spawned by using the SPAWN methods (see below), it will be validated whether the Limits (SPAWN.Limit) of the SPAWN object are not reached. -When all is valid, a new group will be created by the spawning methods, and the internal index will be increased with 1.

    +

    SPAWN Demo Missions source code

    -

    Regarding the name of new spawned groups, a SpawnPrefix will be assigned for each new group created. -If you want to have the Spawn Template name to be used as the SpawnPrefix name, use the SPAWN.New constructor. -However, when the SPAWN.NewWithAlias constructor was used, the Alias name will define the SpawnPrefix name. -Groups will follow the following naming structure when spawned at run-time:

    +

    SPAWN Demo Missions, only for beta testers

    -
      -
    1. Spawned groups will have the name SpawnPrefix#ggg, where ggg is a counter from 0 to 999.
    2. -
    3. Spawned units will have the name SpawnPrefix#ggg-uu, where uu is a counter from 0 to 99 for each new spawned unit belonging to the group.
    4. -
    +

    ALL Demo Missions pack of the last release

    -

    Some additional notes that need to be remembered:

    +
    -
      -
    • Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the #SPAWN module.
    • -
    • It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use.
    • -
    • When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore.
    • -
    +

    YouTube Channel

    -

    1.1) SPAWN construction methods

    - -

    Create a new SPAWN object with the SPAWN.New() or the SPAWN.NewWithAlias() methods:

    - -
      -
    • SPAWN.New(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition).
    • -
    • SPAWN.NewWithAlias(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition), and gives each spawned Group an different name.
    • -
    - -

    It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. -The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. -So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient.

    - -

    1.2) SPAWN initialization methods

    - -

    A spawn object will behave differently based on the usage of initialization methods, which all start with the Init prefix:

    - - - -

    1.3) SPAWN spawning methods

    - -

    Groups can be spawned at different times and methods:

    - - - -

    Note that SPAWN.Spawn and SPAWN.ReSpawn return a GROUP#GROUP.New object, that contains a reference to the DCSGroup object. -You can use the GROUP object to do further actions with the DCSGroup.

    - -

    1.4) Retrieve alive GROUPs spawned by the SPAWN object

    - -

    The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. -Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. -SPAWN provides methods to iterate through that internal GROUP object reference table:

    - -
      -
    • SPAWN.GetFirstAliveGroup(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found.
    • -
    • SPAWN.GetNextAliveGroup(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found.
    • -
    • SPAWN.GetLastAliveGroup(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found.
    • -
    - -

    You can use the methods SPAWN.GetFirstAliveGroup() and sequently SPAWN.GetNextAliveGroup() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. -The method SPAWN.GetGroupFromIndex() will return the GROUP object reference from the given Index, dead or alive...

    - -

    1.5) SPAWN object cleaning

    - -

    Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. -In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, -and it may occur that no new groups are or can be spawned as limits are reached. -To prevent this, a SPAWN.InitCleanUp() initialization method has been defined that will silently monitor the status of each spawned group. -Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. -There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... -In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. -This models AI that has succesfully returned to their airbase, to restart their combat activities. -Check the SPAWN.InitCleanUp() for further info.

    - -

    1.6) Catch the Group spawn event in a callback function!

    - -

    When using the SpawnScheduled method, new Groups are created following the schedule timing parameters. -When a new Group is spawned, you maybe want to execute actions with that group spawned at the spawn event. -To SPAWN class supports this functionality through the SPAWN.OnSpawnGroup( *function( SpawnedGroup ) end * ) method, which takes a function as a parameter that you can define locally. -Whenever a new Group is spawned, the given function is called, and the Group that was just spawned, is given as a parameter. -As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned Group object. -A coding example is provided at the description of the SPAWN.OnSpawnGroup( *function( SpawnedGroup ) end * ) method.

    +

    SPAWN YouTube Channel


    @@ -211,44 +132,34 @@ A coding example is provided at the description of the SPAWN +

    SPAWN class, extends Base#BASE

    +

    The SPAWN class allows to spawn dynamically new groups.

    @@ -301,6 +214,12 @@ A coding example is provided at the description of the SPAWN.CleanUpScheduler + + + + SPAWN.DelayOnOff + + @@ -361,6 +280,24 @@ A coding example is provided at the description of the SPAWN:InitCleanUp(SpawnCleanUpInterval)

    CleanUp groups when they are still alive, but inactive.

    + + + + SPAWN:InitDelayOff() + +

    Turns the Delay Off for the Group when spawning.

    + + + + SPAWN:InitDelayOn() + +

    Turns the Delay On for the Group when spawning.

    + + + + SPAWN:InitDelayOnOff(DelayOnOff) + + @@ -894,6 +831,246 @@ and any spaces before and after the resulting name are removed.

    +

    SPAWN class, extends Base#BASE

    + +

    The SPAWN class allows to spawn dynamically new groups.

    + + +

    Each SPAWN object needs to be have a related template group setup in the Mission Editor (ME), +which is a normal group with the Late Activation flag set. +This template group will never be activated in your mission.
    +SPAWN uses that template group to reference to all the characteristics +(air, ground, livery, unit composition, formation, skill level etc) of each new group to be spawned.

    + +

    Therefore, when creating a SPAWN object, the SPAWN.New and SPAWN.NewWithAlias require +the name of the template group to be given as a string to those constructor methods.

    + +

    Initialization settings can be applied on the SPAWN object, +which modify the behaviour or the way groups are spawned. +These initialization methods have the prefix Init. +There are also spawn methods with the prefix Spawn and will spawn new groups in various ways.

    + +

    IMPORTANT! The methods with prefix Init must be used before any methods with prefix Spawn method are used, or unexpected results may appear!!!

    + +

    Because SPAWN can spawn multiple groups of a template group, +SPAWN has an internal index that keeps track +which was the latest group that was spawned.

    + +

    Limits can be set on how many groups can be spawn in each SPAWN object, +using the method SPAWN.InitLimit. SPAWN has 2 kind of limits:

    + +
      +
    • The maximum amount of Units that can be alive at the same time...
    • +
    • The maximum amount of Groups that can be spawned... This is more of a resource-type of limit.
    • +
    + +

    When new groups get spawned using the Spawn methods, +it will be evaluated whether any limits have been reached. +When no spawn limit is reached, a new group will be created by the spawning methods, +and the internal index will be increased with 1.

    + +

    These limits ensure that your mission does not accidentally get flooded with spawned groups.
    +Additionally, it also guarantees that independent of the group composition, +at any time, the most optimal amount of groups are alive in your mission. +For example, if your template group has a group composition of 10 units, and you specify a limit of 100 units alive at the same time, +with unlimited resources = :InitLimit( 100, 0 ) and 10 groups are alive, but two groups have only one unit alive in the group, +then a sequent Spawn(Scheduled) will allow a new group to be spawned!!!

    + +

    IMPORTANT!! If a limit has been reached, it is possible that a Spawn method returns nil, meaning, no Group had been spawned!!!

    + +

    Spawned groups get the same name as the name of the template group.
    +Spawned units in those groups keep by default the same name as the name of the template group.
    +However, because multiple groups and units are created from the template group, +a suffix is added to each spawned group and unit.

    + +

    Newly spawned groups will get the following naming structure at run-time:

    + +
      +
    1. Spawned groups will have the name _GroupName#nnn_, where GroupName is the name of the template group, + and nnn is a counter from 0 to 999.
    2. +
    3. Spawned units will have the name _GroupName#nnn-uu_, + where uu is a counter from 0 to 99 for each new spawned unit belonging to the group.
    4. +
    + +

    That being said, there is a way to keep the same unit names!
    +The method SPAWN.InitKeepUnitNames() will keep the same unit names as defined within the template group, thus:

    + +
      +
    1. Spawned units will have the name _UnitName#nnn-uu_, + where UnitName is the unit name as defined in the template group*, + and uu is a **counter from 0 to 99 for each new spawned unit belonging to the group.
    2. +
    + +

    Some additional notes that need to be considered!!:

    + +
      +
    • templates are actually groups defined within the mission editor, with the flag "Late Activation" set. + As such, these groups are never used within the mission, but are used by the #SPAWN module.
    • +
    • It is important to defined BEFORE you spawn new groups, + a proper initialization of the SPAWN instance is done with the options you want to use.
    • +
    • When designing a mission, NEVER name groups using a "#" within the name of the group Spawn template(s), + or the SPAWN module logic won't work anymore.
    • +
    + +

    SPAWN construction methods

    + +

    Create a new SPAWN object with the SPAWN.New() or the SPAWN.NewWithAlias() methods:

    + +
      +
    • SPAWN.New(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition).
    • +
    • SPAWN.NewWithAlias(): Creates a new SPAWN object taking the name of the group that represents the GROUP template (definition), and gives each spawned Group an different name.
    • +
    + +

    It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. +The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. +So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient.

    + +

    SPAWN Initialization methods

    + +

    A spawn object will behave differently based on the usage of initialization methods, which all start with the Init prefix:

    + +

    Unit Names

    + +
      +
    • SPAWN.InitKeepUnitNames(): Keeps the unit names as defined within the mission editor, but note that anything after a # mark is ignored, and any spaces before and after the resulting name are removed. IMPORTANT! This method MUST be the first used after :New !!!
    • +
    + +

    Route randomization

    + + + +

    Group composition randomization

    + +
      +
    • SPAWN.InitRandomizeTemplate(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined.
    • +
    + +

    Uncontrolled

    + + + +

    Array formation

    + +
      +
    • SPAWN.InitArray(): Make groups visible before they are actually activated, and order these groups like a batallion in an array.
    • +
    + +

    Position randomization

    + +
      +
    • SPAWN.InitRandomizePosition(): Randomizes the position of Groups that are spawned within a radius band, given an Outer and Inner radius, from the point that the spawn happens.
    • +
    • SPAWN.InitRandomizeUnits(): Randomizes the Units in the Group that is spawned within a radius band, given an Outer and Inner radius.
    • +
    • SPAWN.InitRandomizeZones(): Randomizes the spawning between a predefined list of Zones that are declared using this function. Each zone can be given a probability factor.
    • +
    + +

    Enable / Disable AI when spawning a new Group

    + + + +

    Limit scheduled spawning

    + +
      +
    • SPAWN.InitLimit(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned.
    • +
    + +

    Delay initial scheduled spawn

    + + + +

    Repeat spawned Groups upon landing

    + + + + +

    SPAWN Spawn methods

    + +

    Groups can be spawned at different times and methods:

    + +

    Single spawning methods

    + + + +

    Note that SPAWN.Spawn and SPAWN.ReSpawn return a GROUP#GROUP.New object, that contains a reference to the DCSGroup object. +You can use the GROUP object to do further actions with the DCSGroup.

    + +

    Scheduled spawning methods

    + + + + + +

    Retrieve alive GROUPs spawned by the SPAWN object

    + +

    The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. +Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. +SPAWN provides methods to iterate through that internal GROUP object reference table:

    + +
      +
    • SPAWN.GetFirstAliveGroup(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found.
    • +
    • SPAWN.GetNextAliveGroup(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found.
    • +
    • SPAWN.GetLastAliveGroup(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found.
    • +
    + +

    You can use the methods SPAWN.GetFirstAliveGroup() and sequently SPAWN.GetNextAliveGroup() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. +The method SPAWN.GetGroupFromIndex() will return the GROUP object reference from the given Index, dead or alive...

    + +

    Spawned cleaning of inactive groups

    + +

    Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. +In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, +and it may occur that no new groups are or can be spawned as limits are reached. +To prevent this, a SPAWN.InitCleanUp() initialization method has been defined that will silently monitor the status of each spawned group. +Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. +There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... +In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. +This models AI that has succesfully returned to their airbase, to restart their combat activities. +Check the SPAWN.InitCleanUp() for further info.

    + +

    Catch the Group Spawn Event in a callback function!

    + +

    When using the SPAWN.SpawnScheduleds are created following the spawn time interval parameters. +When a new Group is spawned, you maybe want to execute actions with that group spawned at the spawn event. +The SPAWN class supports this functionality through the method SPAWN.OnSpawnGroup( *function( SpawnedGroup ) end * ), +which takes a function as a parameter that you can define locally. +Whenever a new Group is spawned, the given function is called, and the Group that was just spawned, is given as a parameter. +As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned Group object. +A coding example is provided at the description of the SPAWN.OnSpawnGroup( *function( SpawnedGroup ) end * ) method.

    + +

    Delay the initial spawning

    + +

    When using the SPAWN.SpawnScheduled +immediately when :SpawnScheduled() is initiated. The methods SPAWN.InitDelayOnOff() and SPAWN.InitDelayOn() can be used to +activate a delay before the first Group is spawned. For completeness, a method SPAWN.InitDelayOff() is also available, that +can be used to switch off the initial delay. Because there is no delay by default, this method would only be used when a +SPAWN.SpawnScheduledStop() ; SPAWN.SpawnScheduledStart() sequence would have been used.

    +
    @@ -964,6 +1141,23 @@ and any spaces before and after the resulting name are removed.

    self.CleanUpFunction = routines.scheduleFunction( self._SpawnCleanUpScheduler, { self }, timer.getTime() + 1, SpawnCleanUpInterval )

    + +
    +
    +
    + + #boolean + +SPAWN.DelayOnOff + +
    +
    + + + + +

    No intial delay when spawning the first group.

    +
    @@ -1286,6 +1480,63 @@ self

    + +SPAWN:InitDelayOff() + +
    +
    + +

    Turns the Delay Off for the Group when spawning.

    + +

    Return value

    + +

    #SPAWN: +The SPAWN object

    + +
    +
    +
    +
    + + +SPAWN:InitDelayOn() + +
    +
    + +

    Turns the Delay On for the Group when spawning.

    + +

    Return value

    + +

    #SPAWN: +The SPAWN object

    + +
    +
    +
    +
    + + +SPAWN:InitDelayOnOff(DelayOnOff) + +
    +
    + + + +

    Parameter

    +
      +
    • + +

      DelayOnOff :

      + +
    • +
    +
    +
    +
    +
    + SPAWN:InitKeepUnitNames() @@ -2582,6 +2833,11 @@ when nothing was spawned.

    Note: This method is only required to be called when the schedule was stopped.

    +

    Return value

    + +

    #SPAWN:

    + +
    @@ -2595,6 +2851,11 @@ when nothing was spawned.

    Will stop the scheduled spawning scheduler.

    +

    Return value

    + +

    #SPAWN:

    + +
    diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html new file mode 100644 index 000000000..964497670 --- /dev/null +++ b/docs/Documentation/SpawnStatic.html @@ -0,0 +1,490 @@ + + + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    Module SpawnStatic

    + +

    Core -- Spawn dynamically new STATICs in your missions.

    + + +

    +Banner Image

    + +
    + +

    SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.

    + +
    + +

    Demo Missions

    + +

    SPAWNSTATIC Demo Missions source code

    + +

    SPAWNSTATIC Demo Missions, only for beta testers

    + +

    ALL Demo Missions pack of the last release

    + +
    + +

    YouTube Channel

    + +

    SPAWNSTATIC YouTube Channel

    + +
    + +

    API CHANGE HISTORY

    + +

    The underlying change log documents the API changes. Please read this carefully. The following notation is used:

    + +
      +
    • Added parts are expressed in bold type face.
    • +
    • Removed parts are expressed in italic type face.
    • +
    + +

    Hereby the change log:

    + +
    + +

    AUTHORS and CONTRIBUTIONS

    + +

    Contributions:

    + +

    Authors:

    + +
      +
    • FlightControl: Design & Programming
    • +
    + + +

    Global(s)

    + + + + + +
    SPAWNSTATIC +

    SPAWNSTATIC class, extends Base#BASE

    + +

    The SPAWNSTATIC class allows to spawn dynamically new Statics.

    +
    +

    Type SPAWNSTATIC

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SPAWNSTATIC.CountryID + +
    SPAWNSTATIC:NewFromStatic(SpawnTemplatePrefix, CountryID) +

    Creates the main object to spawn a Static defined in the ME.

    +
    SPAWNSTATIC:NewFromType(SpawnTypeName, SpawnShapeName, SpawnCategory, CountryID) +

    Creates the main object to spawn a Static based on a type name.

    +
    SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, (, NewName) +

    Creates a new Static from a POINT_VEC2.

    +
    SPAWNSTATIC:SpawnFromZone(Zone, Heading, (, NewName) +

    Creates a new Static from a Zone.

    +
    SPAWNSTATIC.SpawnIndex + +
    SPAWNSTATIC.SpawnTemplatePrefix + +
    SPAWNSTATIC.SpawnTypeName + +
    + +

    Global(s)

    +
    +
    + + #SPAWNSTATIC + +SPAWNSTATIC + +
    +
    + +

    SPAWNSTATIC class, extends Base#BASE

    + +

    The SPAWNSTATIC class allows to spawn dynamically new Statics.

    + + +

    Through creating a copy of an existing static object template as defined in the Mission Editor (ME), +SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy" +these properties to create a new static object and place it at the desired coordinate.

    + +

    New spawned Statics get the same name as the name of the template Static, +or gets the given name when a new name is provided at the Spawn method.
    +By default, spawned Statics will follow a naming convention at run-time:

    + +
      +
    • Spawned Statics will have the name _StaticName#nnn_, where StaticName is the name of the Template Static, + and nnn is a counter from 0 to 99999.
    • +
    + + +

    SPAWNSTATIC construction methods

    + +

    Create a new SPAWNSTATIC object with the SPAWNSTATIC.NewFromStatic():

    + +
      +
    • SPAWNSTATIC.NewFromStatic(): Creates a new SPAWNSTATIC object given a name that is used as the base of the naming of each spawned Static.
    • +
    + +

    Spawn methods

    + +

    Groups can be spawned at different times and methods:

    + + + +
    +
    +

    Type SpawnStatic

    + +

    Type SPAWNSTATIC

    +

    Field(s)

    +
    +
    + + + +SPAWNSTATIC.CountryID + +
    +
    + + + +
    +
    +
    +
    + + +SPAWNSTATIC:NewFromStatic(SpawnTemplatePrefix, CountryID) + +
    +
    + +

    Creates the main object to spawn a Static defined in the ME.

    + +

    Parameters

    +
      +
    • + +

      #string SpawnTemplatePrefix : +is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix.

      + +
    • +
    • + +

      CountryID :

      + +
    • +
    +

    Return value

    + +

    #SPAWNSTATIC:

    + + +
    +
    +
    +
    + + +SPAWNSTATIC:NewFromType(SpawnTypeName, SpawnShapeName, SpawnCategory, CountryID) + +
    +
    + +

    Creates the main object to spawn a Static based on a type name.

    + +

    Parameters

    +
      +
    • + +

      #string SpawnTypeName : +is the name of the type.

      + +
    • +
    • + +

      SpawnShapeName :

      + +
    • +
    • + +

      SpawnCategory :

      + +
    • +
    • + +

      CountryID :

      + +
    • +
    +

    Return value

    + +

    #SPAWNSTATIC:

    + + +
    +
    +
    +
    + + +SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, (, NewName) + +
    +
    + +

    Creates a new Static from a POINT_VEC2.

    + +

    Parameters

    +
      +
    • + +

      Core.Point#POINT_VEC2 PointVec2 : +The 2D coordinate where to spawn the static.

      + +
    • +
    • + +

      #number Heading : +The heading of the static, which is a number in degrees from 0 to 360.

      + +
    • +
    • + +

      #string ( : +ptional) The name of the new static.

      + +
    • +
    • + +

      NewName :

      + +
    • +
    +

    Return value

    + +

    #SPAWNSTATIC:

    + + +
    +
    +
    +
    + + +SPAWNSTATIC:SpawnFromZone(Zone, Heading, (, NewName) + +
    +
    + +

    Creates a new Static from a Zone.

    + +

    Parameters

    +
      +
    • + +

      Core.Zone#ZONE_BASE Zone : +The Zone where to spawn the static.

      + +
    • +
    • + +

      #number Heading : +The heading of the static, which is a number in degrees from 0 to 360.

      + +
    • +
    • + +

      #string ( : +ptional) The name of the new static.

      + +
    • +
    • + +

      NewName :

      + +
    • +
    +

    Return value

    + +

    #SPAWNSTATIC:

    + + +
    +
    +
    +
    + + #number + +SPAWNSTATIC.SpawnIndex + +
    +
    + + + +
    +
    +
    +
    + + + +SPAWNSTATIC.SpawnTemplatePrefix + +
    +
    + + + +
    +
    +
    +
    + + + +SPAWNSTATIC.SpawnTypeName + +
    +
    + + + +
    +
    + +

    Type SPAWNSTATIC.SpawnZoneTable

    + +
    + +
    + + diff --git a/docs/Documentation/Static.html b/docs/Documentation/Static.html index 2aeeae3c8..4f2fb8c63 100644 --- a/docs/Documentation/Static.html +++ b/docs/Documentation/Static.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/StaticObject.html b/docs/Documentation/StaticObject.html index dcecd0cf0..d2314e1c1 100644 --- a/docs/Documentation/StaticObject.html +++ b/docs/Documentation/StaticObject.html @@ -18,6 +18,9 @@ diff --git a/docs/Documentation/Task_A2G.html b/docs/Documentation/Task_A2G.html index c4f9f3077..c3ff3617d 100644 --- a/docs/Documentation/Task_A2G.html +++ b/docs/Documentation/Task_A2G.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Task_A2G_Dispatcher.html b/docs/Documentation/Task_A2G_Dispatcher.html index 92d0cee18..3ca561091 100644 --- a/docs/Documentation/Task_A2G_Dispatcher.html +++ b/docs/Documentation/Task_A2G_Dispatcher.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Task_PICKUP.html b/docs/Documentation/Task_PICKUP.html index 08b188774..07ad14a68 100644 --- a/docs/Documentation/Task_PICKUP.html +++ b/docs/Documentation/Task_PICKUP.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Unit.html b/docs/Documentation/Unit.html index b3d712e3b..cfb7e775a 100644 --- a/docs/Documentation/Unit.html +++ b/docs/Documentation/Unit.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • @@ -333,6 +352,12 @@ UNIT:Register(UnitName)

    Create a new UNIT from DCSUnit.

    + + + + UNIT:ResetEvents() + +

    Reset the subscriptions.

    @@ -1495,6 +1520,24 @@ The name of the DCS unit.

    #UNIT:

    + +
    +
    +
    + + +UNIT:ResetEvents() + +
    +
    + +

    Reset the subscriptions.

    + +

    Return value

    + +

    #UNIT:

    + +
    diff --git a/docs/Documentation/Utils.html b/docs/Documentation/Utils.html index b9a22a874..582c54d57 100644 --- a/docs/Documentation/Utils.html +++ b/docs/Documentation/Utils.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/Zone.html b/docs/Documentation/Zone.html index 9fbe8dd88..45cc41b92 100644 --- a/docs/Documentation/Zone.html +++ b/docs/Documentation/Zone.html @@ -31,6 +31,21 @@
  • Client
  • CommandCenter
  • Controllable
  • +
  • DCSAirbase
  • +
  • DCSCoalitionObject
  • +
  • DCSCommand
  • +
  • DCSController
  • +
  • DCSGroup
  • +
  • DCSObject
  • +
  • DCSTask
  • +
  • DCSTypes
  • +
  • DCSUnit
  • +
  • DCSVec3
  • +
  • DCSWorld
  • +
  • DCSZone
  • +
  • DCScountry
  • +
  • DCStimer
  • +
  • DCStrigger
  • Database
  • Detection
  • DetectionManager
  • @@ -59,7 +74,9 @@
  • Set
  • Smoke
  • Spawn
  • +
  • SpawnStatic
  • Static
  • +
  • StaticObject
  • Task
  • Task_A2G
  • Task_A2G_Dispatcher
  • @@ -68,6 +85,8 @@
  • Unit
  • Utils
  • Zone
  • +
  • env
  • +
  • land
  • routines
  • diff --git a/docs/Documentation/env.html b/docs/Documentation/env.html index 985b449dc..1e26ec179 100644 --- a/docs/Documentation/env.html +++ b/docs/Documentation/env.html @@ -18,6 +18,9 @@ @@ -196,6 +215,96 @@ CLIENTS in a SET_CLIENT collection, which are not occupied by human players.

    Controllable

    This module contains the CONTROLLABLE class.

    + + + + DCSAirbase + + + + + + DCSCoalitionObject + + + + + + DCSCommand + + + + + + DCSController + + + + + + DCSGroup + + + + + + DCSObject + + + + + + DCSTask + + + + + + DCSTypes + + + + + + DCSUnit + + + + + + DCSVec3 + + + + + + DCSWorld + + + + + + DCSZone + + + + + + DCScountry + + + + + + DCStimer + + + + + + DCStrigger + + @@ -372,22 +481,25 @@ and creates a CSV file logging the scoring events and results for use at team or Spawn -

    Single-Player:Yes / Multi-Player:Yes / AI:Yes / Human:No / Types:All --
    -Spawn groups of units dynamically in your missions.

    - -

    Banner Image

    - -
    - -

    1) #SPAWN class, extends Base#BASE

    - -

    The #SPAWN class allows to spawn dynamically new groups, based on pre-defined initialization settings, modifying the behaviour when groups are spawned.

    +

    Functional -- Spawn dynamically new GROUPs in your missions.

    + + + + SpawnStatic + +

    Core -- Spawn dynamically new STATICs in your missions.

    Static

    This module contains the STATIC class.

    + + + + StaticObject + + @@ -437,6 +549,18 @@ which are excellent tools to be reused in an OO environment!.

    Zone

    Core - ZONE classes define zones within your mission of various forms, with various capabilities.

    + + + + env + + + + + + land + + diff --git a/docs/Documentation/land.html b/docs/Documentation/land.html index 4861ee69b..8d34bf296 100644 --- a/docs/Documentation/land.html +++ b/docs/Documentation/land.html @@ -18,6 +18,9 @@ diff --git a/docs/Documentation/stylesheet.css b/docs/Documentation/stylesheet.css index 1b82635b5..206209132 100644 --- a/docs/Documentation/stylesheet.css +++ b/docs/Documentation/stylesheet.css @@ -1,131 +1,887 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +@import url('https://fonts.googleapis.com/css?family=Architects+Daughter'); + html { - color: #000; - background: #FFF; + font-family: sans-serif; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -ms-text-size-adjust: 100%; /* 2 */ } -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { - margin: 0; - padding: 0; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -fieldset,img { - border: 0; -} -address,caption,cite,code,dfn,em,strong,th,var,optgroup { - font-style: inherit; - font-weight: inherit; -} -del,ins { - text-decoration: none; -} -li { - list-style: bullet; - margin-left: 20px; -} -caption,th { - text-align: left; -} -h1,h2,h3,h4,h5,h6 { - font-size: 100%; - font-weight: bold; -} -q:before,q:after { - content: ''; -} -abbr,acronym { - border: 0; - font-variant: normal; -} -sup { - vertical-align: baseline; -} -sub { - vertical-align: baseline; -} -legend { - color: #000; -} -input,button,textarea,select,optgroup,option { - font-family: inherit; - font-size: inherit; - font-style: inherit; - font-weight: inherit; -} -input,button,textarea,select {*font-size:100%; -} -/* END RESET */ + +/** + * Remove default margin. + */ body { - margin-left: 1em; - margin-right: 1em; - font-family: arial, helvetica, geneva, sans-serif; - background-color: #ffffff; margin: 0px; + margin: 0; } -code, tt { font-family: monospace; } +/* HTML5 display definitions + ========================================================================== */ -body, p, td, th { font-size: .95em; line-height: 1.2em;} +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ -p, ul { margin: 10px 0 0 10px;} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} -strong { font-weight: bold;} +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ -em { font-style: italic;} +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ h1 { - font-size: 1.5em; - margin: 25px 0 20px 0; + margin: 0.67em 0; + font-size: 2em; } -h2, h3, h4 { margin: 15px 0 10px 0; } -h2 { font-size: 1.25em; } -h3 { font-size: 1.15em; } -h4 { font-size: 1.06em; } -a:link { font-weight: bold; color: #004080; text-decoration: none; } -a:visited { font-weight: bold; color: #006699; text-decoration: none; } -a:link:hover { text-decoration: underline; } +/** + * Address styling not present in IE 8/9. + */ + +mark { + color: #000; + background: #ff0; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; + max-width:100%; + height:auto; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ hr { - color:#cccccc; - background: #00007f; - height: 1px; + height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; } -blockquote { margin-left: 3em; } +/** + * Contain overflow in all browsers. + */ -ul { list-style-type: disc; } - -p.name { - font-family: "Andale Mono", monospace; - padding-top: 1em; +pre { + overflow: auto; } -p:first-child { - margin-top: 0px; +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; } -pre.example { - background-color: rgb(245, 245, 245); - border: 1px solid silver; - padding: 10px; - margin: 10px 0 10px 0; - font-family: "Andale Mono", monospace; - font-size: .85em; +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + margin: 0; /* 3 */ + font: inherit; /* 2 */ + color: inherit; /* 1 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-box-sizing: content-box; /* 2 */ + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; /* 1 */ +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + padding: 0.35em 0.625em 0.75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + padding: 0; /* 2 */ + border: 0; /* 1 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-spacing: 0; + border-collapse: collapse; +} + +td, +th { + padding: 0; +} + +/* LAYOUT STYLES */ +body { + font-family: 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 15px; + font-weight: 400; + line-height: 1.5; + color: #666; + background: #fafafa url(../../images/body-bg.jpg) 0 0 repeat; + margin-left: 1em; + margin-right: 1em; + margin: 0px; +} + +p { + margin-top: 0; +} + + +a { + color: #2879d0; +} +a:hover { + color: #2268b2; +} + +header { + padding-top: 40px; + padding-bottom: 40px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + background: #2e7bcf url(../images/header-bg.jpg) 0 0 repeat-x; + border-bottom: solid 1px #275da1; +} + +h1 { + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 32px; + font-weight: normal; + line-height: 1.5; +} + +h2 { + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 26px; + font-weight: normal; + line-height: 1.3; +} + +h3 { + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 22px; + font-weight: normal; + line-height: 1.1; +} + +.inner { + position: relative; + width: 940px; + margin: 0 auto; +} + +#content-wrapper { + padding-top: 30px; + border-top: solid 1px #fff; +} + +#main-content { + float: left; + width: 690px; +} + +#main-content img { + max-width: 100%; + height: auto; +} + +aside#sidebar { + float: right; + width: 200px; + min-height: 504px; + padding-left: 20px; + font-size: 12px; + line-height: 1.3; + background: transparent url(../../images/sidebar-bg.jpg) 0 0 no-repeat; +} + +aside#sidebar p.repo-owner, +aside#sidebar p.repo-owner a { + font-weight: bold; +} + +#downloads { + margin-bottom: 40px; +} + +a.button { + width: 134px; + height: 58px; + padding-top: 22px; + padding-left: 68px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 23px; + line-height: 1.2; + color: #fff; +} +a.button small { + display: block; + font-size: 11px; +} +header a.button { + position: absolute; + top: 0; + right: 0; + background: transparent url(../images/github-button.png) 0 0 no-repeat; +} +aside a.button { + display: block; + width: 138px; + padding-left: 64px; + margin-bottom: 20px; + font-size: 21px; + background: transparent url(../images/download-button.png) 0 0 no-repeat; +} + +code, pre { + margin-bottom: 30px; + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 13px; + color: #222; +} + +code { + padding: 0 3px; + background-color: #f2f8fc; + border: solid 1px #dbe7f3; } pre { - background-color: rgb(245, 245, 245); - border: 1px solid silver; - padding: 10px; - margin: 10px 0 10px 0; - font-family: "Andale Mono", monospace; + padding: 20px; + overflow: auto; + text-shadow: none; + background: #fff; + border: solid 1px #f2f2f2; +} +pre code { + padding: 0; + color: #2879d0; + background-color: #fff; + border: none; +} + +ul, ol, dl { + margin-bottom: 20px; } -table.index { border: 1px #00007f; } -table.index td { text-align: left; vertical-align: top; } +/* COMMON STYLES */ + +hr { + height: 0; + margin-top: 1em; + margin-bottom: 1em; + border: 0; + border-top: solid 1px #ddd; +} + +table { + width: 100%; + border: 1px solid #ebebeb; +} + +th { + font-weight: 500; +} + +td { + font-weight: 300; + text-align: center; + border: 1px solid #ebebeb; +} + +form { + padding: 20px; + background: #f2f2f2; + +} + + +/* GENERAL ELEMENT TYPE STYLES */ + +#main-content h1 { + margin-top: 0; + margin-bottom: 0; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 2.8em; + font-weight: normal; + color: #474747; + text-indent: 6px; + letter-spacing: -1px; +} + +#main-content h1:before { + padding-right: 0.3em; + margin-left: -0.9em; + color: #9ddcff; + content: "/"; +} + +#main-content h2 { + margin-bottom: 8px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 22px; + font-weight: bold; + color: #474747; + text-indent: 4px; +} +#main-content h2:before { + padding-right: 0.3em; + margin-left: -1.5em; + content: "//"; + color: #9ddcff; +} + +#main-content h3 { + margin-top: 24px; + margin-bottom: 8px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 18px; + font-weight: bold; + color: #474747; + text-indent: 3px; +} + +#main-content h3:before { + padding-right: 0.3em; + margin-left: -2em; + content: "///"; + color: #9ddcff; +} + +#main-content h4 { + margin-bottom: 8px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 15px; + font-weight: bold; + color: #474747; + text-indent: 3px; +} + +h4:before { + padding-right: 0.3em; + margin-left: -2.8em; + content: "////"; + color: #9ddcff; +} + +#main-content h5 { + margin-bottom: 8px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 14px; + color: #474747; + text-indent: 3px; +} +h5:before { + padding-right: 0.3em; + margin-left: -3.2em; + content: "/////"; + color: #9ddcff; +} + +#main-content h6 { + margin-bottom: 8px; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: .8em; + color: #474747; + text-indent: 3px; +} +h6:before { + padding-right: 0.3em; + margin-left: -3.7em; + content: "//////"; + color: #9ddcff; +} + +p { + margin-bottom: 20px; +} + +a { + text-decoration: none; +} + +p a { + font-weight: 400; +} + +blockquote { + padding: 0 0 0 30px; + margin-bottom: 20px; + font-size: 1.6em; + border-left: 10px solid #e9e9e9; +} + +ul { + list-style-position: inside; + list-style: disc; + padding-left: 20px; +} + +ol { + list-style-position: inside; + list-style: decimal; + padding-left: 3px; +} + +footer { + padding-top: 20px; + padding-bottom: 30px; + margin-top: 40px; + font-size: 13px; + color: #aaa; + background: transparent url('../../images/hr.png') 0 0 no-repeat; +} + +footer a { + color: #666; +} +footer a:hover { + color: #444; +} + +/* MISC */ +.clearfix:after { + display: block; + height: 0; + clear: both; + visibility: hidden; + content: '.'; +} + +.clearfix {display: inline-block;} +* html .clearfix {height: 1%;} +.clearfix {display: block;} + +/* #Media Queries +================================================== */ + +/* Smaller than standard 960 (devices and browsers) */ +@media only screen and (max-width: 959px) { } + +/* Tablet Portrait size to standard 960 (devices and browsers) */ +@media only screen and (min-width: 768px) and (max-width: 959px) { + .inner { + width: 740px; + } + header h1, header h2 { + width: 340px; + } + header h1 { + font-size: 60px; + } + header h2 { + font-size: 30px; + } + #main-content { + width: 490px; + } + #main-content h1:before, + #main-content h2:before, + #main-content h3:before, + #main-content h4:before, + #main-content h5:before, + #main-content h6:before { + padding-right: 0; + margin-left: 0; + content: none; + } +} + +/* All Mobile Sizes (devices and browser) */ +@media only screen and (max-width: 767px) { + .inner { + width: 93%; + } + header { + padding: 20px 0; + } + header .inner { + position: relative; + } + header h1, header h2 { + width: 100%; + } + header h1 { + font-size: 48px; + } + header h2 { + font-size: 24px; + } + header a.button { + position: relative; + display: inline-block; + width: auto; + height: auto; + padding: 5px 10px; + margin-top: 15px; + font-size: 13px; + line-height: 1; + color: #2879d0; + text-align: center; + background-color: #9ddcff; + background-image: none; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + header a.button small { + display: inline; + font-size: 13px; + } + #main-content, + aside#sidebar { + float: none; + width: 100% ! important; + } + aside#sidebar { + min-height: 0; + padding: 20px 0; + margin-top: 20px; + background-image: none; + border-top: solid 1px #ddd; + } + aside#sidebar a.button { + display: none; + } + #main-content h1:before, + #main-content h2:before, + #main-content h3:before, + #main-content h4:before, + #main-content h5:before, + #main-content h6:before { + padding-right: 0; + margin-left: 0; + content: none; + } +} + +/* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ +@media only screen and (min-width: 480px) and (max-width: 767px) { } + +/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ +@media only screen and (max-width: 479px) { } + #container { margin-left: 1em; @@ -144,7 +900,8 @@ table.index td { text-align: left; vertical-align: top; } } #main { - background-color: #f0f0f0; + color: #666; + background: #fafafa url(../../images/body-bg.jpg) 0 0 repeat; border-left: 2px solid #cccccc; } @@ -152,20 +909,28 @@ table.index td { text-align: left; vertical-align: top; } float: left; width: 18em; vertical-align: top; - background-color: #f0f0f0; overflow: scroll; position: fixed; height:100%; + background: #2e7bcf url(../../images/header-bg.jpg) 0 0 repeat-x; + color: #fff; } #navigation h2 { - background-color:#e7e7e7; - font-size:1.1em; - color:#000000; + font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; + background: #2e7bcf url(../images/header-bg.jpg) 0 0 repeat-x; + border-bottom: solid 1px #275da1; + width: 540px; + margin-top: 0; + margin-bottom: 0.2em; + font-size: 36px; + font-weight: normal; + line-height: 1; + color: #fff; + letter-spacing: -1px; text-align: left; padding:0.2em; border-top:1px solid #dddddd; - border-bottom:1px solid #dddddd; } #navigation ul @@ -173,16 +938,24 @@ table.index td { text-align: left; vertical-align: top; } font-size:1em; list-style-type: none; margin: 1px 1px 10px 1px; + color: #fff; } #navigation li { text-indent: -1em; display: block; margin: 3px 0px 0px 22px; + color: #fff; } +#navigation ul li a { + color: #fff; +} + + #navigation li li a { margin: 0px 3px 0px -1em; + color: #fff; } #content { @@ -193,6 +966,27 @@ table.index td { text-align: left; vertical-align: top; } background-color: #ffffff; } + +#content h2 a { + color: #000; + border-bottom: 1px solid #000; +} + +#content h2 a code { +font-size: 22px; +font-weight: 400; +background-color: transparent; +color: #2879d0; +border: none; +} + +#content h1 code { +font-size: 26px; +font-weight: 400; +background-color: transparent; +border: none; +} + #about { clear: both; padding: 5px; @@ -200,70 +994,45 @@ table.index td { text-align: left; vertical-align: top; } background-color: #ffffff; } -@media print { - body { - font: 12pt "Times New Roman", "TimeNR", Times, serif; - } - a { font-weight: bold; color: #004080; text-decoration: underline; } - - #main { - background-color: #ffffff; - border-left: 0px; - } - - #container { - margin-left: 2%; - margin-right: 2%; - background-color: #ffffff; - } - - #content { - padding: 1em; - background-color: #ffffff; - } - - #navigation { - display: none; - } - pre.example { - font-family: "Andale Mono", monospace; - font-size: 10pt; - page-break-inside: avoid; - } -} - -table.module_list { - border-width: 1px; - border-style: solid; - border-color: #cccccc; - border-collapse: collapse; -} -table.module_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #cccccc; -} -table.module_list td.name { background-color: #f0f0f0; } -table.module_list td.summary { width: 100%; } - - table.function_list { border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } + table.function_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; + word-wrap:break-word; } -table.function_list td.name { background-color: #f0f0f0; } -table.function_list td.summary { width: 100%; } -dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} -dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} -dl.table h3, dl.function h3 {font-size: .95em;} +table.function_list td.name { font-weight: 400; width:50%; white-space: normal; text-align:left;} +table.function_list td.summary { width: 50%; } + +dl.table dt, dl.function { + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; + border-bottom: 1px solid #ccc; +} + +dl.table dt, dl.function dt { + border-top: 1px solid #000; + padding-top: 0.5em; + padding-bottom: 0.5em; + border-bottom: 1px solid #ccc; +} + +dl.table dd, dl.function dd { + padding-bottom: 0.5em; + margin: 20px 0 0 20px; +} + +dl.table dd, dl.function dd p { + font-weight : normal; +} + +dl.table h3, dl.function h3 {font-size: 1.5em;} diff --git a/docs/Installation/LDT_Project_Existing_Location.JPG b/docs/Installation/LDT_Project_Existing_Location.JPG new file mode 100644 index 000000000..a36765470 Binary files /dev/null and b/docs/Installation/LDT_Project_Existing_Location.JPG differ diff --git a/docs/Presentations/RADIO/Dia1.JPG b/docs/Presentations/RADIO/Dia1.JPG new file mode 100644 index 000000000..d245e9749 Binary files /dev/null and b/docs/Presentations/RADIO/Dia1.JPG differ diff --git a/docs/Presentations/SPAWNSTATIC.pptx b/docs/Presentations/SPAWNSTATIC.pptx new file mode 100644 index 000000000..53e14f0dc Binary files /dev/null and b/docs/Presentations/SPAWNSTATIC.pptx differ diff --git a/docs/Presentations/SPAWNSTATIC/Dia1.JPG b/docs/Presentations/SPAWNSTATIC/Dia1.JPG new file mode 100644 index 000000000..46fcee945 Binary files /dev/null and b/docs/Presentations/SPAWNSTATIC/Dia1.JPG differ diff --git a/docs/README.md b/docs/README.md index 56c645be6..6339e9b0f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -94,7 +94,7 @@ You'll need to browse to the right MOOSE Class within the inheritance tree struc ## 4.1) MOOSE Demonstration Missions -The framework comes with demonstration missions which can be downloaded [here](https://github.com/FlightControl-Master/MOOSE_PRESENTATIONS/releases), that you can try out and helps you to code. +The framework comes with demonstration missions which can be downloaded [here](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases), that you can try out and helps you to code. These missions provide examples of defined use cases how the MOOSE framework can be utilized. Each test mission is located in a separate directory, which contains at least one .lua file and .miz file. The .lua file contains the mission script file that shows how the use case was implemented. You can copy/paste code the code snippets from this .lua file into your missions, as it will accellerate your mission developments. diff --git a/docs/Usage_Guide.md b/docs/Usage_Guide.md index 90afd885b..5e936f4f3 100644 --- a/docs/Usage_Guide.md +++ b/docs/Usage_Guide.md @@ -3,6 +3,7 @@ Using the MOOSE framework is very easy, and this document provides you with a detailed explanation how to install and use MOOSE within your missions. + ## 1.1) MOOSE framework at GitHub You can find the source of [MOOSE framework on GITHUB](https://github.com/FlightControl-Master/MOOSE/). @@ -10,6 +11,7 @@ It is free for download and usage, since it is released under the GNU 3.0 open s Although the MOOSE contributors and tester are using the GitHub service to enforces a structured approval process, release and change management, and a communicative distribution and deployment, you, as a mission designer, don't need to mess with it. Still, if you are interrested intesting the latest features of MOOSE of in adding your own, you can read the [relevant](http://flightcontrol-master.github.io/MOOSE/Beta_Test_Guide.html) [guides](http://flightcontrol-master.github.io/MOOSE/Contribution_Guide.html) and/or contact FlightControl The MOOSE framework development is an open source project, and as such, contributors are welcome and encouraged to contribute on the development.Some key users have already started with this process. + ## 1.2) Eclipse LDT MOOSE utilizes the Eclipse Lua Development Tools. As a result, the MOOSE framework is documented using the luadocumentor standard. @@ -18,6 +20,7 @@ What that means is that while you are coding your mission, your object and varia ![Intellisense](Usage/Intellisense.JPG) + ## 1.3) LUA training In order to efficiently use the MOOSE framework, it is highly recommended that you learn a couple of basic principles of lua. @@ -28,18 +31,23 @@ knowledge to "understand" the code, and also, to understand the syntax. **Therefore, I suggest you walk through this [lua quick guide](https://www.tutorialspoint.com/lua/lua_quick_guide.htm)**. Ignore the lua environment setup. DCS comes with a pre-defined lua environment. -# 2) MOOSE Installation Guide -## 2.1) Download the latest release of MOOSE + +# 2) Download the latest release of MOOSE The delivery of MOOSE follows a structured release process. Over time, new features are added that can be used in your mission. + ## The latest release of MOOSE can be downloaded **[here](https://github.com/FlightControl-Master/MOOSE/releases)**. **Unzip the files into a directory of your choice, but keep the folder structure intact**. -## 2.2) Download and install the Eclipse Lua Development Tools (LDT), which is an advanced lua editor. + +# 3) Download the software + + +## 3.1) Download and install the Eclipse Lua Development Tools **(LDT)**, which is an advanced lua editor. 1. If you don't have JAVA yet, you may have to install [java](https://www.java.com/en/download) first. 2. Download and Install [Eclipse LDT](https://eclipse.org/ldt) on your Windows 64 bit system. @@ -47,14 +55,17 @@ The delivery of MOOSE follows a structured release process. Over time, new featu TNow you should have a working LDT on your system. Don't skip this step, LDT is a game-changer. Don't believe us ? Well we challenge you to test and tell us what you think ! Once you tried coding with intellisense, you won't go back ! -## 2.3) Configure your LDT for the usage of MOOSE. -You need to configure your Eclipse LDT environment and link it with the MOOSE respository. + +# 4) Setup the **Moose_Framework project** in LDT. + +You need to configure your Eclipse LDT environment and link it with the Moose code. This will enable you to **start developing mission scripts** in lua, which will be **fully intellisense enabled**!!! Please follow the steps outlined! -### 2.3.1) Create a new **Workspace** in LDT. + +## 4.1) Create a new **Workspace** in LDT. The LDT editor has a concept of **Workspaces**, which contains all your settings of your editing environment, like views, menu options etc, and your code... Nothing to pay attention to really, but you need to set it up! @@ -63,44 +74,79 @@ When you open EclipseLDT for the first time, it will ask you where to put your * 1. Open Eclipse LDT. 2. Select the default workspace that LDT suggests. -### 2.3.2) Create a new **Project** in LDT. -Here, we will create a **New Project** called **Moose_Framework** in your LDT environment. -The project details are already defined within the MOOSE framework repository, -which is unzipped on your local MOOSE directory on your PC. -We will link into that directory and automatically load the Project properties. +## 4.2) Setup a **new project** in LDT and name it **Moose_Framework**. -1. Select from the Menu: **File** -> **New** -> **Lua Project**. +### 4.2.1) Select from the Menu: **File** -> **New** -> **Lua Project**. ![LDT_New_Project](Installation/LDT_New_Project.JPG) -2. A **New Project** dialog box is shown. +Here, we will create a **New Project** called **Moose_Framework** in your LDT environment. + +### Important! Name your project **Moose_Framework** + +The project details are already defined within the MOOSE framework repository, +which is unzipped in your **local Moose folder** on your PC. +We will link into that directory and **automatically load the Project properties**. + + +### 4.2.2) Type the Project Name: **Moose_Framework**. ![LDT_Project](Installation/LDT_Project.JPG) -3. Type the Project Name: **Moose_Framework**. -4. In the sub-box "Project Contents", select the option **Create Project at existing location** (from existing source). -5. **Browse** to the local MOOSE directory (press on the Browse button) and select the root directory of your local MO.OSE directory on your PC. Press OK. -6. You're back at the "New Project" dialog box. Press the **Next** button below the dialog box. +### 4.2.3) In the sub-box "Project Contents", select the option **Create Project at existing location** (from existing source). + +![LDT_Project](Installation/LDT_Project_Existing_Location.JPG) + +### 4.2.4) **Browse** to the local MOOSE directory (press on the Browse button) and select the **local Moose folder on your PC, which you unzipped**. Press OK. + +### 4.2.5) You're back at the "New Project" dialog box. Press the **Next** button below the dialog box. + __(All the other settings are by default ok)__. -7. You should see now a dialog box with the following properties. -Note that the Moose Development/Moose directory is flagged as the **Source Directory*. (It is listed totally on top.) + +### 4.2.6) You should see now a dialog box with the following properties. + +The Moose Development/Moose directory should be flagged as the **Source Directory*. (It is listed totally on top.) This is important because it will search in the files in this directory and sub directories for lua documentator enabled lua files. This will enable the intellisense of the MOOSE repository! ![LDT Finish](Installation/LDT_Moose_Framework_Finish.JPG) -8. Press the **Finish** button. +### 4.2.7) Press the **Finish** button. As a result, when you browse to the Script Explorer, you'll see the following: ![LDT_Script_Explorer](Installation/LDT_Script_Explorer.JPG) -**Congratulations! You have now setup your Moose_Framework project LDT environment!** +### 4.2.8) **Congratulations! You have now setup your Moose_Framework project LDT environment!** -# 2.4) Your first mission -## 2.4.1) Setup your **Mission Project** in LDT + +# 5) Setup a new project **Moose_Missions** in LDT, containing the the Moose demonstration missions. + +The framework comes with demonstration missions which can be downloaded [here](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases), that you can try out and helps you to code. +These missions provide examples of defined use cases how the MOOSE framework can be utilized. Each test mission is located in a separate directory, which contains at least one .lua file and .miz file. The .lua file contains the mission script file that shows how the use case was implemented. You can copy/paste code the code snippets from this .lua file into your missions, as it will accellerate your mission developments. You will learn, see, and understand how the different MOOSE classes need to be applied, and how you can create more complex mission scenarios by combining these MOOSE classes into a complex but powerful mission engine. +Some of these exact test missions are also demonstrated in a video format on the [YouTube channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg). + +## 5.1) Download the [Moose demonstration missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) latest release package. + + +## 5.2) Unzip the package into a local folder on your PC. + + +## 5.3) Setup a **new project** in LDT and name it **Moose_Missions**. + +### 5.3.1) In LDT, select from the menu **New lua project**, and name it Moose_Missions. + +### 5.3.2) Select the local folder on your PC, where you saved the demonstration missions contents. + +### 5.3.3) Press Finish + + + +# 6) Setup Your first mission + +## 6.1) Setup a new project in LDT and name it **My_Missions** In order to design your own missions, it is recommended you create a separate directory on your PC which contains your mission files. Your mission will be designed consisting possibly @@ -119,16 +165,15 @@ Therefore, **the recommendation is that your create for each mission a separate The MOOSE test mission folder structure is a good example how this could be organized. The LDT has been customized and provides a tool to **automatically** maintain your existing .miz files. -### 2.4.1.1. Select from the Menu: **File** -> **New** -> **Lua Project**. +### 6.1.1. Select from the Menu: **File** -> **New** -> **Lua Project**. ![LDT_New_Project](Installation/LDT_New_Project.JPG) -### 2.4.1.2. A **New Project** dialog box is shown. +### 6.1.2. A **New Project** dialog box is shown. ![LDT_Project](Installation/LDT_Project.JPG) -### 2.4.1.3. Type your Project Name: (In my example it is **DCS_Caucasus_Missions**. - +### 6.1.3. Type your Project Name: (In my example it is **DCS_Caucasus_Missions**. Note the indicated options in yellow: @@ -137,51 +182,51 @@ Note the indicated options in yellow: ![LDT_Project](Installation/LDT_Project_My_Missions.JPG) -### 2.4.1.4. Press **Next >** +### 6.1.4. Press **Next >** -### 2.4.1.5. Click the **Projects** tab at the top of the window. +### 6.1.5. Click the **Projects** tab at the top of the window. ![LDT_Project](Installation/LDT_New_Project_Projects.JPG) -### 2.4.1.6. Press the **Add...** button. +### 6.1.6. Press the **Add...** button. -### 2.4.1.7. A new windows will be displayed: **Required Project Selection**. +### 6.1.7. A new windows will be displayed: **Required Project Selection**. This is an important step. This will _link_ your project to the Moose_Framework project and will activate **intellisense**. ![LDT_Project](Installation/LDT_Select_Moose_Framework.JPG) -### 2.4.1.8. After the selection, press the **OK** button. +### 6.1.8. After the selection, press the **OK** button. -### 2.4.1.9. Watch your newly created project in the Script Explorer of LDT. +### 6.1.9. Watch your newly created project in the Script Explorer of LDT. You can delete the possibly created SRC directory. You won't need it at all. ![LDT_Project](Installation/LDT_Delete_Src.JPG) -### 2.4.1.10. Within your newly created Missions Project, right click and select **New -> Folder**. +### 6.1.10. Within your newly created Missions Project, right click and select **New -> Folder**. As explained above, each of your missions will be stored in a separate folder. Please follow the explanation how to do that. ![LDT_Project](Installation/LDT_Add_Folder.JPG) -### 2.4.1.11. Type the **Folder Name**. +### 6.1.11. Type the **Folder Name**. This can be any descriptive text explaining the title of your mission. ![LDT_Project](Installation/LDT_Mission_Folder_Name.JPG) -### 2.4.1.12. In your newly created **Mission Folder**, right click and select **New -> Lua File**. +### 6.1.12. In your newly created **Mission Folder**, right click and select **New -> Lua File**. This will create your **mission script file**, the file that contains all the lua code using the Moose framework using your mission. -### 2.4.1.13. Type the **Lua Mission Script Name**. +### 6.1.13. Type the **Lua Mission Script Name**. ![LDT_Project](Installation/LDT_Mission_Lua_File_Name.JPG) -## 2.4.2) Create your first Mission file +## 6.2) Create your first Mission file In the root of the MOOSE package, a file named **Moose.lua** can be found. In order to create or design a mission using the MOOSE framework, @@ -198,11 +243,11 @@ Voila, MOOSE is now included in your mission. During the execution of this missi Find below a detailed explanation of the actions to follow: -### 2.4.2.1. Open the Mission Editor in DCS, select an empty mission, and click the triggers button. +### 6.2.1. Open the Mission Editor in DCS, select an empty mission, and click the triggers button. ![LDT_Project](Installation/DCS_Triggers_Empty.JPG) -### 2.4.2.2. Add a new trigger, that will load the Moose.lua file. +### 6.2.2. Add a new trigger, that will load the Moose.lua file. Check the cyan colored circles: @@ -213,7 +258,7 @@ Check the cyan colored circles: ![LDT_Project](Installation/DCS_Triggers_Load_Moose_Add.JPG) -### 2.4.2.3. Select the Moose.lua loader from the **Moose Mission Setup** folder in the Moose_Framework pack. +### 6.2.3. Select the Moose.lua loader from the **Moose Mission Setup** folder in the Moose_Framework pack. Additional notes: @@ -224,11 +269,11 @@ Press the **OK** button. ![LDT_Project](Installation/DCS_Triggers_Load_Moose_Select_File.JPG) -### 2.4.2.4. Check that the Moose.lua file has been correctly added to your Mission. +### 6.2.4. Check that the Moose.lua file has been correctly added to your Mission. ![LDT_Project](Installation/DCS_Triggers_Load_Moose_File_Added.JPG) -### 2.4.2.5. Add a new trigger, that will load your mission .lua file. +### 6.2.5. Add a new trigger, that will load your mission .lua file. Check the cyan colored circles: @@ -239,7 +284,7 @@ Check the cyan colored circles: ![LDT_Project](Installation/DCS_Triggers_Load_Mission_Add.JPG) -### 2.4.2.6. Select the mission .lua file from your **missions** folder you just created or already have. +### 6.2.6. Select the mission .lua file from your **missions** folder you just created or already have. Additional notes: @@ -250,23 +295,24 @@ Press the **OK** button. ![LDT_Project](Installation/DCS_Triggers_Load_Mission_File_Select.JPG) -### 2.4.2.7. Check that your mission .lua script file has been correctly added to your mission. +### 6.2.7. Check that your mission .lua script file has been correctly added to your mission. ![LDT_Project](Installation/DCS_Triggers_Load_Mission_File_Added.JPG) -## 2.4.3) Maintain your .miz files +## 6.3) Maintain your .miz files IMPORTANT NOTE: When a new version of MOOSE is released, you'll have to UPDATE the Moose.lua file in EACH OF YOUR MISSION. This can be a tedious task, and for this purpose, a tool has been developed that will update the Moose.lua files automatically within your missions. -### 2.4.3.1. Select the **Update SELECTED Mission** from the External Tools in LDT. +### 6.3.1. Select the **Update SELECTED Mission** from the External Tools in LDT. This will activate a script that will automatically re-insert your mission .lua file into your mission. ![LDT_Project](Installation/DCS_Triggers_Load_Mission_File_Added.JPG) -## 2.4.4) Create folder links into your "My Missions" folder in Saved Games/DCS/Missions. + +## 6.4) Create folder links into your "My Missions" folder in Saved Games/DCS/Missions. ***TODO : Detail how hard links work, explain how they help the wworkflow*** @@ -274,13 +320,7 @@ This trick will save you a lot of time. You need to install the tool ... to crea Select from the following possible links that can be created to save you time while browing through the different folders to include script files: -### 2.4.4.1. Create a link to your **Moose Mission Setup** folder ... +### 6.4.1. Create a link to your **Moose Mission Setup** folder ... -### 2.4.4.2. Create a link to your **missions** folder ... - -# 4) Demonstration Missions - -The framework comes with demonstration missions which can be downloaded [here](https://github.com/FlightControl-Master/MOOSE_PRESENTATIONS/releases), that you can try out and helps you to code. -These missions provide examples of defined use cases how the MOOSE framework can be utilized. Each test mission is located in a separate directory, which contains at least one .lua file and .miz file. The .lua file contains the mission script file that shows how the use case was implemented. You can copy/paste code the code snippets from this .lua file into your missions, as it will accellerate your mission developments. You will learn, see, and understand how the different MOOSE classes need to be applied, and how you can create more complex mission scenarios by combining these MOOSE classes into a complex but powerful mission engine. -Some of these exact test missions are also demonstrated in a video format on the [YouTube channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg). +### 6.4.2. Create a link to your **missions** folder ...