From 2bbc3d50d778f3dc47b77dab06b9613337506614 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Mon, 8 Jul 2019 13:49:14 -0700 Subject: [PATCH 1/2] better error handling when using interpolate funcs; don't swallow func errors --- packer/core.go | 12 +++++++++--- template/interpolate/funcs.go | 10 +++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packer/core.go b/packer/core.go index 507c79b81..2a6210356 100644 --- a/packer/core.go +++ b/packer/core.go @@ -366,9 +366,15 @@ func (c *Core) init() error { c.variables[k] = renderedV ctx.UserVariables = c.variables case ttmp.ExecError: - shouldRetry = true - failedInterpolation = fmt.Sprintf(`"%s": "%s"`, k, v) - continue + castError := err.(ttmp.ExecError) + switch castError.Err.(type) { + case interpolate.ErrVariableNotSet: + shouldRetry = true + failedInterpolation = fmt.Sprintf(`"%s": "%s"; error: %s`, k, v, err) + continue + default: + return err + } default: return fmt.Errorf( // unexpected interpolation error: abort the run diff --git a/template/interpolate/funcs.go b/template/interpolate/funcs.go index 57495052a..f2842bc16 100644 --- a/template/interpolate/funcs.go +++ b/template/interpolate/funcs.go @@ -47,6 +47,14 @@ var FuncGens = map[string]FuncGenerator{ "lower": funcGenPrimitive(strings.ToLower), } +type ErrVariableNotSet struct { + Var string // Name of template. +} + +func (e ErrVariableNotSet) Error() string { + return fmt.Sprintf("variable %s not set", e.Var) +} + // FuncGenerator is a function that given a context generates a template // function for the template. type FuncGenerator func(*Context) interface{} @@ -168,7 +176,7 @@ func funcGenUser(ctx *Context) interface{} { // error and retry if we're interpolating UserVariables. But if // we're elsewhere in the template, just return the empty string. if !ok { - return "", errors.New(fmt.Sprintf("variable %s not set", k)) + return "", ErrVariableNotSet{k} } } return val, nil From e54b1cedd936f46260ab339c1d1e443bd760e7a3 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Mon, 8 Jul 2019 15:39:46 -0700 Subject: [PATCH 2/2] text/template turns out to swallow custom error types. --- packer/core.go | 7 +++---- template/interpolate/funcs.go | 10 ++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packer/core.go b/packer/core.go index 2a6210356..c9672eb96 100644 --- a/packer/core.go +++ b/packer/core.go @@ -3,6 +3,7 @@ package packer import ( "fmt" "sort" + "strings" ttmp "text/template" @@ -367,12 +368,10 @@ func (c *Core) init() error { ctx.UserVariables = c.variables case ttmp.ExecError: castError := err.(ttmp.ExecError) - switch castError.Err.(type) { - case interpolate.ErrVariableNotSet: + if strings.Contains(castError.Error(), interpolate.ErrVariableNotSetString) { shouldRetry = true failedInterpolation = fmt.Sprintf(`"%s": "%s"; error: %s`, k, v, err) - continue - default: + } else { return err } default: diff --git a/template/interpolate/funcs.go b/template/interpolate/funcs.go index f2842bc16..1d76f8f06 100644 --- a/template/interpolate/funcs.go +++ b/template/interpolate/funcs.go @@ -47,13 +47,7 @@ var FuncGens = map[string]FuncGenerator{ "lower": funcGenPrimitive(strings.ToLower), } -type ErrVariableNotSet struct { - Var string // Name of template. -} - -func (e ErrVariableNotSet) Error() string { - return fmt.Sprintf("variable %s not set", e.Var) -} +var ErrVariableNotSetString = "Error: variable not set:" // FuncGenerator is a function that given a context generates a template // function for the template. @@ -176,7 +170,7 @@ func funcGenUser(ctx *Context) interface{} { // error and retry if we're interpolating UserVariables. But if // we're elsewhere in the template, just return the empty string. if !ok { - return "", ErrVariableNotSet{k} + return "", fmt.Errorf("%s %s", ErrVariableNotSetString, k) } } return val, nil