feat(engine): add 'partial' function

This adds a context-aware template function called 'partial' that will
allow rendering other templates in a chart into a string value, which
can then be piped to other functions. Usage is something like
'{{partial 'path/to/template.yaml' | indent 2}}'

This might be a bad idea.

Closes #1005
pull/1006/head
Matt Butcher 9 years ago
parent be053f3c05
commit 9718c9e7c8

@ -88,6 +88,28 @@ type renderable struct {
vals chartutil.Values vals chartutil.Values
} }
// alterFuncMap takes the Engine's FuncMap and adds context-specific functions.
//
// The resulting FuncMap is only valid for the passed-in template.
func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
// Clone the func map because we are adding context-specific functions.
var funcMap template.FuncMap = map[string]interface{}{}
for k, v := range e.FuncMap {
funcMap[k] = v
}
// Add the 'include' function here so we can close over t.
funcMap["include"] = func(name string, data interface{}) string {
buf := bytes.NewBuffer(nil)
if err := t.ExecuteTemplate(buf, name, data); err != nil {
buf.WriteString(err.Error())
}
return buf.String()
}
return funcMap
}
// render takes a map of templates/values and renders them. // render takes a map of templates/values and renders them.
func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) { func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
// Basically, what we do here is start with an empty parent template and then // Basically, what we do here is start with an empty parent template and then
@ -105,10 +127,13 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
// but will still emit <no value> for others. We mitigate that later. // but will still emit <no value> for others. We mitigate that later.
t.Option("missingkey=zero") t.Option("missingkey=zero")
} }
funcMap := e.alterFuncMap(t)
files := []string{} files := []string{}
for fname, r := range tpls { for fname, r := range tpls {
log.Printf("Preparing template %s", fname) log.Printf("Preparing template %s", fname)
t = t.New(fname).Funcs(e.FuncMap) t = t.New(fname).Funcs(funcMap)
if _, err := t.Parse(r.tpl); err != nil { if _, err := t.Parse(r.tpl); err != nil {
return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err) return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
} }

@ -358,3 +358,33 @@ func TestRenderBuiltinValues(t *testing.T) {
} }
} }
func TestAlterFuncMap(t *testing.T) {
c := &chart.Chart{
Metadata: &chart.Metadata{Name: "conrad"},
Templates: []*chart.Template{
{Name: "quote", Data: []byte(`{{include "conrad/_partial" . | indent 2}} dead.`)},
{Name: "_partial", Data: []byte(`{{.Release.Name}} - he`)},
},
Values: &chart.Config{Raw: ``},
Dependencies: []*chart.Chart{},
}
v := chartutil.Values{
"Values": &chart.Config{Raw: ""},
"Chart": c.Metadata,
"Release": chartutil.Values{
"Name": "Mistah Kurtz",
},
}
out, err := New().Render(c, v)
if err != nil {
t.Fatal(err)
}
expect := " Mistah Kurtz - he dead."
if got := out["conrad/quote"]; got != expect {
t.Errorf("Expected %q, got %q (%v)", expect, got, out)
}
}

Loading…
Cancel
Save