From 3ebfe06ec8dcfbe2da1d7d7fde02d9fd4c61193d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 23 May 2015 16:12:32 -0700 Subject: [PATCH] packer: render build names --- packer/core.go | 31 ++++++++++++++++ packer/core_test.go | 41 +++++++++++++++++++++ packer/test-fixtures/build-names-basic.json | 5 +++ packer/test-fixtures/build-names-func.json | 5 +++ template/interpolate/i.go | 5 +++ 5 files changed, 87 insertions(+) create mode 100644 packer/test-fixtures/build-names-basic.json create mode 100644 packer/test-fixtures/build-names-func.json diff --git a/packer/core.go b/packer/core.go index caa18a196..21ea4b8f9 100644 --- a/packer/core.go +++ b/packer/core.go @@ -3,9 +3,11 @@ package packer import ( "fmt" "os" + "sort" "github.com/hashicorp/go-multierror" "github.com/mitchellh/packer/template" + "github.com/mitchellh/packer/template/interpolate" ) // Core is the main executor of Packer. If Packer is being used as a @@ -16,6 +18,7 @@ type Core struct { ui Ui template *template.Template variables map[string]string + builds map[string]*template.Builder } // CoreConfig is the structure for initializing a new Core. Once a CoreConfig @@ -38,15 +41,43 @@ func NewCore(c *CoreConfig) (*Core, error) { } } + // Go through and interpolate all the build names. We shuld be able + // to do this at this point with the variables. + builds := make(map[string]*template.Builder) + for _, b := range c.Template.Builders { + v, err := interpolate.Render(b.Name, &interpolate.Context{ + UserVariables: c.Variables, + }) + if err != nil { + return nil, fmt.Errorf( + "Error interpolating builder '%s': %s", + b.Name, err) + } + + builds[v] = b + } + return &Core{ cache: c.Cache, components: c.Components, ui: c.Ui, template: c.Template, variables: c.Variables, + builds: builds, }, nil } +// BuildNames returns the builds that are available in this configured core. +func (c *Core) BuildNames() []string { + r := make([]string, 0, len(c.builds)) + for n, _ := range c.builds { + r = append(r, n) + } + sort.Strings(r) + + return r +} + // Build returns the Build object for the given name. func (c *Core) Build(n string) (Build, error) { // Setup the builder diff --git a/packer/core_test.go b/packer/core_test.go index dc7880302..d3f338d12 100644 --- a/packer/core_test.go +++ b/packer/core_test.go @@ -2,11 +2,52 @@ package packer import ( "os" + "reflect" "testing" "github.com/mitchellh/packer/template" ) +func TestCoreBuildNames(t *testing.T) { + cases := []struct { + File string + Vars map[string]string + Result []string + }{ + { + "build-names-basic.json", + nil, + []string{"something"}, + }, + + { + "build-names-func.json", + nil, + []string{"TUBES"}, + }, + } + + for _, tc := range cases { + tpl, err := template.ParseFile(fixtureDir(tc.File)) + if err != nil { + t.Fatalf("err: %s\n\n%s", tc.File, err) + } + + core, err := NewCore(&CoreConfig{ + Template: tpl, + Variables: tc.Vars, + }) + if err != nil { + t.Fatalf("err: %s\n\n%s", tc.File, err) + } + + names := core.BuildNames() + if !reflect.DeepEqual(names, tc.Result) { + t.Fatalf("err: %s\n\n%#v", tc.File, names) + } + } +} + func TestCoreValidate(t *testing.T) { cases := []struct { File string diff --git a/packer/test-fixtures/build-names-basic.json b/packer/test-fixtures/build-names-basic.json new file mode 100644 index 000000000..1b0162551 --- /dev/null +++ b/packer/test-fixtures/build-names-basic.json @@ -0,0 +1,5 @@ +{ + "builders": [ + {"type": "something"} + ] +} diff --git a/packer/test-fixtures/build-names-func.json b/packer/test-fixtures/build-names-func.json new file mode 100644 index 000000000..feb28cf37 --- /dev/null +++ b/packer/test-fixtures/build-names-func.json @@ -0,0 +1,5 @@ +{ + "builders": [ + {"type": "{{upper `tubes`}}"} + ] +} diff --git a/template/interpolate/i.go b/template/interpolate/i.go index 5f70ed82a..d52653fcf 100644 --- a/template/interpolate/i.go +++ b/template/interpolate/i.go @@ -19,6 +19,11 @@ type Context struct { EnableEnv bool } +// Render is shorthand for constructing an I and calling Render. +func Render(v string, ctx *Context) (string, error) { + return (&I{Value: v}).Render(ctx) +} + // I stands for "interpolation" and is the main interpolation struct // in order to render values. type I struct {