@ -21,6 +21,7 @@ import (
"log"
"path"
"path/filepath"
"regexp"
"sort"
"strings"
"text/template"
@ -80,6 +81,12 @@ type renderable struct {
basePath string
}
var warnRegex = regexp . MustCompile ( ` HELM\[(.*)\]HELM ` )
func warnWrap ( warn string ) string {
return fmt . Sprintf ( "HELM[%s]HELM" , warn )
}
// initFunMap creates the Engine's FuncMap and adds context-specific functions.
func ( e Engine ) initFunMap ( t * template . Template , referenceTpls map [ string ] renderable ) {
funcMap := funcMap ( )
@ -126,7 +133,7 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render
log . Printf ( "[INFO] Missing required value: %s" , warn )
return "" , nil
}
return val , errors . Errorf ( warn )
return val , errors . Errorf ( warnWrap ( warn ) )
} else if _ , ok := val . ( string ) ; ok {
if val == "" {
if e . LintMode {
@ -134,7 +141,7 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render
log . Printf ( "[INFO] Missing required value: %s" , warn )
return "" , nil
}
return val , errors . Errorf ( warn )
return val , errors . Errorf ( warnWrap ( warn ) )
}
}
return val , nil
@ -181,7 +188,7 @@ func (e Engine) renderWithReferences(tpls, referenceTpls map[string]renderable)
for _ , filename := range keys {
r := tpls [ filename ]
if _ , err := t . New ( filename ) . Parse ( r . tpl ) ; err != nil {
return map [ string ] string { } , parseTemplat eError( filename , err )
return map [ string ] string { } , cleanu pP arseError( filename , err )
}
}
@ -190,7 +197,7 @@ func (e Engine) renderWithReferences(tpls, referenceTpls map[string]renderable)
for filename , r := range referenceTpls {
if t . Lookup ( filename ) == nil {
if _ , err := t . New ( filename ) . Parse ( r . tpl ) ; err != nil {
return map [ string ] string { } , parseTemplat eError( filename , err )
return map [ string ] string { } , cleanu pP arseError( filename , err )
}
}
}
@ -207,7 +214,7 @@ func (e Engine) renderWithReferences(tpls, referenceTpls map[string]renderable)
vals [ "Template" ] = chartutil . Values { "Name" : filename , "BasePath" : tpls [ filename ] . basePath }
var buf strings . Builder
if err := t . ExecuteTemplate ( & buf , filename , vals ) ; err != nil {
return map [ string ] string { } , parseTemplate Error( filename , err )
return map [ string ] string { } , cleanupExec Error( filename , err )
}
// Work around the issue where Go will emit "<no value>" even if Options(missing=zero)
@ -223,18 +230,41 @@ func (e Engine) renderWithReferences(tpls, referenceTpls map[string]renderable)
return rendered , nil
}
func parseTemplat eError( filename string , err error ) error {
func cleanu pP arseError( filename string , err error ) error {
tokens := strings . Split ( err . Error ( ) , ": " )
if len ( tokens ) == 1 {
// This might happen if a non-templating error occurs
return fmt . Errorf ( " render error in (%s): %s", filename , err )
return fmt . Errorf ( " pa rs e error in (%s): %s", filename , err )
}
// The first token is "template"
// The second token is either "filename:lineno" or "filename:lineNo:columnNo"
location := tokens [ 1 ]
// The remaining tokens make up a stacktrace-like chain, ending with the relevant error
errMsg := tokens [ len ( tokens ) - 1 ]
return fmt . Errorf ( "render error at (%s): %s" , string ( location ) , errMsg )
return fmt . Errorf ( "parse error at (%s): %s" , string ( location ) , errMsg )
}
func cleanupExecError ( filename string , err error ) error {
if _ , isExecError := err . ( template . ExecError ) ; ! isExecError {
return err
}
tokens := strings . SplitN ( err . Error ( ) , ": " , 3 )
if len ( tokens ) != 3 {
// This might happen if a non-templating error occurs
return fmt . Errorf ( "execution error in (%s): %s" , filename , err )
}
// The first token is "template"
// The second token is either "filename:lineno" or "filename:lineNo:columnNo"
location := tokens [ 1 ]
parts := warnRegex . FindStringSubmatch ( tokens [ 2 ] )
if len ( parts ) >= 2 {
return fmt . Errorf ( "execution error at (%s): %s" , string ( location ) , parts [ 1 ] )
}
return err
}
func sortTemplates ( tpls map [ string ] renderable ) [ ] string {