Speed up `tpl`

- Use a clone of the current Template instead of re-creating everything from scratch
- Needs to inject `include` so any defines in the tpl text can be seen.

Signed-off-by: Graham Reed <greed@7deadly.org>
pull/11351/head
Graham Reed 2 years ago
parent bed23120b0
commit db4f330122

@ -103,13 +103,10 @@ func warnWrap(warn string) string {
return warnStartDelim + warn + warnEndDelim
}
// initFunMap creates the Engine's FuncMap and adds context-specific functions.
func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]renderable) {
funcMap := funcMap()
includedNames := make(map[string]int)
// Add the 'include' function here so we can close over t.
funcMap["include"] = func(name string, data interface{}) (string, error) {
// 'include' needs to be defined in the scope of a 'tpl' template as
// well as regular file-loaded templates.
func includeFun(t *template.Template, includedNames map[string]int) func(string, interface{}) (string, error) {
return func(name string, data interface{}) (string, error) {
var buf strings.Builder
if v, ok := includedNames[name]; ok {
if v > recursionMaxNums {
@ -123,32 +120,42 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render
includedNames[name]--
return buf.String(), err
}
}
// initFunMap creates the Engine's FuncMap and adds context-specific functions.
func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]renderable) {
funcMap := funcMap()
includedNames := make(map[string]int)
// Add the 'include' function here so we can close over t.
funcMap["include"] = includeFun(t, includedNames)
// Add the 'tpl' function here
funcMap["tpl"] = func(tpl string, vals chartutil.Values) (string, error) {
basePath, err := vals.PathValue("Template.BasePath")
t, err := t.Clone()
if err != nil {
return "", errors.Wrapf(err, "cannot retrieve Template.Basepath from values inside tpl function: %s", tpl)
return "", errors.Wrapf(err, "cannot clone template")
}
templateName, err := vals.PathValue("Template.Name")
if err != nil {
return "", errors.Wrapf(err, "cannot retrieve Template.Name from values inside tpl function: %s", tpl)
// Re-inject 'include' so that it can close over our clone of t;
// this lets any 'define's inside tpl be 'include'd.
tplFuncMap := template.FuncMap{
"include": includeFun(t, includedNames),
}
t.Funcs(tplFuncMap)
templates := map[string]renderable{
templateName.(string): {
tpl: tpl,
vals: vals,
basePath: basePath.(string),
},
t, err = t.Parse(tpl)
if err != nil {
return "", errors.Wrapf(err, "cannot parse template %q", tpl)
}
result, err := e.renderWithReferences(templates, referenceTpls)
if err != nil {
var buf strings.Builder
if err := t.Execute(&buf, vals); err != nil {
return "", errors.Wrapf(err, "error during tpl function execution for %q", tpl)
}
return result[templateName.(string)], nil
// See comment in renderWithReferences explaining the <no value> hack.
return strings.ReplaceAll(buf.String(), "<no value>", ""), nil
}
// Add the `required` function here so we can use lintMode

Loading…
Cancel
Save