Rework filter() and configuration() to support new container hierarchies; can now use on rules
This commit is contained in:
parent
6471232ced
commit
98aba2438f
@ -95,11 +95,13 @@
|
||||
|
||||
api.register {
|
||||
name = "buildcommands",
|
||||
scope = "config",
|
||||
scope = { "config", "rule" },
|
||||
kind = "list:string",
|
||||
tokens = true,
|
||||
}
|
||||
|
||||
api.alias("buildcommands", "buildCommands")
|
||||
|
||||
api.register {
|
||||
name = "buildoptions",
|
||||
scope = "config",
|
||||
@ -231,7 +233,7 @@
|
||||
|
||||
api.register {
|
||||
name = "filename",
|
||||
scope = "project;rule",
|
||||
scope = { "project", "rule" },
|
||||
kind = "string",
|
||||
tokens = true,
|
||||
}
|
||||
@ -452,7 +454,7 @@
|
||||
|
||||
api.register {
|
||||
name = "location",
|
||||
scope = "project;rule",
|
||||
scope = { "project", "rule" },
|
||||
kind = "path",
|
||||
tokens = true,
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
|
||||
_WORKING_DIR = os.getcwd()
|
||||
|
||||
local p = premake
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Script-side program entry point.
|
||||
@ -93,7 +96,7 @@
|
||||
|
||||
if action then
|
||||
print("Building configurations...")
|
||||
premake.oven.bake()
|
||||
p.oven.bake(p.api.rootScope())
|
||||
end
|
||||
|
||||
-- Run the interactive prompt, if requested
|
||||
|
@ -33,6 +33,16 @@
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Return the currently active configuration container instance.
|
||||
---
|
||||
|
||||
function api.activeScope()
|
||||
return api.scope.current or api.scope.root
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Register a new class of configuration container. A configuration container
|
||||
-- can hold configuration settings, as well as child configuration containers.
|
||||
@ -105,7 +115,8 @@
|
||||
-- << start a new settings block >>
|
||||
|
||||
-- Activate the container
|
||||
api.scope[cc.name] = container
|
||||
api.scope[cc.name] = container -- TODO: do I still need this?
|
||||
api.scope.current = container
|
||||
return container
|
||||
end
|
||||
|
||||
@ -397,22 +408,47 @@
|
||||
|
||||
|
||||
---
|
||||
-- Find the currently active configuration scope.
|
||||
-- Return the target container instance for a field.
|
||||
--
|
||||
-- @param fld
|
||||
-- @param field
|
||||
-- The field being set or fetched.
|
||||
-- @return
|
||||
-- The currently active configuration set object.
|
||||
-- The currently active container instance if one is available, or nil if
|
||||
-- active container is of the wrong class.
|
||||
---
|
||||
|
||||
function api.target(fld)
|
||||
if api.scope.rule and p.field.hasScope(fld, "rule") then
|
||||
return api.scope.rule
|
||||
elseif fld.scope ~= "rule" then
|
||||
return api.scope.project or api.scope.solution or api.scope.root
|
||||
else
|
||||
function api.target(field)
|
||||
-- if nothing is in scope, use the global root scope
|
||||
|
||||
if not api.scope.current then
|
||||
return api.scope.root
|
||||
end
|
||||
|
||||
-- use the current scope if it falls within the container hierarchy
|
||||
-- of one of this field's target scopes; it is okay to set a value of
|
||||
-- the parent of container (e.g. a project-level value can be set on a
|
||||
-- solution, since it will be inherited).
|
||||
|
||||
local currentClass = api.scope.current.class
|
||||
for i = 1, #field.scopes do
|
||||
-- temporary: map config scope to the desired container class; will
|
||||
-- go away once everything is ported to containers
|
||||
local targetScope = field.scopes[i]
|
||||
if targetScope == "config" then
|
||||
targetScope = "project"
|
||||
end
|
||||
|
||||
local targetClass = p.containerClass.get(targetScope)
|
||||
repeat
|
||||
if currentClass == targetClass then
|
||||
return api.scope.current
|
||||
end
|
||||
targetClass = targetClass.parent
|
||||
until not targetClass
|
||||
end
|
||||
|
||||
-- this field's scope isn't available
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@ -436,6 +472,11 @@
|
||||
end
|
||||
|
||||
local target = api.target(field)
|
||||
if not target then
|
||||
local err = string.format("unable to set %s in %s scope, should be %s", field.name, api.scope.current.class.name, table.concat(field.scopes, ", "))
|
||||
error(err, 3)
|
||||
end
|
||||
|
||||
local status, err = configset.store(target, field, value)
|
||||
if err then
|
||||
error(err, 3)
|
||||
@ -456,6 +497,11 @@
|
||||
if not value then return end
|
||||
|
||||
local target = api.target(field)
|
||||
if not target then
|
||||
local err = string.format("unable to remove %s from %s scope, should be %s", field.name, api.scope.current.class.name, table.concat(field.scopes, ", "))
|
||||
error(err, 3)
|
||||
end
|
||||
|
||||
local hasDeprecatedValues = (type(field.deprecated) == "table")
|
||||
|
||||
-- Build a list of values to be removed. If this field has deprecated
|
||||
@ -957,7 +1003,7 @@
|
||||
---
|
||||
|
||||
function configuration(terms)
|
||||
local target = api.scope.project or api.scope.solution or api.scope.root
|
||||
local target = api.activeScope()
|
||||
if terms then
|
||||
if terms == "*" then terms = nil end
|
||||
configset.addblock(target, {terms}, os.getcwd())
|
||||
@ -973,7 +1019,7 @@
|
||||
---
|
||||
|
||||
function filter(terms)
|
||||
local target = api.scope.project or api.scope.solution or api.scope.root
|
||||
local target = api.activeScope()
|
||||
if terms then
|
||||
if terms == "*" then terms = nil end
|
||||
local ok, err = configset.addFilter(target, {terms}, os.getcwd())
|
||||
@ -1007,6 +1053,15 @@
|
||||
-- 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
|
||||
@ -1026,12 +1081,15 @@
|
||||
prj = sln.projects[name]
|
||||
if not prj then
|
||||
prj = premake.project.new(sln, name)
|
||||
prj.class = p.containerClass.get("project")
|
||||
prj.group = api.scope.group or ""
|
||||
premake.solution.addproject(sln, prj)
|
||||
end
|
||||
end
|
||||
|
||||
api.scope.solution = sln
|
||||
api.scope.project = prj
|
||||
api.scope.current = prj
|
||||
|
||||
configuration {}
|
||||
|
||||
@ -1083,11 +1141,13 @@
|
||||
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 {}
|
||||
|
||||
@ -1229,6 +1289,11 @@
|
||||
end
|
||||
|
||||
local cset = api.target(field)
|
||||
if not cset then
|
||||
local err = string.format("unable to set rule in %s scope, should be project", api.scope.current.class.name)
|
||||
error(err, 2)
|
||||
end
|
||||
|
||||
local current = cset.current
|
||||
cset.current = cset.blocks[1]
|
||||
api.callback(field, value)
|
||||
|
@ -98,20 +98,40 @@
|
||||
return nil, "parent class does not exist"
|
||||
end
|
||||
|
||||
-- Fill in some calculated properties
|
||||
-- Looks good, set myself up and add to master list
|
||||
|
||||
def.children = {}
|
||||
def.listKey = def.name:plural()
|
||||
setmetatable(def, p.containerClass)
|
||||
container._classes[def.name] = def
|
||||
|
||||
-- Wire myself to my parent class
|
||||
|
||||
def.parent = container._classes[def.parent]
|
||||
def.listKey = def.name:plural()
|
||||
if def.parent then
|
||||
table.insert(def.parent.children, def)
|
||||
end
|
||||
|
||||
-- Finish: add to master list, enable calling with ":" syntax
|
||||
|
||||
container._classes[def.name] = def
|
||||
setmetatable(def, p.containerClass)
|
||||
return def
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Retrieve a container class by name.
|
||||
--
|
||||
-- @param name
|
||||
-- The class name.
|
||||
-- @return
|
||||
-- The corresponding container class if found, nil otherwise.
|
||||
---
|
||||
|
||||
function p.containerClass.get(name)
|
||||
return container._classes[name]
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Create a new instance of a container class.
|
||||
--
|
||||
|
@ -81,6 +81,13 @@
|
||||
|
||||
f._kind = kind
|
||||
|
||||
-- Make sure scope is always an array; don't overwrite old value
|
||||
if type(f.scope) == "table" then
|
||||
f.scopes = f.scope
|
||||
else
|
||||
f.scopes = { f.scope }
|
||||
end
|
||||
|
||||
-- All fields must have a valid store() function
|
||||
if not field.accessor(f, "store") then
|
||||
return nil, "invalid field kind '" .. f._kind .. "'"
|
||||
@ -251,25 +258,6 @@
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Check to see if a field supports a given project scope.
|
||||
--
|
||||
-- @param f
|
||||
-- The field to test.
|
||||
-- @param scope
|
||||
-- The scope to look for (e.g. "config", "project", "rule").
|
||||
-- @return
|
||||
-- The scope value if found, nil otherwise.
|
||||
---
|
||||
|
||||
function field.hasScope(f, scope)
|
||||
if f.scope == scope or f.scope:find(scope, 1, true) then
|
||||
return scope
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function field.merge(f, current, value)
|
||||
local processor = field.accessor(f, "merge")
|
||||
if processor then
|
||||
|
@ -172,7 +172,7 @@
|
||||
|
||||
function fileconfig.hasFileSettings(fcfg)
|
||||
for key, field in pairs(premake.fields) do
|
||||
if p.field.hasScope(field, "config") then
|
||||
if field.scopes[1] == "config" then
|
||||
local value = fcfg[field.name]
|
||||
if value then
|
||||
if type(value) == "table" then
|
||||
|
@ -20,19 +20,29 @@
|
||||
local context = premake.context
|
||||
|
||||
|
||||
---
|
||||
-- Traverses the entire container hierarchy built up by the project scripts,
|
||||
-- filters, merges, and munges the project settings based on the current
|
||||
-- runtime environment, and returns a new container hierarchy with the end
|
||||
-- result. This result will then get handed off to the current action to
|
||||
-- do whatever it is it needs to do, like generate project files.
|
||||
--
|
||||
-- Iterates through all of the current solutions, bakes down their contents,
|
||||
-- and then replaces the original solution object with the baked result.
|
||||
-- This is the entry point to the whole baking process, which happens after
|
||||
-- the scripts have run, but before the project files are generated.
|
||||
--
|
||||
-- @param root
|
||||
-- The top level or root container to be baked.
|
||||
-- @return
|
||||
-- ???
|
||||
---
|
||||
|
||||
function oven.bake()
|
||||
function oven.bake(root)
|
||||
-- I haven't yet ported the project objects to containers
|
||||
local result = {}
|
||||
for i, sln in ipairs(solution.list) do
|
||||
result[i] = oven.bakeSolution(sln)
|
||||
end
|
||||
solution.list = result
|
||||
|
||||
-- Start container implementation
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
@ -410,8 +410,12 @@ end
|
||||
|
||||
function premake.validateScopes(cfg, expected, ctx)
|
||||
for f in field.each() do
|
||||
-- Pull out the project level scope
|
||||
local scope = field.hasScope(f, "config") or field.hasScope(f, "project") or field.hasScope(f, "solution")
|
||||
-- Pull out the project level scope (this will get cleaned up when
|
||||
-- the project objects move to the new container API)
|
||||
local scope
|
||||
if f.scopes[1] ~= "rule" then
|
||||
scope = f.scopes[1]
|
||||
end
|
||||
|
||||
-- Skip fields that are at or below the expected scope. Config-
|
||||
-- level fields are the most general (can be applied to projects
|
||||
|
@ -83,38 +83,16 @@
|
||||
-- Warn if a configuration value is set in the wrong scope.
|
||||
--
|
||||
|
||||
function suite.warns_onSolutionStringField_inProject()
|
||||
solution "MySolution"
|
||||
configurations { "Debug", "Release" }
|
||||
project "MyProject"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
startproject "MyProject"
|
||||
premake.validate()
|
||||
test.stderr("'startproject' on project")
|
||||
end
|
||||
|
||||
function suite.warns_onSolutionStringField_inConfig()
|
||||
solution "MySolution"
|
||||
configurations { "Debug", "Release" }
|
||||
project "MyProject"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
filter "Debug"
|
||||
startproject "MyProject"
|
||||
premake.validate()
|
||||
test.stderr("'startproject' on config")
|
||||
end
|
||||
|
||||
function suite.warns_onSolutionStringField_onlyWarnOnce()
|
||||
solution "MySolution"
|
||||
configurations { "Debug", "Release" }
|
||||
project "MyProject"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
startproject "MyProject"
|
||||
premake.validate()
|
||||
test.notstderr("'startproject' on config")
|
||||
test.stderr("'startproject' on config")
|
||||
end
|
||||
|
||||
function suite.warns_onProjectStringField_inConfig()
|
||||
|
Loading…
Reference in New Issue
Block a user