You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helm/pkg/engine/engine.go

106 lines
3.1 KiB

package engine
import (
"bytes"
"fmt"
"text/template"
"github.com/Masterminds/sprig"
chartutil "github.com/deis/tiller/pkg/chart"
"github.com/deis/tiller/pkg/proto/hapi/chart"
)
// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
// FuncMap contains the template functions that will be passed to each
// render call. This may only be modified before the first call to Render.
FuncMap template.FuncMap
}
// New creates a new Go template Engine instance.
//
// The FuncMap is initialized here. You may modify the FuncMap _prior to_ the
// first invocation of Render.
//
// The FuncMap sets all of the Sprig functions except for those that provide
// access to the underlying OS (env, expandenv).
func New() *Engine {
f := sprig.TxtFuncMap()
delete(f, "env")
delete(f, "expandenv")
return &Engine{
FuncMap: f,
}
}
// Render takes a chart, optional values, and attempts to render the Go templates.
//
// Render can be called repeatedly on the same engine.
//
// This will look in the chart's 'templates' data (e.g. the 'templates/' directory)
// and attempt to render the templates there using the values passed in.
func (e *Engine) Render(chrt *chart.Chart, vals *chart.Config) (map[string]string, error) {
var cvals chartutil.Values
if chrt.Values == nil {
cvals = map[string]interface{}{}
} else {
var err error
cvals, err = chartutil.ReadValues([]byte(chrt.Values.Raw))
if err != nil {
return map[string]string{}, err
}
}
// Parse values if not nil
if vals != nil {
evals, err := chartutil.ReadValues([]byte(vals.Raw))
if err != nil {
return map[string]string{}, err
}
// Coalesce chart default values and values
for k, v := range evals {
// FIXME: This needs to merge tables. Ideally, this feature should
// be part of the Values type.
cvals[k] = v
}
}
// Render the charts
tmap := make(map[string]string, len(chrt.Templates))
for _, tpl := range chrt.Templates {
tmap[tpl.Name] = string(tpl.Data)
}
return e.render(tmap, cvals)
}
func (e *Engine) render(tpls map[string]string, v interface{}) (map[string]string, error) {
// Basically, what we do here is start with an empty parent template and then
// build up a list of templates -- one for each file. Once all of the templates
// have been parsed, we loop through again and execute every template.
//
// The idea with this process is to make it possible for more complex templates
// to share common blocks, but to make the entire thing feel like a file-based
// template engine.
t := template.New("gotpl")
files := []string{}
for fname, tpl := range tpls {
t = t.New(fname).Funcs(e.FuncMap)
if _, err := t.Parse(tpl); err != nil {
return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
}
files = append(files, fname)
}
rendered := make(map[string]string, len(files))
var buf bytes.Buffer
for _, file := range files {
if err := t.ExecuteTemplate(&buf, file, v); err != nil {
return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err)
}
rendered[file] = buf.String()
buf.Reset()
}
return rendered, nil
}