Added support for key-value fields to the API

This commit is contained in:
Jason Perkins 2011-06-02 15:26:15 -04:00
parent 52ef4b7079
commit cf3bdb076e
7 changed files with 249 additions and 39 deletions

View File

@ -378,6 +378,13 @@
kind = "list",
scope = "config",
},
vpaths =
{
kind = "keyvalue",
scope = "container",
},
}
@ -530,6 +537,43 @@
end
--
-- Adds values to a key-value field of a solution/project/configuration. `ctype`
-- specifies the container type (see premake.getobject) for the field.
--
function premake.setkeyvalue(ctype, fieldname, value)
local container, err = premake.getobject(ctype)
if not container then
error(err, 4)
end
if not container[fieldname] then
container[fieldname] = { }
end
if type(value) ~= "table" then
error("invalid value; table expected", 4)
end
local result = container[fieldname]
local function doinsert(tbl, errordepth)
for key,value in pairs(tbl) do
if type(value) == "table" then
doinsert(value, errordepth + 1)
elseif type(key) == "string" and type(value) == "string" then
result[key] = value
else
error("invalid value; both key and value must be a string", errordepth)
end
end
end
doinsert(value, 4)
return container[fieldname]
end
--
-- Set a new value for a string field of a solution/project/configuration. `ctype`
@ -567,23 +611,25 @@
local scope = premake.fields[name].scope
local allowed = premake.fields[name].allowed
if ((kind == "string" or kind == "path") and value) then
if (kind == "string" or kind == "path") and value then
if type(value) ~= "string" then
error("string value expected", 3)
end
end
if (kind == "string") then
if kind == "string" then
return premake.setstring(scope, name, value, allowed)
elseif (kind == "path") then
elseif kind == "path" then
if value then value = path.getabsolute(value) end
return premake.setstring(scope, name, value)
elseif (kind == "list") then
elseif kind == "list" then
return premake.setarray(scope, name, value, allowed)
elseif (kind == "dirlist") then
elseif kind == "dirlist" then
return premake.setdirarray(scope, name, value)
elseif (kind == "filelist") then
elseif kind == "filelist" then
return premake.setfilearray(scope, name, value)
elseif kind == "keyvalue" then
return premake.setkeyvalue(scope, name, value)
end
end

View File

@ -142,29 +142,43 @@
-- The source object, containing the settings to added to the destination.
--
local function mergefield(kind, dest, src)
local tbl = dest or { }
if kind == "keyvalue" then
for key, value in pairs(src) do
tbl[key] = value
end
else
for _, item in ipairs(src) do
if not tbl[item] then
table.insert(tbl, item)
tbl[item] = item
end
end
end
return tbl
end
local function mergeobject(dest, src)
if not src then return end
for field, value in pairs(src) do
if not nocopy[field] then
if type(value) == "table" then
-- merge two lists, removing any duplicates along the way
local tbl = dest[field] or { }
if field == 'terms' then
for term_key,term_value in pairs(value)do
tbl[term_key]=term_value
end
-- if there's nothing to add, quick out
if not src then
return
end
for fieldname, value in pairs(src) do
if not nocopy[fieldname] then
-- fields that are included in the API are merged...
local field = premake.fields[fieldname]
if field then
if type(value) == "table" then
dest[fieldname] = mergefield(field.kind, dest[fieldname], value)
else
for _, item in ipairs(value) do
if not tbl[item] then
table.insert(tbl, item)
tbl[item] = item
end
end
dest[fieldname] = value
end
dest[field] = tbl
-- ...everything else is just copied as-is
else
dest[field] = value
dest[fieldname] = value
end
end
end

View File

@ -115,6 +115,27 @@
end
--
-- Adds the key-value associations from one table into another
-- and returns the resulting merged table.
--
function table.merge(...)
local result = { }
for _,t in ipairs(arg) do
if type(t) == "table" then
for k,v in pairs(t) do
result[k] = v
end
else
error("invalid value")
end
end
return result
end
--
-- Translates the values contained in array, using the specified
-- translation table, and returns the results in a new array.

View File

@ -0,0 +1,108 @@
--
-- tests/baking/test_merging.lua
-- Verifies different field types are merged properly during baking.
-- Copyright (c) 2011 Jason Perkins and the Premake project
--
T.baking_merging = { }
local suite = T.baking_merging
--
-- Setup code
--
local sln, prj, cfg
function suite.setup()
sln = solution "MySolution"
configurations { "Debug", "Release" }
end
local function prepare()
premake.bake.buildconfigs()
prj = premake.solution.getproject(sln, 1)
end
--
-- String value tests
--
function suite.Strings_AreReplaced()
kind "SharedLib"
project "MyProject"
kind "StaticLib"
prepare()
test.isequal("StaticLib", prj.kind)
end
function suite.Strings_KeepPreviousValue()
kind "SharedLib"
project "MyProject"
prepare()
test.isequal("SharedLib", prj.kind)
end
--
-- List tests
--
function suite.Lists_KeepPreviousValue()
project "MyProject"
prepare()
test.isequal("Debug:Release", table.concat(prj.configurations, ":"))
end
function suite.Lists_AreJoined()
defines { "SOLUTION" }
project "MyProject"
defines { "PROJECT" }
prepare()
test.isequal("SOLUTION:PROJECT", table.concat(prj.defines, ":"))
end
function suite.Lists_RemoveDuplicates()
defines { "SOLUTION", "DUPLICATE" }
project "MyProject"
defines { "PROJECT", "DUPLICATE" }
prepare()
test.isequal("SOLUTION:DUPLICATE:PROJECT", table.concat(prj.defines, ":"))
end
function suite.Lists_FlattensNestedTables()
defines { "ROOT", { "NESTED" } }
project "MyProject"
prepare()
test.isequal("ROOT:NESTED", table.concat(prj.defines, ":"))
end
--
-- Key/value tests
--
function suite.KeyValue_AreMerged()
vpaths { ["sln"] = "Solution" }
project "MyProject"
vpaths { ["prj"] = "Project" }
prepare()
test.isequal("Solution", prj.vpaths["sln"])
test.isequal("Project", prj.vpaths["prj"])
end
function suite.KeyValue_OverwritesOldValues()
vpaths { ["sln"] = "Solution", ["prj"] = "Solution2" }
project "MyProject"
vpaths { ["prj"] = "Project" }
prepare()
test.isequal("Project", prj.vpaths["prj"])
end
function suite.KeyValue_FlattensNestedTables()
vpaths { ["r"] = "Root", { ["n"] = "Nested" } }
project "MyProject"
prepare()
test.isequal("Root", prj.vpaths["r"])
test.isequal("Nested", prj.vpaths["n"])
end

View File

@ -1,7 +1,7 @@
--
-- tests/base/test_api.lua
-- Automated test suite for the project API support functions.
-- Copyright (c) 2008-2010 Jason Perkins and the Premake project
-- Copyright (c) 2008-2011 Jason Perkins and the Premake project
--
T.api = { }
@ -120,6 +120,36 @@
end
--
-- premake.setkeyvalue() tests
--
function suite.setkeyvalue_InsertsValues_OnTable()
premake.CurrentConfiguration = { }
premake.setkeyvalue("config", "vpaths", { ["*.h"] = "Headers" })
test.isequal("Headers", premake.CurrentConfiguration.vpaths["*.h"])
end
function suite.setkeyvalue_RaisesError_OnString()
premake.CurrentConfiguration = { }
ok, err = pcall(function () premake.setkeyvalue("config", "vpaths", "Headers") end)
test.isfalse(ok)
end
function suite.setkeyvalue_RaisesError_OnNonStringKey()
premake.CurrentConfiguration = { }
ok, err = pcall(function () premake.setkeyvalue("config", "vpaths", { [1] = "Headers" }) end)
test.isfalse(ok)
end
function suite.setkeyvalue_RaisesError_OnNonStringValue()
premake.CurrentConfiguration = { }
ok, err = pcall(function () premake.setkeyvalue("config", "vpaths", { ["*.h"] = 1 }) end)
test.isfalse(ok)
end
--
-- accessor tests
--

View File

@ -57,18 +57,6 @@
-- Tests
--
function suite.SolutionFields()
prepare()
test.isequal("Debug:Release", table.concat(cfg.configurations,":"))
end
function suite.ProjectFields()
prepare()
test.isequal("C", cfg.language)
end
function suite.ProjectWideSettings()
prepare()
test.isequal("SOLUTION:PROJECT:NATIVE", table.concat(prj.defines,":"))

View File

@ -48,7 +48,6 @@
dofile("test_gmake_cs.lua")
dofile("base/test_api.lua")
dofile("base/test_action.lua")
dofile("base/test_baking.lua")
dofile("base/test_config.lua")
dofile("base/test_location.lua")
dofile("base/test_os.lua")
@ -58,6 +57,10 @@
dofile("tools/test_gcc.lua")
dofile("base/test_config_bug.lua")
-- Baking tests
dofile("base/test_baking.lua")
dofile("baking/test_merging.lua")
-- Clean tests
dofile("actions/test_clean.lua")