From 908e9fb6762dd5d4c12c705b10973142f60d3e7b Mon Sep 17 00:00:00 2001 From: David Chung Date: Mon, 6 Feb 2017 01:32:29 -0800 Subject: [PATCH] New template improvements (#388) Signed-off-by: David Chung --- dockerfiles/Dockerfile.bundle | 7 ++++++ pkg/template/funcs.go | 38 +++++++++++++++++++++++++++++++- pkg/template/integration_test.go | 10 +++++++++ pkg/template/template.go | 8 +++++++ 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/dockerfiles/Dockerfile.bundle b/dockerfiles/Dockerfile.bundle index 95b3b2bbe..079b7d7d5 100644 --- a/dockerfiles/Dockerfile.bundle +++ b/dockerfiles/Dockerfile.bundle @@ -2,4 +2,11 @@ FROM alpine:3.5 RUN apk add --update ca-certificates +RUN mkdir -p /infrakit/plugins /infrakit/configs /infrakit/logs + +VOLUME /infrakit + +ENV INFRAKIT_HOME /infrakit +ENV INFRAKIT_PLUGINS_DIR /infrakit/plugins + ADD build/* /usr/local/bin/ diff --git a/pkg/template/funcs.go b/pkg/template/funcs.go index 53e606d06..c5d84b6d8 100644 --- a/pkg/template/funcs.go +++ b/pkg/template/funcs.go @@ -114,6 +114,40 @@ func IndexOf(srch interface{}, array interface{}, strictOptional ...bool) int { // DefaultFuncs returns a list of default functions for binding in the template func (t *Template) DefaultFuncs() []Function { return []Function{ + { + Name: "source", + Description: []string{ + "Source / evaluate the template at the input location (as URL).", + "This will make all of the global variables declared there visible in this template's context.", + }, + Func: func(p string) (string, error) { + loc := p + if strings.Index(loc, "str://") == -1 { + buff, err := getURL(t.url, p) + if err != nil { + return "", err + } + loc = buff + } + sourced, err := NewTemplate(loc, t.options) + if err != nil { + return "", err + } + // copy the binds in the parent scope into the child + for k, v := range t.binds { + sourced.binds[k] = v + } + // inherit the functions defined for this template + for k, v := range t.funcs { + sourced.AddFunc(k, v) + } + // set this as the parent of the sourced template so its global can mutate the globals in this + sourced.parent = t + + // TODO(chungers) -- let the sourced template define new functions that can be called in the parent. + return sourced.Render(nil) + }, + }, { Name: "include", Description: []string{ @@ -187,7 +221,9 @@ func (t *Template) DefaultFuncs() []Function { "Global variables are propagated to all templates that are rendered via the 'include' function.", }, Func: func(name string, v interface{}) interface{} { - t.binds[name] = v + for here := t; here != nil; here = here.parent { + here.updateGlobal(name, v) + } return "" }, }, diff --git a/pkg/template/integration_test.go b/pkg/template/integration_test.go index 08f072932..a94149304 100644 --- a/pkg/template/integration_test.go +++ b/pkg/template/integration_test.go @@ -169,3 +169,13 @@ func TestAddDef(t *testing.T) { require.NoError(t, err) require.Equal(t, "hello: x + y = 125", view) } + +func TestSourceAndGlobal(t *testing.T) { + r := `{{ global \"foo\" 100 }}` + s := `{{ source "str://` + r + `" }}foo={{ref "foo"}}` + tt, err := NewTemplate("str://"+s, Options{}) + require.NoError(t, err) + view, err := tt.Render(nil) + require.NoError(t, err) + require.Equal(t, "foo=100", view) +} diff --git a/pkg/template/template.go b/pkg/template/template.go index bba7a0e38..959abbd7b 100644 --- a/pkg/template/template.go +++ b/pkg/template/template.go @@ -76,6 +76,8 @@ type Template struct { registered []Function lock sync.Mutex + + parent *Template } // NewTemplate fetches the content at the url and returns a template. If the string begins @@ -143,6 +145,12 @@ func (t *Template) AddDef(name string, val interface{}, doc ...string) *Template return t } +func (t *Template) updateGlobal(name string, value interface{}) { + t.lock.Lock() + defer t.lock.Unlock() + t.binds[name] = value +} + // Validate parses the template and checks for validity. func (t *Template) Validate() (*Template, error) { t.lock.Lock()