mirror of https://github.com/helm/helm
parent
e1321bb86f
commit
fa387494fb
@ -0,0 +1,7 @@
|
||||
/*Package engine implements the Go template engine as a Tiller Engine.
|
||||
|
||||
Tiller provides a simple interface for taking a Chart and rendering its templates.
|
||||
The 'engine' package implements this interface using Go's built-in 'text/template'
|
||||
package.
|
||||
*/
|
||||
package engine
|
@ -0,0 +1,73 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig"
|
||||
"github.com/deis/tiller/pkg/hapi"
|
||||
)
|
||||
|
||||
type Engine struct {
|
||||
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(chart *hapi.Chart, vals *hapi.Values) (map[string]string, error) {
|
||||
// Uncomment this once the proto files compile.
|
||||
//return render(chart.Chartfile.Name, chart.Templates, vals)
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
|
||||
func (e *Engine) render(name string, 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(name)
|
||||
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
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEngine(t *testing.T) {
|
||||
e := New()
|
||||
|
||||
// Forbidden because they allow access to the host OS.
|
||||
forbidden := []string{"env", "expandenv"}
|
||||
for _, f := range forbidden {
|
||||
if _, ok := e.FuncMap[f]; ok {
|
||||
t.Errorf("Forbidden function %s exists in FuncMap.", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRender(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestRenderInternals(t *testing.T) {
|
||||
// Test the internals of the rendering tool.
|
||||
e := New()
|
||||
|
||||
tpls := map[string]string{
|
||||
"one": `Hello {{title .Name}}`,
|
||||
"two": `Goodbye {{upper .Value}}`,
|
||||
// Test whether a template can reliably reference another template
|
||||
// without regard for ordering.
|
||||
"three": `{{template "two" dict "Value" "three"}}`,
|
||||
}
|
||||
vals := map[string]string{"Name": "one", "Value": "two"}
|
||||
|
||||
out, err := e.render("irrelevant", tpls, vals)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed template rendering: %s", err)
|
||||
}
|
||||
|
||||
if len(out) != 3 {
|
||||
t.Fatalf("Expected 3 templates, got %d", len(out))
|
||||
}
|
||||
|
||||
if out["one"] != "Hello One" {
|
||||
t.Errorf("Expected 'Hello One', got %q", out["one"])
|
||||
}
|
||||
|
||||
if out["two"] != "Goodbye TWO" {
|
||||
t.Errorf("Expected 'Goodbye TWO'. got %q", out["two"])
|
||||
}
|
||||
|
||||
if out["three"] != "Goodbye THREE" {
|
||||
t.Errorf("Expected 'Goodbye THREE'. got %q", out["two"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestParallelRenderInternals(t *testing.T) {
|
||||
// Make sure that we can use one Engine to run parallel template renders.
|
||||
e := New()
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 20; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
fname := "my/file/name"
|
||||
tt := fmt.Sprintf("expect-%d", i)
|
||||
tpls := map[string]string{fname: `{{.val}}`}
|
||||
v := map[string]string{"val": tt}
|
||||
out, err := e.render("intentionally_duplicated", tpls, v)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to render %s: %s", tt, err)
|
||||
}
|
||||
if out[fname] != tt {
|
||||
t.Errorf("Expected %q, got %q", tt, out[fname])
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
Loading…
Reference in new issue