From c2ebeb83268f24870069c7aef651ca2f3b477b28 Mon Sep 17 00:00:00 2001 From: David Chung Date: Wed, 17 May 2017 11:46:33 -0700 Subject: [PATCH 1/2] reduce number of fetches for dynamic commands Signed-off-by: David Chung --- pkg/cli/context.go | 34 ++++++++++++++++++++-------------- pkg/template/template.go | 23 +++++++++++++++++++---- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/pkg/cli/context.go b/pkg/cli/context.go index 22857ec79..548e02965 100644 --- a/pkg/cli/context.go +++ b/pkg/cli/context.go @@ -428,14 +428,7 @@ func (c *Context) Funcs() []template.Function { // loadBackend determines the backend to use for executing the rendered template text (e.g. run in shell). // During this phase, the template delimiters are changed to =% %= so put this in the comment {{/* */}} -func (c *Context) loadBackends() error { - t, err := template.NewTemplate(c.src, template.Options{ - DelimLeft: "=%", - DelimRight: "%=", - }) - if err != nil { - return err - } +func (c *Context) loadBackends(t *template.Template) error { t.AddFunc("print", func() string { c.run = func(script string) error { @@ -567,7 +560,10 @@ func (c *Context) loadBackends() error { return "" }) - _, err = t.Render(c) + _, err := t.Render(c) + + // clean up after we rendered... remove the functions + t.RemoveFunc("sh", "print", "instanceProvision", "managerCommit") return err } @@ -585,17 +581,27 @@ func (c *Context) BuildFlags() error { // Execute runs the command func (c *Context) Execute() error { - if err := c.loadBackends(); err != nil { - return err - } - t, err := template.NewTemplate(c.src, template.Options{ - Stderr: func() io.Writer { return os.Stderr }, + DelimLeft: "=%", + DelimRight: "%=", }) if err != nil { return err } + if err := c.loadBackends(t); err != nil { + return err + } + + // // create a new one without any fetch using the already fetched content + // t = template.NewFromTemplate(t, template.Options{ + // Stderr: func() io.Writer { return os.Stderr }, + // }) + + t.SetOptions(template.Options{ + Stderr: func() io.Writer { return os.Stderr }, + }) + c.exec = true c.template = t script, err := configureTemplate(t, c.plugins).Render(c) diff --git a/pkg/template/template.go b/pkg/template/template.go index 73c430946..cb2f760e3 100644 --- a/pkg/template/template.go +++ b/pkg/template/template.go @@ -143,6 +143,15 @@ func NewTemplateFromBytes(buff []byte, contextURL string, opt Options) (*Templat }, nil } +// NewFromTemplate creates a new template from existing, without any fetches (hence network calls) +func NewFromTemplate(from *Template, opt Options) *Template { + return &Template{ + options: opt, + url: from.url, + body: from.body, + } +} + // SetOptions sets the runtime flags for the engine func (t *Template) SetOptions(opt Options) *Template { t.lock.Lock() @@ -167,6 +176,16 @@ func (t *Template) AddFunc(name string, f interface{}) *Template { return t } +// RemoveFunc remove the functions +func (t *Template) RemoveFunc(name ...string) *Template { + t.lock.Lock() + defer t.lock.Unlock() + for _, n := range name { + delete(t.funcs, n) + } + return t +} + // Ref returns the value keyed by name in the context of this template. See 'ref' template function. func (t *Template) Ref(name string) interface{} { if found, has := t.globals[name]; has { @@ -275,10 +294,6 @@ func (t *Template) build(context Context) error { t.lock.Lock() defer t.lock.Unlock() - if t.parsed != nil { - return nil - } - registered := []Function{} fm := map[string]interface{}{} From d32e363425e1a43c08c5a89afd8fcc9cb7eef0c4 Mon Sep 17 00:00:00 2001 From: David Chung Date: Wed, 17 May 2017 12:14:29 -0700 Subject: [PATCH 2/2] use a single template Signed-off-by: David Chung --- pkg/cli/context.go | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/pkg/cli/context.go b/pkg/cli/context.go index 548e02965..415d1271c 100644 --- a/pkg/cli/context.go +++ b/pkg/cli/context.go @@ -567,37 +567,50 @@ func (c *Context) loadBackends(t *template.Template) error { return err } +func (c *Context) getTemplate() (*template.Template, error) { + if c.template == nil { + t, err := template.NewTemplate(c.src, template.Options{}) + if err != nil { + return nil, err + } + c.template = t + } + return c.template, nil +} + // BuildFlags from parsing the body which is a template -func (c *Context) BuildFlags() error { - t, err := template.NewTemplate(c.src, template.Options{}) +func (c *Context) BuildFlags() (err error) { + var t *template.Template + + t, err = c.getTemplate() if err != nil { - return err + return } - + t.SetOptions(template.Options{}) _, err = configureTemplate(t, c.plugins).Render(c) - return err + return } // Execute runs the command -func (c *Context) Execute() error { +func (c *Context) Execute() (err error) { + var t *template.Template - t, err := template.NewTemplate(c.src, template.Options{ + t, err = c.getTemplate() + if err != nil { + return + } + + // First pass to get the backends + t.SetOptions(template.Options{ DelimLeft: "=%", DelimRight: "%=", }) - if err != nil { - return err - } if err := c.loadBackends(t); err != nil { return err } - // // create a new one without any fetch using the already fetched content - // t = template.NewFromTemplate(t, template.Options{ - // Stderr: func() io.Writer { return os.Stderr }, - // }) - + // Now regular processing t.SetOptions(template.Options{ Stderr: func() io.Writer { return os.Stderr }, })