Merge pull request #554 from Blizzard/add-uncached-subcontext
Add an 'uncached' sub-context to the context.
This commit is contained in:
commit
702d5947b3
@ -53,6 +53,11 @@
|
||||
end
|
||||
|
||||
|
||||
function m.getRule(name)
|
||||
p.oven.bake()
|
||||
return p.global.getRule(name)
|
||||
end
|
||||
|
||||
|
||||
function m.getProject(wks, i)
|
||||
wks = m.getWorkspace(wks)
|
||||
|
@ -31,6 +31,7 @@
|
||||
["file.basename"] = { absolute = false, token = "%(Filename)" },
|
||||
["file.abspath"] = { absolute = true, token = "%(FullPath)" },
|
||||
["file.relpath"] = { absolute = false, token = "%(Identity)" },
|
||||
["file.path"] = { absolute = true, token = "%(RelativeDir)" },
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,7 +84,6 @@
|
||||
return {
|
||||
m.propertyDefaults,
|
||||
m.commandLineTemplates,
|
||||
m.outputs,
|
||||
m.executionDescription,
|
||||
m.additionalDependencies,
|
||||
}
|
||||
@ -144,10 +143,18 @@
|
||||
|
||||
|
||||
function m.commandLineTemplates(r)
|
||||
if #r.buildcommands then
|
||||
local cmds = os.translateCommands(r.buildcommands, p.WINDOWS)
|
||||
-- create shadow context.
|
||||
local env = p.rule.createEnvironment(r, "[%s]")
|
||||
local ctx = p.context.extent(r, env)
|
||||
|
||||
-- now use the shadow context to detoken.
|
||||
local buildcommands = ctx.buildcommands
|
||||
|
||||
-- write out the result.
|
||||
if buildcommands and #buildcommands > 0 then
|
||||
local cmds = os.translateCommands(buildcommands, p.WINDOWS)
|
||||
cmds = table.concat(cmds, p.eol())
|
||||
p.x('<CommandLineTemplate>%s</CommandLineTemplate>', cmds)
|
||||
p.x('<CommandLineTemplate>@echo off\n%s</CommandLineTemplate>', cmds)
|
||||
end
|
||||
end
|
||||
|
||||
@ -162,16 +169,16 @@
|
||||
|
||||
|
||||
function m.executionDescription(r)
|
||||
if r.buildmessage then
|
||||
p.x('<ExecutionDescription>%s</ExecutionDescription>', r.buildmessage)
|
||||
-- create shadow context.
|
||||
local env = p.rule.createEnvironment(r, "%%(%s)")
|
||||
local ctx = p.context.extent(r, env)
|
||||
|
||||
-- now use the shadow context to detoken.
|
||||
local buildmessage = ctx.buildmessage
|
||||
|
||||
-- write out the result.
|
||||
if buildmessage and #buildmessage > 0 then
|
||||
p.x('<ExecutionDescription>%s</ExecutionDescription>', buildmessage)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.outputs(r)
|
||||
if #r.buildoutputs then
|
||||
local outputs = table.concat(r.buildoutputs, ";")
|
||||
p.x('<Outputs>%s</Outputs>', path.translate(outputs))
|
||||
end
|
||||
end
|
||||
|
@ -20,6 +20,7 @@
|
||||
return {
|
||||
p.vstudio.projectElement,
|
||||
m.availableItemGroup,
|
||||
m.computedProperties,
|
||||
m.computeInputsGroup,
|
||||
m.usingTask,
|
||||
m.ruleTarget,
|
||||
@ -54,6 +55,29 @@
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- Generate the computed outputs property.
|
||||
---
|
||||
function m.computedProperties(r)
|
||||
-- create shadow context.
|
||||
local pathVars = p.rule.createPathVars(r, "%%(%s)")
|
||||
local ctx = p.context.extent(r, { pathVars = pathVars })
|
||||
|
||||
-- now use the shadow context to detoken.
|
||||
local buildoutputs = ctx.buildoutputs
|
||||
|
||||
-- write the output.
|
||||
if buildoutputs and #buildoutputs > 0 then
|
||||
local outputs = table.concat(buildoutputs, ";")
|
||||
p.push('<ItemDefinitionGroup>')
|
||||
p.push('<%s>', r.name)
|
||||
p.x('<Outputs>%s</Outputs>', path.translate(outputs))
|
||||
p.pop('</%s>', r.name)
|
||||
p.pop('</ItemDefinitionGroup>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Generate the computed input targets group.
|
||||
@ -277,12 +301,19 @@
|
||||
|
||||
|
||||
function m.linkLib(r)
|
||||
-- create shadow context.
|
||||
local pathVars = p.rule.createPathVars(r, "%%(%s)")
|
||||
local ctx = p.context.extent(r, { pathVars = pathVars })
|
||||
|
||||
-- now use the shadow context to detoken.
|
||||
local buildoutputs = ctx.buildoutputs
|
||||
|
||||
local linkable, compileable
|
||||
for i = 1, #r.buildoutputs do
|
||||
if (path.islinkable(r.buildoutputs[i])) then
|
||||
for i = 1, #buildoutputs do
|
||||
if (path.islinkable(buildoutputs[i])) then
|
||||
linkable = true
|
||||
end
|
||||
if (path.iscppfile(r.buildoutputs[i])) then
|
||||
if (path.iscppfile(buildoutputs[i])) then
|
||||
compileable = true
|
||||
end
|
||||
end
|
||||
@ -314,7 +345,7 @@
|
||||
p.w('<Message')
|
||||
p.w(' Importance="High"')
|
||||
p.w(' Text="%%(%s.ExecutionDescription)" />', r.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
@ -326,13 +357,13 @@
|
||||
|
||||
|
||||
|
||||
function m.properties(r)
|
||||
function m.properties(r)
|
||||
local defs = r.propertydefinition
|
||||
for i = 1, #defs do
|
||||
local name = defs[i].name
|
||||
p.w('%s="%%(%s.%s)"', name, r.name, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
@ -59,6 +59,31 @@
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Create an extended and uncached context based on another context object.
|
||||
--
|
||||
-- @param baseContext
|
||||
-- The base context to extent
|
||||
-- @param newEnvVars
|
||||
-- An optional key-value environment table for token expansion; keys and
|
||||
-- values provided in this table will be available for tokens to use.
|
||||
-- @return
|
||||
-- A new context object.
|
||||
--
|
||||
|
||||
function context.extent(baseContext, newEnvVars)
|
||||
local ctx = {}
|
||||
ctx._ctx = baseContext
|
||||
ctx.environ = newEnvVars or baseContext.environ
|
||||
ctx.terms = {}
|
||||
ctx._basedir = baseContext._basedir
|
||||
|
||||
setmetatable(ctx, context.__mt_uncached)
|
||||
|
||||
return ctx
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Add a new key-value pair to refine the context filtering.
|
||||
@ -204,7 +229,7 @@
|
||||
local value = configset.fetch(ctx._cfgset, field, ctx.terms, ctx, onlylocal and ctx._cfgset)
|
||||
if value then
|
||||
-- store the result for later lookups
|
||||
ctx[key] = value
|
||||
rawset(ctx, key, value)
|
||||
end
|
||||
|
||||
return value
|
||||
@ -214,3 +239,14 @@
|
||||
__index = context.fetchvalue
|
||||
}
|
||||
|
||||
context.__mt_uncached = {
|
||||
__index = function(ctx, key)
|
||||
local field = p.field.get(key)
|
||||
if not field then
|
||||
return nil
|
||||
end
|
||||
local parent = rawget(ctx, '_ctx')
|
||||
return configset.fetch(parent._cfgset, field, ctx.terms, ctx, nil)
|
||||
end
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,9 @@
|
||||
end
|
||||
end
|
||||
|
||||
-- fetch the pathVars from the enviroment.
|
||||
local envMap = environ.pathVars or {}
|
||||
|
||||
-- enable access to the global environment
|
||||
setmetatable(environ, {__index = _G})
|
||||
|
||||
@ -79,14 +82,14 @@
|
||||
end
|
||||
end
|
||||
|
||||
-- If this token is in my path variable mapping table, replace the
|
||||
-- If this token is in my path variable mapping tables, replace the
|
||||
-- value with the one from the map. This needs to go here because
|
||||
-- I don't want to make the result relative, but I don't want the
|
||||
-- absolute path handling below.
|
||||
|
||||
if varMap[token] then
|
||||
local mapped = envMap[token] or varMap[token]
|
||||
if mapped then
|
||||
err = nil
|
||||
result = varMap[token]
|
||||
result = mapped
|
||||
if type(result) == "function" then
|
||||
success, result = pcall(result, e)
|
||||
if not success then
|
||||
|
@ -159,3 +159,51 @@
|
||||
p.api.storeField(fld, value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- prepare an environment with the rule properties as global tokens,
|
||||
-- according to the format specified.
|
||||
--
|
||||
-- @param environ
|
||||
-- The environment table to fill up
|
||||
-- @param format
|
||||
-- The formatting to be used, ie "[%s]".
|
||||
---
|
||||
|
||||
function rule.prepareEnvironment(self, environ, format)
|
||||
for _, def in ipairs(self.propertydefinition) do
|
||||
environ[def.name] = string.format(format, def.name)
|
||||
end
|
||||
end
|
||||
|
||||
function rule.createEnvironment(self, format)
|
||||
local environ = {}
|
||||
rule.prepareEnvironment(self, environ, format)
|
||||
return environ
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- prepare an table of pathVars with the rule properties as global tokens,
|
||||
-- according to the format specified.
|
||||
--
|
||||
-- @param pathVars
|
||||
-- The pathVars table to fill up
|
||||
-- @param format
|
||||
-- The formatting to be used, ie "%%(%s)".
|
||||
---
|
||||
|
||||
function rule.preparePathVars(self, pathVars, format)
|
||||
for _, def in ipairs(self.propertydefinition) do
|
||||
pathVars[def.name] = { absolute = true, token = string.format(format, def.name) }
|
||||
end
|
||||
end
|
||||
|
||||
function rule.createPathVars(self, format)
|
||||
local pathVars = {}
|
||||
rule.preparePathVars(self, pathVars, format)
|
||||
return pathVars
|
||||
end
|
||||
|
@ -131,6 +131,8 @@ return {
|
||||
"actions/vstudio/vc2010/test_project_refs.lua",
|
||||
"actions/vstudio/vc2010/test_prop_sheet.lua",
|
||||
"actions/vstudio/vc2010/test_resource_compile.lua",
|
||||
"actions/vstudio/vc2010/test_rule_props.lua",
|
||||
"actions/vstudio/vc2010/test_rule_targets.lua",
|
||||
"actions/vstudio/vc2010/test_rule_vars.lua",
|
||||
"actions/vstudio/vc2010/test_target_machine.lua",
|
||||
"actions/vstudio/vc2010/test_user_file.lua",
|
||||
|
71
tests/actions/vstudio/vc2010/test_rule_props.lua
Normal file
71
tests/actions/vstudio/vc2010/test_rule_props.lua
Normal file
@ -0,0 +1,71 @@
|
||||
--
|
||||
-- tests/actions/vstudio/vc2010/vstudio_vs2010_rule_props.lua
|
||||
-- Validate generation of custom rules
|
||||
-- Author Tom van Dijck
|
||||
-- Copyright (c) 2016 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
local suite = test.declare("vstudio_vs2010_rule_props")
|
||||
|
||||
local vc2010 = premake.vstudio.vc2010
|
||||
local m = premake.vstudio.vs2010.rules.props
|
||||
|
||||
|
||||
--
|
||||
-- Setup
|
||||
--
|
||||
|
||||
local wks, prj
|
||||
|
||||
function suite.setup()
|
||||
premake.action.set("vs2010")
|
||||
rule 'example'
|
||||
display 'Example compiler'
|
||||
fileExtension '.example'
|
||||
|
||||
propertydefinition {
|
||||
name = "output_path",
|
||||
kind = "string",
|
||||
display = "Output Path",
|
||||
description = "",
|
||||
}
|
||||
|
||||
buildmessage 'Compiling %{file.basename} with example-compiler...'
|
||||
buildcommands {
|
||||
'package-example-compiler.exe %{output_path} "%{file.relpath}"'
|
||||
}
|
||||
buildoutputs {
|
||||
'%{output_path}%{file.basename}.example.cc',
|
||||
'%{output_path}%{file.basename}.example.h'
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- commandLineTemplates
|
||||
--
|
||||
|
||||
function suite.commandLineTemplates()
|
||||
local r = test.getRule("example")
|
||||
m.commandLineTemplates(r)
|
||||
|
||||
test.capture [[
|
||||
<CommandLineTemplate>@echo off
|
||||
package-example-compiler.exe [output_path] "%(Identity)"</CommandLineTemplate>
|
||||
]]
|
||||
end
|
||||
|
||||
--
|
||||
-- executionDescription
|
||||
--
|
||||
|
||||
function suite.executionDescription()
|
||||
local r = test.getRule("example")
|
||||
m.executionDescription(r)
|
||||
|
||||
test.capture [[
|
||||
<ExecutionDescription>Compiling %(Filename) with example-compiler...</ExecutionDescription>
|
||||
]]
|
||||
end
|
||||
|
97
tests/actions/vstudio/vc2010/test_rule_targets.lua
Normal file
97
tests/actions/vstudio/vc2010/test_rule_targets.lua
Normal file
@ -0,0 +1,97 @@
|
||||
--
|
||||
-- tests/actions/vstudio/vc2010/vstudio_vs2010_rule_targets.lua
|
||||
-- Validate generation of custom rules
|
||||
-- Author Tom van Dijck
|
||||
-- Copyright (c) 2016 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
local suite = test.declare("vstudio_vs2010_rule_targets")
|
||||
|
||||
local vc2010 = premake.vstudio.vc2010
|
||||
local m = premake.vstudio.vs2010.rules.targets
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Setup
|
||||
--
|
||||
|
||||
local wks, prj
|
||||
|
||||
function suite.setup()
|
||||
premake.action.set("vs2010")
|
||||
rule 'example'
|
||||
display 'Example compiler'
|
||||
fileExtension '.example'
|
||||
|
||||
propertydefinition {
|
||||
name = "output_path",
|
||||
kind = "string",
|
||||
display = "Output Path",
|
||||
description = "",
|
||||
}
|
||||
|
||||
buildmessage 'Compiling %{file.basename} with example-compiler...'
|
||||
buildcommands {
|
||||
'package-example-compiler.exe %{output_path} "%{file.relpath}"'
|
||||
}
|
||||
buildoutputs {
|
||||
'%{output_path}%{file.basename}.example.cc',
|
||||
'%{output_path}%{file.basename}.example.h'
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- availableItemName
|
||||
--
|
||||
|
||||
function suite.availableItemName()
|
||||
local r = test.getRule("example")
|
||||
m.availableItemName(r)
|
||||
|
||||
test.capture [[
|
||||
<AvailableItemName Include="example">
|
||||
<Targets>_example</Targets>
|
||||
</AvailableItemName>
|
||||
]]
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- computedProperties
|
||||
--
|
||||
|
||||
function suite.computedProperties()
|
||||
local r = test.getRule("example")
|
||||
m.computedProperties(r)
|
||||
|
||||
test.capture [[
|
||||
<ItemDefinitionGroup>
|
||||
<example>
|
||||
<Outputs>%(output_path)%(Filename).example.cc;%(output_path)%(Filename).example.h</Outputs>
|
||||
</example>
|
||||
</ItemDefinitionGroup>
|
||||
]]
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- usingTask
|
||||
--
|
||||
|
||||
function suite.usingTask()
|
||||
local r = test.getRule("example")
|
||||
m.usingTask(r)
|
||||
|
||||
test.capture [[
|
||||
<UsingTask
|
||||
TaskName="example"
|
||||
TaskFactory="XamlTaskFactory"
|
||||
AssemblyName="Microsoft.Build.Tasks.v4.0">
|
||||
<Task>$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml</Task>
|
||||
</UsingTask>
|
||||
]]
|
||||
end
|
@ -51,3 +51,25 @@
|
||||
configset.store(cset, field.get("targetname"), "MyProject%{1 + 1}")
|
||||
test.isequal("MyProject2", ctx.targetname)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Token environment in extended context overrides context.
|
||||
--
|
||||
|
||||
function suite.extent()
|
||||
-- set in toplevel context.
|
||||
configset.store(cset, field.get("targetname"), "%{value}")
|
||||
|
||||
-- detoken in toplevel context should result in empty string.
|
||||
test.isequal("", ctx.targetname)
|
||||
|
||||
-- create an extended context with a local environ.
|
||||
local environ = {
|
||||
value = "text"
|
||||
}
|
||||
local ext = context.extent(ctx, environ)
|
||||
|
||||
-- detoken in extended context should result in value set in that environ.
|
||||
test.isequal("text", ext.targetname)
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user