Fixes for key-array and the new api.register() path
This commit is contained in:
parent
86984a87de
commit
8e326ff6f1
285
src/base/api.lua
285
src/base/api.lua
@ -8,126 +8,6 @@
|
||||
local api = premake.api
|
||||
|
||||
|
||||
--
|
||||
-- A place to store the current active objects in each project scope.
|
||||
--
|
||||
|
||||
api.scope = {}
|
||||
|
||||
|
||||
--
|
||||
-- Register a new API function. See the built-in API definitions below
|
||||
-- for usage examples.
|
||||
--
|
||||
|
||||
function api.register(field)
|
||||
-- verify the name
|
||||
local name = field.name
|
||||
if not name then
|
||||
error("missing name", 2)
|
||||
end
|
||||
|
||||
if _G[name] then
|
||||
error("name in use", 2)
|
||||
end
|
||||
|
||||
-- make sure there is a handler available for this kind of value
|
||||
local kind = field.kind
|
||||
if kind:startswith("key-") then
|
||||
kind = kind:sub(5)
|
||||
end
|
||||
|
||||
if not api["set" .. kind] then
|
||||
error("invalid kind '" .. kind .. "'", 2)
|
||||
end
|
||||
|
||||
_G[name] = function(value)
|
||||
return api.callback(field, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Callback for all API functions; everything comes here first, and then
|
||||
-- parceled out to the individual set...() functions.
|
||||
--
|
||||
|
||||
function api.callback(field, value)
|
||||
-- find the right target object for this field
|
||||
local target
|
||||
if field.scope == "project" then
|
||||
target = api.scope.project or api.scope.solution
|
||||
else
|
||||
target = api.scope.configuration
|
||||
end
|
||||
|
||||
if not target then
|
||||
error("no " .. field.scope .. " in scope", 3)
|
||||
end
|
||||
|
||||
-- A keyed value is a table containing key-value pairs, where the
|
||||
-- type of the value is defined by the field.
|
||||
if field.kind:startswith("key-") then
|
||||
target[field.name] = target[field.name] or {}
|
||||
api.setkeyvalue(target[field.name], field, value)
|
||||
|
||||
-- Otherwise, it is a "simple" value defined by the field
|
||||
else
|
||||
local setter = api["set" .. field.kind]
|
||||
setter(target, field.name, field, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Update a keyed value. Iterate over the keys in the new value, and use
|
||||
-- the corresponding values to update the target object.
|
||||
--
|
||||
|
||||
function api.setkeyvalue(target, field, values)
|
||||
if type(values) ~= "table" then
|
||||
error("value must be a table of key-value pairs", 4)
|
||||
end
|
||||
|
||||
local kind = field.kind:sub(5)
|
||||
local setter = api["set" .. kind]
|
||||
for key, value in pairs(values) do
|
||||
setter(target, key, field, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Set a new array value. Arrays are lists of values stored by "value",
|
||||
-- in that new values overwrite old ones, rather than merging like lists.
|
||||
--
|
||||
|
||||
function api.setarray(target, name, field, value)
|
||||
-- put simple values in an array
|
||||
if type(value) ~= "table" then
|
||||
value = { value }
|
||||
end
|
||||
|
||||
-- store it, overwriting any existing value
|
||||
target[field.name] = value
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Set a new string value on an API field.
|
||||
--
|
||||
|
||||
function api.setstring(target, name, field, value)
|
||||
error("setstring is not yet implemented")
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Everything below this point is a candidate for deprecation
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
--
|
||||
-- Here I define all of the getter/setter functions as metadata. The actual
|
||||
-- functions are built programmatically below.
|
||||
@ -554,13 +434,150 @@
|
||||
|
||||
vpaths =
|
||||
{
|
||||
kind = "keypath",
|
||||
kind = "key-pathlist",
|
||||
scope = "container",
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- A place to store the current active objects in each project scope.
|
||||
--
|
||||
|
||||
api.scope = {}
|
||||
|
||||
|
||||
--
|
||||
-- Register a new API function. See the built-in API definitions below
|
||||
-- for usage examples.
|
||||
--
|
||||
|
||||
function api.register(field)
|
||||
-- verify the name
|
||||
local name = field.name
|
||||
if not name then
|
||||
error("missing name", 2)
|
||||
end
|
||||
|
||||
if _G[name] then
|
||||
error("name in use", 2)
|
||||
end
|
||||
|
||||
-- make sure there is a handler available for this kind of value
|
||||
local kind = field.kind
|
||||
if kind:startswith("key-") then
|
||||
kind = kind:sub(5)
|
||||
end
|
||||
|
||||
if not api["set" .. kind] then
|
||||
error("invalid kind '" .. kind .. "'", 2)
|
||||
end
|
||||
|
||||
-- add this new field to my master list
|
||||
premake.fields[field.name] = field
|
||||
|
||||
-- add create a setter function for it
|
||||
_G[name] = function(value)
|
||||
return api.callback(field, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Callback for all API functions; everything comes here first, and then
|
||||
-- parceled out to the individual set...() functions.
|
||||
--
|
||||
|
||||
function api.callback(field, value)
|
||||
-- find the right target object for this field
|
||||
local target
|
||||
if field.scope == "project" then
|
||||
target = api.scope.project or api.scope.solution
|
||||
else
|
||||
target = api.scope.configuration
|
||||
end
|
||||
|
||||
if not target then
|
||||
error("no " .. field.scope .. " in scope", 3)
|
||||
end
|
||||
|
||||
-- A keyed value is a table containing key-value pairs, where the
|
||||
-- type of the value is defined by the field.
|
||||
if field.kind:startswith("key-") then
|
||||
target[field.name] = target[field.name] or {}
|
||||
api.setkeyvalue(target[field.name], field, value)
|
||||
|
||||
-- Otherwise, it is a "simple" value defined by the field
|
||||
else
|
||||
local setter = api["set" .. field.kind]
|
||||
setter(target, field.name, field, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Update a keyed value. Iterate over the keys in the new value, and use
|
||||
-- the corresponding values to update the target object.
|
||||
--
|
||||
|
||||
function api.setkeyvalue(target, field, values)
|
||||
if type(values) ~= "table" then
|
||||
error("value must be a table of key-value pairs", 4)
|
||||
end
|
||||
|
||||
local kind = field.kind:sub(5)
|
||||
local setter = api["set" .. kind]
|
||||
for key, value in pairs(values) do
|
||||
setter(target, key, field, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Set a new array value. Arrays are lists of values stored by "value",
|
||||
-- in that new values overwrite old ones, rather than merging like lists.
|
||||
--
|
||||
|
||||
function api.setarray(target, name, field, value)
|
||||
-- put simple values in an array
|
||||
if type(value) ~= "table" then
|
||||
value = { value }
|
||||
end
|
||||
|
||||
-- store it, overwriting any existing value
|
||||
target[name] = value
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Set a new string value on an API field.
|
||||
--
|
||||
|
||||
function api.setstring(target, name, field, value)
|
||||
error("setstring is not yet implemented")
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Register the core API functions.
|
||||
--
|
||||
|
||||
api.register {
|
||||
name = "configmaps",
|
||||
scope = "project",
|
||||
kind = "key-array"
|
||||
}
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Everything below this point is a candidate for deprecation
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
--
|
||||
-- Check to see if a value exists in a list of values, using a
|
||||
-- case-insensitive match. If the value does exist, the canonical
|
||||
@ -835,7 +852,7 @@
|
||||
return premake.setdirarray(container, name, value)
|
||||
elseif kind == "filelist" then
|
||||
return premake.setfilearray(container, name, value)
|
||||
elseif kind == "keyvalue" or kind == "keypath" then
|
||||
elseif kind == "key-value" or kind == "key-pathlist" then
|
||||
return premake.setkeyvalue(scope, name, value)
|
||||
elseif kind == "object" then
|
||||
return premake.setobject(container, name, value)
|
||||
@ -871,17 +888,20 @@
|
||||
--
|
||||
|
||||
for name, info in pairs(premake.fields) do
|
||||
_G[name] = function(value)
|
||||
return accessor(name, value)
|
||||
end
|
||||
-- skip my new register() fields
|
||||
if not info.name then
|
||||
_G[name] = function(value)
|
||||
return accessor(name, value)
|
||||
end
|
||||
|
||||
-- list value types get a remove() call too
|
||||
if info.kind == "list" or
|
||||
info.kind == "dirlist" or
|
||||
info.kind == "filelist"
|
||||
then
|
||||
_G["remove"..name] = function(value)
|
||||
premake.remove(name, value)
|
||||
-- list value types get a remove() call too
|
||||
if info.kind == "list" or
|
||||
info.kind == "dirlist" or
|
||||
info.kind == "filelist"
|
||||
then
|
||||
_G["remove"..name] = function(value)
|
||||
premake.remove(name, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -932,7 +952,6 @@
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- this is the new place for storing scoped objects
|
||||
api.scope.configuration = cfg
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
-- down into one object per configuration. These objects are cached with the
|
||||
-- project, and can be retrieved by calling the getconfig() or eachconfig().
|
||||
--
|
||||
-- Copyright (c) 2008-2011 Jason Perkins and the Premake project
|
||||
-- Copyright (c) 2008-2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.bake = { }
|
||||
@ -159,7 +159,7 @@
|
||||
|
||||
local function mergefield(kind, dest, src)
|
||||
local tbl = dest or { }
|
||||
if kind == "keyvalue" or kind == "keypath" then
|
||||
if kind == "key-value" or kind == "key-pathlist" then
|
||||
for key, value in pairs(src) do
|
||||
tbl[key] = mergefield("list", tbl[key], value)
|
||||
end
|
||||
|
@ -257,18 +257,27 @@
|
||||
--
|
||||
|
||||
function oven.mergefield(cfg, name, value)
|
||||
-- is this field part of the Premake API? If no, just copy and done
|
||||
local field = premake.fields[name]
|
||||
|
||||
-- if this isn't a Premake field, then just copy
|
||||
if not field then
|
||||
cfg[name] = value
|
||||
return
|
||||
end
|
||||
|
||||
if field.kind == "keyvalue" or field.kind == "keypath" then
|
||||
if field.kind:startswith("key-") then
|
||||
oven.mergekeyvalue(cfg, name, field.kind, value)
|
||||
else
|
||||
oven.mergevalue(cfg, name, field.kind, value)
|
||||
end
|
||||
|
||||
--[[
|
||||
if field.kind:startswith("key-") then
|
||||
cfg[name] = cfg[name] or {}
|
||||
for key, keyvalue in pairs(value) do
|
||||
cfg[name][key] = oven.mergetables(cfg[name][key] or {}, keyvalue)
|
||||
end
|
||||
|
||||
elseif field.kind == "object" then
|
||||
cfg[name] = value
|
||||
elseif type(value) == "table" then
|
||||
@ -276,13 +285,61 @@
|
||||
else
|
||||
cfg[name] = value
|
||||
end
|
||||
--]]
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Merge the values of one table into another.
|
||||
-- Merge a collection of key-values into an baked configuration.
|
||||
-- @param target
|
||||
-- The object receiving the values.
|
||||
-- @param fieldname
|
||||
-- The name of the field being set.
|
||||
-- @param fieldkind
|
||||
-- The data type of the field.
|
||||
-- @param values
|
||||
-- The object containing the key-value pairs.
|
||||
--
|
||||
-- @param original
|
||||
|
||||
function oven.mergekeyvalue(target, fieldname, fieldkind, values)
|
||||
-- make sure I've got an object to hold the key-value pairs
|
||||
target[fieldname] = target[fieldname] or {}
|
||||
|
||||
-- get the data type of the values (remove the "key-" part)
|
||||
fieldkind = fieldkind:sub(5)
|
||||
|
||||
-- merge in the values
|
||||
for key, value in pairs(values) do
|
||||
oven.mergevalue(target[fieldname], key, fieldkind, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Copy, and optionally merge, a value into a baked configuration.
|
||||
-- @param target
|
||||
-- The object receiving the values.
|
||||
-- @param fieldname
|
||||
-- The name of the field being set.
|
||||
-- @param fieldkind
|
||||
-- The data type of the field.
|
||||
-- @param values
|
||||
-- The object containing the key-value pairs.
|
||||
--
|
||||
|
||||
function oven.mergevalue(target, fieldname, fieldkind, value)
|
||||
-- list values get merged, others overwrite
|
||||
if fieldkind:endswith("list") then
|
||||
target[fieldname] = oven.mergetables(target[fieldname] or {}, value)
|
||||
else
|
||||
target[fieldname] = value
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Merge a collection of key-values into an baked configuration.
|
||||
-- @param target
|
||||
-- The original value of the table being merged into.
|
||||
-- @param additions
|
||||
-- The new values to add to the table.
|
||||
|
@ -106,7 +106,7 @@
|
||||
--
|
||||
|
||||
function project.getconfig(prj, buildcfg, platform, field, filename)
|
||||
-- check for a cached version, build by bakeconfigs()
|
||||
-- check for a cached version, built by bakeconfigs()
|
||||
if not filename and prj.configs then
|
||||
local key = (buildcfg or "*") .. (platform or "")
|
||||
return prj.configs[key]
|
||||
|
@ -99,3 +99,21 @@
|
||||
EndGlobalSection
|
||||
]]
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Verify that solution-project configuration maps are correctly applied.
|
||||
--
|
||||
|
||||
function suite.configIsMapped_onProjectConfigMapping()
|
||||
configmaps { ["Debug"] = "Development" }
|
||||
prepare()
|
||||
test.capture [[
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C9135098-6047-8142-B10E-D27E7F73FCB3}.Debug|Win32.ActiveCfg = Development|Win32
|
||||
{C9135098-6047-8142-B10E-D27E7F73FCB3}.Debug|Win32.Build.0 = Development|Win32
|
||||
{C9135098-6047-8142-B10E-D27E7F73FCB3}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{C9135098-6047-8142-B10E-D27E7F73FCB3}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
]]
|
||||
end
|
||||
|
@ -42,3 +42,13 @@
|
||||
test.isequal({ "myvalue" }, api.scope.project.testapi)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- New values should overwrite old.
|
||||
--
|
||||
|
||||
function suite.overwrites_onNewValue()
|
||||
testapi "first"
|
||||
testapi "second"
|
||||
test.isequal({ "second" }, api.scope.project.testapi)
|
||||
end
|
||||
|
45
tests/oven/test_keyvalues.lua
Normal file
45
tests/oven/test_keyvalues.lua
Normal file
@ -0,0 +1,45 @@
|
||||
--
|
||||
-- tests/oven/test_keyvalues.lua
|
||||
-- Test the handling of key-value data types in the oven.
|
||||
-- Copyright (c) 2011-2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
T.oven_keyvalues = { }
|
||||
local suite = T.oven_keyvalues
|
||||
local oven = premake5.oven
|
||||
|
||||
|
||||
--
|
||||
-- Setup and teardown
|
||||
--
|
||||
|
||||
local sln, prj
|
||||
|
||||
function suite.setup()
|
||||
sln = solution("MySolution")
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that key-value types show up in the baked result.
|
||||
--
|
||||
|
||||
function suite.valuePresentInResult()
|
||||
configmaps { ["key"] = "value" }
|
||||
local cfg = oven.merge({}, sln)
|
||||
test.isequal("value", cfg.configmaps["key"][1])
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- When multiple key-value blocks are present, the resulting keys
|
||||
-- should be merged into a single result.
|
||||
--
|
||||
|
||||
function suite.keysMerged_onMultipleValues()
|
||||
configmaps { ["sln"] = "slnvalue" }
|
||||
prj = project("MyProject")
|
||||
configmaps { ["prj"] = "prjvalue" }
|
||||
local cfg = oven.merge(oven.merge({}, sln), prj)
|
||||
test.istrue(cfg.configmaps.sln ~= nil and cfg.configmaps.prj ~= nil)
|
||||
end
|
@ -82,6 +82,7 @@
|
||||
|
||||
-- Baking tests
|
||||
dofile("base/test_baking.lua")
|
||||
dofile("oven/test_keyvalues.lua")
|
||||
|
||||
-- Toolset tests
|
||||
dofile("tools/test_gcc.lua")
|
||||
|
Loading…
Reference in New Issue
Block a user