diff --git a/src/base/api.lua b/src/base/api.lua index 73ea4dbd..3d5e1b69 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -17,6 +17,9 @@ -- scope (e.g. solutions, projects, groups, and configurations). Initialize -- it with a "root" container to contain the other containers, as well as the -- global configuration settings which should apply to all of them. +-- +-- TODO: this should be hidden, with a perhaps a read-only accessor to fetch +-- individual scopes for testing. --- api.scope = {} @@ -78,6 +81,22 @@ +--- +-- Recursively clear any child scopes for a container class. For example, +-- if a solution is being activated, clear the project and group scopes, +-- as those are children of solutions. If the root scope is made active, +-- all child scopes will be cleared. +--- + + function api._clearChildScopes(cc) + for ch in cc:eachChildClass() do + api.scope[ch.name] = nil + api._clearChildScopes(ch) + end + end + + + --- -- Activate a new configuration container, making it the target for all -- subsequent configuration settings. When you call solution() or project() @@ -89,28 +108,54 @@ -- @param name -- The name of the container instance to be activated. If a container -- (e.g. project) with this name does not already exist it will be --- created. +-- created. If name is not set, the last activated container of this +-- class will be made current again. -- @return -- The container instance. --- function api._setScope(cc, name) - local instance + -- for backward compatibility, "*" activates the parent container + if name == "*" then + return api._setScope(cc.parent) + end - -- << handle (name == nil) >> + -- if name is not set, use whatever was last made current + local container + if not name then + container = api.scope[cc.name] + if not container then + error("no " .. cc.name .. " in scope", 3) + end + end - -- << handle "*" >> + if not container then + -- all containers should be contained within a parent + local parent = api.scope[cc.parent.name] + if not parent then + error("no active " .. cc.parent.name, 3) + end - -- Fetch (creating if necessary) the container - local parentContainer = api._target(cc.parent) - local container = parentContainer:fetchContainer(cc, name) + -- fetch (creating if necessary) the container + container = parent:fetchChild(cc, name) + if not container then + container = parent:createChild(cc, name, parent) + else + configset.addFilter(container, {}, os.getcwd()) + end + end - -- << start a new settings block >> + -- clear out any active child container types + api._clearChildScopes(cc) - -- Activate the container - api.scope[cc.name] = container -- TODO: do I still need this? + -- activate the container, as well as its ancestors api.scope.current = container - return container + while container.parent do + api.scope[container.class.name] = container + container = container.parent + end + + return api.scope.current end @@ -630,6 +675,9 @@ --- function api.reset() + -- Clear out all top level objects + api.scope.root.solutions = {} + -- Remove all custom variables local vars = api.getCustomVars() for i, var in ipairs(vars) do @@ -1034,6 +1082,23 @@ + + local _slnContainerClass = api.container { + name = "solution", + } + + api.container { + name = "group", + parent = "solution", + } + + api.container { + name = "project", + parent = "solution", + } + + + --- -- Begin a new solution group, which will contain any subsequent projects. --- @@ -1056,15 +1121,6 @@ -- The active project object. -- - api.container { - name = "solution", - } - - api.container { - name = "project", - parent = "solution", - } - function project(name) if not name then if api.scope.project then @@ -1081,6 +1137,7 @@ local prj if name ~= "*" then + sln.projects = sln.projects or {} prj = sln.projects[name] if not prj then prj = premake.project.new(sln, name) @@ -1120,44 +1177,6 @@ --- --- Set the current configuration scope to a solution. --- --- @param name --- The name of the solution. If a solution with this name already --- exists, it is made current, otherwise a new solution is created --- with this name. If no name is provided, the most recently defined --- solution is made active. --- @return --- The active solution object. --- - - function solution(name) - if not name then - if api.scope.solution then - name = api.scope.solution.name - else - return nil - end - end - - local sln - if name ~= "*" then - sln = premake.solution.get(name) or premake.solution.new(name) - sln.class = p.containerClass.get("solution") - end - - api.scope.solution = sln - api.scope.project = nil - api.scope.group = nil - api.scope.current = sln - - configuration {} - - return sln - end - - -- -- Define a new action. -- diff --git a/src/base/container.lua b/src/base/container.lua index e3bdfdd3..695eef9f 100644 --- a/src/base/container.lua +++ b/src/base/container.lua @@ -73,6 +73,8 @@ -- An initializer function to call for new instances of this class. -- Should accept the new instance object as its only argument. -- +-- Other keys are allowed and will be left intact. +-- -- @return -- A new container class object if successful, else nil and an -- error message. @@ -102,8 +104,8 @@ -- Looks good, set myself up and add to master list - def.children = {} - def.listKey = def.name:plural() + def._children = {} + def._listKey = def.name:plural() setmetatable(def, p.containerClass) container._classes[def.name] = def @@ -111,7 +113,7 @@ def.parent = container._classes[def.parent] if def.parent then - table.insert(def.parent.children, def) + table.insert(def.parent._children, def) end return def @@ -119,6 +121,23 @@ +--- +-- Enumerate the child container class of a given class. +--- + + function p.containerClass:eachChildClass() + local children = self._children + local i = 0 + return function () + i = i + 1 + if i <= #children then + return children[i] + end + end + end + + + --- -- Retrieve a container class by name. -- @@ -158,6 +177,32 @@ +--- +-- Create a new child container of the given class, with the specified name. +-- +-- @param cc +-- The class of child container to be fetched. +-- @param key +-- A string key or array index for the container. +-- @param parent +-- The parent container instance. +-- @return +-- The child container instance. +--- + + function container:createChild(cc, key, parent) + self[cc._listKey] = self[cc._listKey] or {} + local list = self[cc._listKey] + + local child = cc:new(key, parent) + table.insert(list, child) + list[key] = child + + return child + end + + + --- -- Return an iterator for the child containers of a particular class. -- @@ -165,8 +210,8 @@ -- The class of child container to be enumerated. --- - function container:eachContainer(cc) - local children = self[cc.listKey] or {} + function container:eachChild(cc) + local children = self[cc._listKey] or {} local i = 0 return function () i = i + 1 @@ -180,28 +225,16 @@ --- -- Fetch the child container with the given container class and instance name. --- If it doesn't exist, a new container is created. -- -- @param cc -- The class of child container to be fetched. -- @param key --- A string key or array index for the container. If a string key is --- provided, the container will be created if it doesn't exist. If an --- array index is provided, nil will be returned if it does not exist. +-- A string key or array index for the container. -- @return -- The child container instance. --- - function container:fetchContainer(cc, key) - self[cc.listKey] = self[cc.listKey] or {} - local children = self[cc.listKey] - local c = children[key] - - if not c and type(key) == "string" then - c = cc:new(key, parent) - table.insert(children, c) - children[key] = c - end - - return c + function container:fetchChild(cc, key) + self[cc._listKey] = self[cc._listKey] or {} + return self[cc._listKey][key] end diff --git a/src/base/oven.lua b/src/base/oven.lua index 86e4b490..ce169f0a 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -10,14 +10,16 @@ -- premake.oven = {} - local oven = premake.oven - local solution = premake.solution - local project = premake.project - local config = premake.config - local fileconfig = premake.fileconfig - local configset = premake.configset - local context = premake.context + + local p = premake + local solution = p.solution + local project = p.project + local config = p.config + local fileconfig = p.fileconfig + local configset = p.configset + local context = p.context + --- @@ -34,15 +36,15 @@ --- function oven.bake(root) - -- I haven't yet ported the project objects to containers local result = {} - for i, sln in ipairs(solution.list) do + + local root = p.api.rootContainer() + root.solutions = root.solutions or {} + for i, sln in ipairs(root.solutions) do result[i] = oven.bakeSolution(sln) end - solution.list = result - - -- Start container implementation + root.solutions = result end @@ -104,6 +106,7 @@ -- store that for future reference local projects = {} + sln.projects = sln.projects or {} for i, prj in ipairs(sln.projects) do projects[i] = oven.bakeProject(prj, ctx) projects[prj.name] = projects[i] diff --git a/src/base/rules.lua b/src/base/rules.lua index a7e38de7..c8bddba4 100644 --- a/src/base/rules.lua +++ b/src/base/rules.lua @@ -31,7 +31,7 @@ --- function rules.each() - return p.api.rootContainer():eachContainer(_ruleContainerClass) + return p.api.rootContainer():eachChild(_ruleContainerClass) end @@ -46,5 +46,5 @@ --- function rules.fetch(key) - return p.api.rootContaiiner():fetchContainer(_ruleContainerClass, key) + return p.api.rootContainer():fetchChild(_ruleContainerClass, key) end diff --git a/src/base/solution.lua b/src/base/solution.lua index b956de2e..513fdb72 100644 --- a/src/base/solution.lua +++ b/src/base/solution.lua @@ -6,41 +6,12 @@ premake.solution = {} local solution = premake.solution - local project = premake.project - local configset = premake.configset - local context = premake.context - local tree = premake.tree + local p = premake + local project = p.project + local context = p.context + local tree = p.tree --- The list of defined solutions (which contain projects, etc.) - - solution.list = {} - - --- --- Create a new solution and add it to the session. --- --- @param name --- The new solution's name. --- @return --- A new solution object. --- - - function solution.new(name) - sln = configset.new(premake.api.rootContainer()) - setmetatable(sln, configset.metatable(sln)) - - sln.name = name - sln.projects = {} - sln.basedir = os.getcwd() - sln.filename = name - - -- Add to master list keyed by both name and index - table.insert(premake.solution.list, sln) - premake.solution.list[name] = sln - - return sln - end -- @@ -67,11 +38,13 @@ -- function solution.each() + local root = p.api.rootContainer() + local i = 0 return function () i = i + 1 - if i <= #premake.solution.list then - return premake.solution.list[i] + if i <= #root.solutions then + return root.solutions[i] end end end @@ -153,7 +126,10 @@ -- function solution.get(key) - return premake.solution.list[key] + local root = p.api.rootContainer() + if root.solutions then + return root.solutions[key] + end end diff --git a/tests/testfx.lua b/tests/testfx.lua index ff9a8316..3c04b8dc 100644 --- a/tests/testfx.lua +++ b/tests/testfx.lua @@ -339,7 +339,6 @@ stderr_capture = nil - premake.solution.list = { } premake.clearWarnings() premake.eol("\n") premake.escaper(nil)