diff --git a/src/project/oven.lua b/src/project/oven.lua index 67a88563..902d92ec 100755 --- a/src/project/oven.lua +++ b/src/project/oven.lua @@ -16,7 +16,9 @@ local nomerge = { keywords = true, - removes = true + project = true, + removes = true, + solution = true, } @@ -41,14 +43,15 @@ filterTerms = filterTerms or {} -- keyword/term tests are case-insensitive; convert all terms to lowercase + local casedTerms = {} for key, value in pairs(filterTerms) do - filterTerms[key] = value:lower() + casedTerms[key] = value:lower() end -- If I'm baking a project, start with the values from the solution level local cfg if container.solution then - cfg = oven.bake(container.solution, filterTerms, filterField) + cfg = oven.bake(container.solution, casedTerms, filterField) else cfg = {} end @@ -59,13 +62,19 @@ -- Walk the blocks available in this container, and merge their values -- into my configuration-in-progress, if they pass the keyword filter for _, block in ipairs(container.blocks) do - if oven.filter(block, filterTerms) then + if oven.filter(block, casedTerms) then oven.merge(cfg, block, filterField) end end - -- Remember the list of terms used to create this config - cfg.terms = filterTerms + -- Store the filter terms in the configuration (i.e. buildcfg, platform) + cfg.terms = casedTerms + for key, value in pairs(filterTerms) do + cfg[key] = value + end + + -- Expand inline tokens + oven.expandtokens(cfg) return cfg end @@ -104,6 +113,60 @@ end +-- +-- Scan an object for expandable tokens, and expand them, in place. +-- + + function oven.expandtokens(target) + -- build a context for the tokens to use + local context = { + _G = _G, + sln = target.solution, + prj = target.project, + cfg = target + } + + -- function to do the work of replacing the tokens + local expander = function(token) + -- convert the token into a function to execute + local func, err = loadstring("return " .. token) + if not func then + return nil, err + end + + -- give the function access to the project objects + setfenv(func, context) + + -- run it and return the result + local result = func() + if not result then + return nil, "Invalid token '" .. token .. "'" + end + return result + end + + -- scan the object and replace all tokens encountered + for key, value in pairs(target) do + if type(value) == "string" then + + target[key] = string.gsub(value, "%%{(.-)}", function(token) + result, err = expander(token) + if not result then + error(err, 0) + end + return result + end) + + elseif not nomerge[key] then + + -- recurse + + end + end + end + + +-- -- -- Compare a list of block keywords against a set of filter terms. Keywords -- are Lua patterns applied to the block when it is specified in the script @@ -215,6 +278,9 @@ oven.remove(cfg, block.removes, filterField) end + -- remember the container object (solution, project, etc.) + cfg[type(block)] = block + return cfg end diff --git a/src/project/project.lua b/src/project/project.lua index d087968f..5ec1ea03 100755 --- a/src/project/project.lua +++ b/src/project/project.lua @@ -97,6 +97,9 @@ -- function project.getconfig(prj, buildcfg, platform, field, filename) + -- make sure I've got the actual project, and not a baked configuration + prj = prj.project or prj + -- check for a cached version, built by bakeconfigs() if not filename and prj.configs then local key = (buildcfg or "*") .. (platform or "") @@ -114,14 +117,16 @@ end -- Figure out the target operating environment for this configuration - local cfg = premake5.oven.bake(prj, { buildcfg, platform, _ACTION }, "system") - system = cfg.system or system or premake.action.current().os or os.get() + local filter = { + ["buildcfg"] = buildcfg, + ["platform"] = platform, + ["action"] = _ACTION + } + + local cfg = premake5.oven.bake(prj, filter, "system") + filter.system = cfg.system or system or premake.action.current().os or os.get() - cfg = premake5.oven.bake(prj, { buildcfg, platform, _ACTION, system }, field) - cfg.project = prj - cfg.buildcfg = buildcfg - cfg.platform = platform - cfg.system = system + cfg = premake5.oven.bake(prj, filter, field) cfg.architecture = cfg.architecture or architecture return cfg end diff --git a/tests/oven/test_tokens.lua b/tests/oven/test_tokens.lua new file mode 100644 index 00000000..14c974dc --- /dev/null +++ b/tests/oven/test_tokens.lua @@ -0,0 +1,57 @@ +-- +-- tests/oven/test_tokens.lua +-- Test the Premake oven's handling of tokens. +-- Copyright (c) 2012 Jason Perkins and the Premake project +-- + + T.oven_tokens = { } + local suite = T.oven_tokens + local oven = premake5.oven + local project = premake5.project + + +-- +-- Setup and teardown +-- + + local sln, prj, cfg + + function suite.setup() + premake.api.register { + name = "testapi", + kind = "string", + scope = "config", + } + + sln, prj = test.createsolution() + end + + function suite.teardown() + testapi = nil + end + + function prepare() + cfg = project.getconfig(prj, "Debug") + end + + +-- +-- Verify that solution values can be expanded. +-- + + function suite.doesExpandSolutionValues() + testapi "bin/%{sln.name}" + prepare() + test.isequal("bin/MySolution", cfg.testapi) + end + + +-- +-- Verify that multiple values can be expanded. +-- + + function suite.doesExpandMultipleValues() + testapi "bin/%{prj.name}/%{cfg.buildcfg}" + prepare() + test.isequal("bin/MyProject/Debug", cfg.testapi) + end diff --git a/tests/premake4.lua b/tests/premake4.lua index 7b874c7d..0f2e5cff 100644 --- a/tests/premake4.lua +++ b/tests/premake4.lua @@ -89,6 +89,7 @@ dofile("oven/test_lists.lua") dofile("oven/test_objects.lua") dofile("oven/test_removes.lua") + dofile("oven/test_tokens.lua") -- Toolset tests dofile("tools/test_gcc.lua")