From 0cfcbd66ca6311e6fa17102d78ea639a02800729 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Mon, 2 Mar 2020 01:20:32 -0800 Subject: [PATCH] execute_command in powershell wasn't interpolating build vars properly (#8771) --- template/interpolate/funcs.go | 69 +++++++++++++++++------------- template/interpolate/funcs_test.go | 7 +++ 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/template/interpolate/funcs.go b/template/interpolate/funcs.go index 9dcd5061d..1a5daf192 100644 --- a/template/interpolate/funcs.go +++ b/template/interpolate/funcs.go @@ -164,41 +164,50 @@ func funcGenTemplateDir(ctx *Context) interface{} { } } +func passthroughOrInterpolate(data map[interface{}]interface{}, s string) (string, error) { + if heldPlace, ok := data[s]; ok { + if hp, ok := heldPlace.(string); ok { + // If we're in the first interpolation pass, the goal is to + // make sure that we pass the value through. + // TODO match against an actual string constant + if strings.Contains(hp, common.PlaceholderMsg) { + return fmt.Sprintf("{{.%s}}", s), nil + } else { + return hp, nil + } + } + } + return "", fmt.Errorf("loaded data, but couldnt find %s in it.", s) + +} func funcGenBuild(ctx *Context) interface{} { + // Depending on where the context data is coming from, it could take a few + // different map types. The following switch standardizes the map types + // so we can act on them correctly. return func(s string) (string, error) { - if data, ok := ctx.Data.(map[string]string); ok { - if heldPlace, ok := data[s]; ok { - // If we're in the first interpolation pass, the goal is to - // make sure that we pass the value through. - // TODO match against an actual string constant - if strings.Contains(heldPlace, common.PlaceholderMsg) { - return fmt.Sprintf("{{.%s}}", s), nil - } else { - return heldPlace, nil - } + switch data := ctx.Data.(type) { + case map[interface{}]interface{}: + return passthroughOrInterpolate(data, s) + case map[string]interface{}: + // convert to a map[interface{}]interface{} so we can use same + // parsing on it + passed := make(map[interface{}]interface{}, len(data)) + for k, v := range data { + passed[k] = v } - return "", fmt.Errorf("loaded data, but couldnt find %s in it.", s) - } - if data, ok := ctx.Data.(map[interface{}]interface{}); ok { - // PlaceholderData has been passed into generator, so if the given - // key already exists in data, then we know it's an "allowed" key - if heldPlace, ok := data[s]; ok { - if hp, ok := heldPlace.(string); ok { - // If we're in the first interpolation pass, the goal is to - // make sure that we pass the value through. - // TODO match against an actual string constant - if strings.Contains(hp, common.PlaceholderMsg) { - return fmt.Sprintf("{{.%s}}", s), nil - } else { - return hp, nil - } - } + return passthroughOrInterpolate(passed, s) + case map[string]string: + // convert to a map[interface{}]interface{} so we can use same + // parsing on it + passed := make(map[interface{}]interface{}, len(data)) + for k, v := range data { + passed[k] = v } - return "", fmt.Errorf("loaded data, but couldnt find %s in it.", s) + return passthroughOrInterpolate(passed, s) + default: + return "", fmt.Errorf("Error validating build variable: the given "+ + "variable %s will not be passed into your plugin.", s) } - - return "", fmt.Errorf("Error validating build variable: the given "+ - "variable %s will not be passed into your plugin.", s) } } diff --git a/template/interpolate/funcs_test.go b/template/interpolate/funcs_test.go index b9a586641..363ee9672 100644 --- a/template/interpolate/funcs_test.go +++ b/template/interpolate/funcs_test.go @@ -384,6 +384,13 @@ func TestFuncPackerBuild(t *testing.T) { Template: "{{ build `MissingVar` }}", OutVal: "", }, + // Data map is a map[string]interface and contains value + { + DataMap: map[string]interface{}{"PartyVar": "PartyVal"}, + ErrExpected: false, + Template: "{{ build `PartyVar` }}", + OutVal: "PartyVal", + }, } for _, tc := range testCases {