Require configuration set fetch/store to use registered fields only; phase out direct table access
This commit is contained in:
parent
c42c87a4ee
commit
974b622b82
@ -306,7 +306,7 @@
|
||||
local target = api.gettarget(field.scope)
|
||||
|
||||
if not value then
|
||||
return target.configset[field.name]
|
||||
return configset.fetchvalue(target.configset, field.name)
|
||||
end
|
||||
|
||||
local status, result = pcall(function ()
|
||||
@ -367,7 +367,7 @@
|
||||
end
|
||||
|
||||
if value:contains("*") then
|
||||
local current = target.configset[field.name]
|
||||
local current = configset.fetchvalue(target.configset, field.name)
|
||||
local mask = path.wildcards(value)
|
||||
for _, item in ipairs(current) do
|
||||
if item:match(mask) == item then
|
||||
@ -561,18 +561,16 @@
|
||||
--
|
||||
|
||||
function api.settable(target, name, field, value)
|
||||
-- if the target is the project, configset will be set and I can push
|
||||
-- the value there. Otherwise I was called to store into some other kind
|
||||
-- of object (i.e. an array or list)
|
||||
target = target.configset or target
|
||||
|
||||
-- put simple values in an array
|
||||
if type(value) ~= "table" then
|
||||
value = { value }
|
||||
end
|
||||
|
||||
-- store it, overwriting any existing value
|
||||
target[name] = value
|
||||
if target.configset then
|
||||
configset.addvalue(target.configset, field.name, value)
|
||||
else
|
||||
target[name] = value
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -641,13 +639,6 @@
|
||||
function api.setlist(target, name, field, value)
|
||||
local setter = api.getSetter(field, api.ListLevel)
|
||||
|
||||
-- If this target is just a wrapper for a configuration set,
|
||||
-- apply the new values to that set instead. The current
|
||||
-- solution and project objects act this way.
|
||||
if target.configset then
|
||||
target = target.configset
|
||||
end
|
||||
|
||||
-- process all of the values, according to the data type
|
||||
local result = {}
|
||||
local function recurse(value)
|
||||
@ -661,7 +652,14 @@
|
||||
end
|
||||
recurse(value)
|
||||
|
||||
target[name] = result
|
||||
-- If this target is just a wrapper for a configuration set,
|
||||
-- apply the new values to that set instead. The current
|
||||
-- solution and project objects act this way.
|
||||
if target.configset then
|
||||
configset.addvalue(target.configset, field.name, result)
|
||||
else
|
||||
target[name] = result
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -713,8 +711,11 @@
|
||||
-- if the target is the project, configset will be set and I can push
|
||||
-- the value there. Otherwise I was called to store into some other kind
|
||||
-- of object (i.e. an array or list)
|
||||
target = target.configset or target
|
||||
target[name] = value
|
||||
if target.configset then
|
||||
configset.addvalue(target.configset, field.name, value)
|
||||
else
|
||||
target[name] = value
|
||||
end
|
||||
|
||||
-- Odd case: the FatalWarnings flag expands to multiple values now
|
||||
-- (FatalCompileWarnings, FatalLinkWarnings). Generalize this
|
||||
|
@ -5,7 +5,7 @@
|
||||
-- I've had a chance to build it out more before using.
|
||||
--
|
||||
-- A configuration set manages a collection of configuration values, which
|
||||
-- are organized into "blocks". Each block stores a set of field-value pairs,
|
||||
-- are organized into "blocks". Each block stores a set of field-value pairs,
|
||||
-- along with a list of terms which indicate the context in which those
|
||||
-- values should be applied.
|
||||
--
|
||||
@ -35,19 +35,46 @@
|
||||
|
||||
function configset.new(parent)
|
||||
local cset = {}
|
||||
cset._parent = parent or false
|
||||
cset._parent = parent
|
||||
cset._blocks = {}
|
||||
cset._current = false
|
||||
cset._current = nil
|
||||
cset.compiled = false
|
||||
|
||||
-- enable config sets to be treat like plain old tables; storing
|
||||
-- a value will place it into the current block
|
||||
setmetatable(cset, configset.__mt)
|
||||
|
||||
return cset
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- Create and return a metatable which allows a configuration set to act as a
|
||||
-- "backing store" for a regular Lua table. Table operations that access a
|
||||
-- registered field will fetch from or store to the configurations set, while
|
||||
-- unknown keys are get and set to the table normally.
|
||||
---
|
||||
|
||||
function configset.metatable(cset)
|
||||
return {
|
||||
__newindex = function(tbl, key, value)
|
||||
local f = premake.field.get(key)
|
||||
if f then
|
||||
return configset.addvalue(cset, f.name, value)
|
||||
else
|
||||
rawset(tbl, key, value)
|
||||
return value
|
||||
end
|
||||
end,
|
||||
__index = function(tbl, key)
|
||||
local f = premake.field.get(key)
|
||||
if f then
|
||||
return configset.fetchvalue(cset, f.name, cset._current._criteria.terms)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Register a field that requires special handling.
|
||||
--
|
||||
@ -66,7 +93,7 @@
|
||||
configset._fields[name] = behavior
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Create a new block of configuration field-value pairs, with the provided
|
||||
-- set of context terms to control their application.
|
||||
@ -86,10 +113,10 @@
|
||||
function configset.addblock(cset, terms, basedir)
|
||||
local block = {}
|
||||
block._basedir = basedir
|
||||
|
||||
|
||||
-- attach a criteria object to the block to control its application
|
||||
block._criteria = criteria.new(terms)
|
||||
|
||||
|
||||
table.insert(cset._blocks, block)
|
||||
cset._current = block
|
||||
return block
|
||||
@ -195,8 +222,8 @@
|
||||
-- @param cset
|
||||
-- The configuration set to query.
|
||||
-- @param context
|
||||
-- A list of lowercase context terms to use during the fetch. Only those
|
||||
-- blocks with terms fully contained by this list will be considered in
|
||||
-- A list of lowercase context terms to use during the fetch. Only those
|
||||
-- blocks with terms fully contained by this list will be considered in
|
||||
-- determining the returned value. Terms should be lower case to make
|
||||
-- the context filtering case-insensitive.
|
||||
-- @param filename
|
||||
@ -222,7 +249,7 @@
|
||||
table.insert(result._blocks, block)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
result.compiled = true
|
||||
return result
|
||||
end
|
||||
@ -240,14 +267,14 @@
|
||||
for _, v in ipairs(b) do
|
||||
merge(a, v)
|
||||
end
|
||||
|
||||
|
||||
-- if b is a simple value, insert it
|
||||
else
|
||||
-- find and remove earlier values
|
||||
if a[b] then
|
||||
table.remove(a, table.indexof(a, b))
|
||||
end
|
||||
|
||||
|
||||
table.insert(a, b)
|
||||
a[b] = b
|
||||
end
|
||||
@ -268,7 +295,7 @@
|
||||
return block[fieldname]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if cset._parent then
|
||||
return fetchassign(cset._parent, fieldname, context, filename)
|
||||
end
|
||||
@ -280,14 +307,14 @@
|
||||
-- a single result; values may optionally be merged too.
|
||||
--
|
||||
|
||||
local function fetchkeyed(cset, fieldname, context, filename, mergevalues)
|
||||
local function fetchkeyed(cset, fieldname, context, filename, mergevalues)
|
||||
local result = {}
|
||||
|
||||
-- grab values from the parent set first
|
||||
if cset._parent then
|
||||
result = fetchkeyed(cset._parent, fieldname, context, filename, merge)
|
||||
end
|
||||
|
||||
|
||||
function process(values)
|
||||
for k, v in pairs(values) do
|
||||
if type(k) == "number" then
|
||||
@ -347,14 +374,14 @@
|
||||
if block._removes and block._removes[fieldname] then
|
||||
remove(block._removes[fieldname])
|
||||
end
|
||||
|
||||
|
||||
local value = block[fieldname]
|
||||
if value then
|
||||
merge(result, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
@ -368,8 +395,8 @@
|
||||
-- The name of the field to query. The field should have already been
|
||||
-- defined using the api.register() function.
|
||||
-- @param context
|
||||
-- A list of lowercase context terms to use during the fetch. Only those
|
||||
-- blocks with terms fully contained by this list will be considered in
|
||||
-- A list of lowercase context terms to use during the fetch. Only those
|
||||
-- blocks with terms fully contained by this list will be considered in
|
||||
-- determining the returned value. Terms should be lower case to make
|
||||
-- the context filtering case-insensitive.
|
||||
-- @param filename
|
||||
@ -382,37 +409,27 @@
|
||||
function configset.fetchvalue(cset, fieldname, context, filename)
|
||||
local value
|
||||
|
||||
if not context then
|
||||
context = cset._current._criteria.terms
|
||||
end
|
||||
|
||||
-- should this field be merged or assigned?
|
||||
local field = configset._fields[fieldname]
|
||||
local keyed = field and field.keyed
|
||||
local merge = field and field.merge
|
||||
|
||||
|
||||
if keyed then
|
||||
value = fetchkeyed(cset, fieldname, context, filename, merge)
|
||||
elseif merge then
|
||||
value = fetchmerge(cset, fieldname, context, filename)
|
||||
else
|
||||
value = fetchassign(cset, fieldname, context, filename)
|
||||
value = fetchassign(cset, fieldname, context, filename)
|
||||
-- if value is an object, return a copy of it, so that they can
|
||||
-- modified by the caller without altering the source data
|
||||
if type(value) == "table" then
|
||||
value = table.deepcopy(value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Metatable allows configuration sets to be used like objects in the API.
|
||||
-- Setting a value adds it to the currently active block. Getting a value
|
||||
-- retrieves it using the currently active's block list of filter terms.
|
||||
--
|
||||
|
||||
configset.__mt = {
|
||||
__newindex = configset.addvalue,
|
||||
__index = function(cset, fieldname)
|
||||
return configset.fetchvalue(cset, fieldname, cset._current._criteria.terms)
|
||||
end
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
--
|
||||
-- The context also provides caching for the values returned from the set.
|
||||
--
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
-- Copyright (c) 2012-2014 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.context = {}
|
||||
@ -152,10 +152,21 @@
|
||||
--
|
||||
|
||||
function context.fetchvalue(ctx, key)
|
||||
-- The underlying configuration set will only hold registered fields.
|
||||
-- If the requested key doesn't have a corresponding field, it is just
|
||||
-- a regular value to be stored and fetched from the table.
|
||||
|
||||
local field = premake.field.get(key)
|
||||
if not field then
|
||||
return rawget(ctx, key)
|
||||
end
|
||||
|
||||
-- If there is a matching field, then go fetch the aggregated value
|
||||
-- from my configuration set, and then cache it future lookups.
|
||||
|
||||
local value = configset.fetchvalue(ctx._cfgset, key, ctx.terms, ctx._filename[1])
|
||||
if value then
|
||||
-- do I need to expand tokens?
|
||||
local field = premake.fields[key]
|
||||
-- do I need to expand tokens? -- local field = premake.fields[key]
|
||||
if field and field.tokens then
|
||||
local kind = field.kind
|
||||
local ispath = kind:startswith("path") or kind:startswith("file") or kind:startswith("mixed")
|
||||
|
@ -29,18 +29,19 @@
|
||||
prj.solution = sln
|
||||
prj.script = _SCRIPT
|
||||
|
||||
local cset = configset.new(sln.configset)
|
||||
cset.basedir = os.getcwd()
|
||||
cset.filename = name
|
||||
cset.uuid = os.uuid(name)
|
||||
prj.configset = cset
|
||||
-- Start a new configuration set to hold this project's info. For
|
||||
-- convenience and backward compatibility with the old Premake 3.x
|
||||
-- way of doing things, allow the project to be treated like a
|
||||
-- regular table.
|
||||
|
||||
-- attach a type descriptor
|
||||
setmetatable(prj, {
|
||||
__index = function(prj, key)
|
||||
return prj.configset[key]
|
||||
end,
|
||||
})
|
||||
local cset = configset.new(sln.configset)
|
||||
prj.configset = cset
|
||||
setmetatable(prj, configset.metatable(cset))
|
||||
|
||||
-- And set defaults for some of the fields
|
||||
prj.basedir = os.getcwd()
|
||||
prj.filename = name
|
||||
prj.uuid = os.uuid(name)
|
||||
|
||||
return prj
|
||||
end
|
||||
|
@ -1,10 +1,10 @@
|
||||
--
|
||||
-- solution.lua
|
||||
-- Work with the list of solutions loaded from the script.
|
||||
-- Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
-- Copyright (c) 2002-2014 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.solution = { }
|
||||
premake.solution = {}
|
||||
local solution = premake.solution
|
||||
local project = premake.project
|
||||
local configset = premake.configset
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
-- The list of defined solutions (which contain projects, etc.)
|
||||
|
||||
premake.solution.list = {}
|
||||
solution.list = {}
|
||||
|
||||
|
||||
--
|
||||
@ -29,24 +29,25 @@
|
||||
function solution.new(name)
|
||||
local sln = {}
|
||||
|
||||
-- add to master list keyed by both name and index
|
||||
table.insert(premake.solution.list, sln)
|
||||
premake.solution.list[name] = sln
|
||||
|
||||
sln.name = name
|
||||
sln.projects = {}
|
||||
|
||||
local cset = configset.new(configset.root)
|
||||
cset.basedir = os.getcwd()
|
||||
cset.filename = name
|
||||
sln.configset = cset
|
||||
-- Start a new configuration set to hold this project's info. For
|
||||
-- convenience and backward compatibility with the old Premake 3.x
|
||||
-- way of doing things, allow the solution to be treated like a
|
||||
-- regular table.
|
||||
|
||||
-- attach a type descriptor
|
||||
setmetatable(sln, {
|
||||
__index = function(sln, key)
|
||||
return sln.configset[key]
|
||||
end,
|
||||
})
|
||||
local cset = configset.new(configset.root)
|
||||
sln.configset = cset
|
||||
setmetatable(sln, configset.metatable(cset))
|
||||
|
||||
-- Set defaults for some of the fields
|
||||
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
|
||||
|
@ -50,11 +50,6 @@
|
||||
test.isequal(".so", configset.fetchvalue(cset, "targetextension", {}))
|
||||
end
|
||||
|
||||
function suite.canRoundtrip_onDefaultBlock_usingDirectSet()
|
||||
cset.targetextension = ".so"
|
||||
test.isequal(".so", configset.fetchvalue(cset, "targetextension", {}))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that I can roundtrip a value stored into a block
|
||||
@ -67,12 +62,6 @@
|
||||
test.isequal(".dll", configset.fetchvalue(cset, "targetextension", { "windows" }))
|
||||
end
|
||||
|
||||
function suite.canRoundtrip_onSimpleTermMatch_usingDirectGet()
|
||||
configset.addblock(cset, { "Windows" })
|
||||
configset.addvalue(cset, "targetextension", ".dll")
|
||||
test.isequal(".dll", cset.targetextension)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that blocks that do not match the context terms
|
||||
|
@ -1,11 +1,10 @@
|
||||
--
|
||||
-- tests/base/test_context.lua
|
||||
-- Test suite for the configuration context API.
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
-- Copyright (c) 2012-2014 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
T.context = {}
|
||||
local suite = T.context
|
||||
local suite = test.declare("context")
|
||||
|
||||
local context = premake.context
|
||||
local configset = premake.configset
|
||||
@ -15,11 +14,11 @@
|
||||
-- Setup and teardown
|
||||
--
|
||||
|
||||
local ctx, cfgset
|
||||
local ctx, cset
|
||||
|
||||
function suite.setup()
|
||||
cfgset = configset.new()
|
||||
ctx = context.new(cfgset)
|
||||
cset = configset.new()
|
||||
ctx = context.new(cset)
|
||||
end
|
||||
|
||||
|
||||
@ -38,7 +37,7 @@
|
||||
--
|
||||
|
||||
function suite.returnsConfigValue_onExistingValue()
|
||||
cfgset.targetextension = ".so"
|
||||
configset.addvalue(cset, "targetextension", ".so")
|
||||
test.isequal(".so", ctx.targetextension)
|
||||
end
|
||||
|
||||
@ -48,6 +47,6 @@
|
||||
--
|
||||
|
||||
function suite.doesExpandTokens()
|
||||
cfgset.targetname = "MyProject%{1 + 1}"
|
||||
configset.addvalue(cset, "targetname", "MyProject%{1 + 1}")
|
||||
test.isequal("MyProject2", ctx.targetname)
|
||||
end
|
||||
|
Reference in New Issue
Block a user