From 839784b044cf683e6d4dfb12b36e770c06d61d71 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 21 May 2015 14:32:22 -0600 Subject: [PATCH] template: parse post-processors --- template/parse.go | 92 ++++++++++++++++- template/parse_test.go | 102 +++++++++++++++++++ template/template.go | 12 ++- template/test-fixtures/parse-pp-basic.json | 6 ++ template/test-fixtures/parse-pp-keep.json | 6 ++ template/test-fixtures/parse-pp-map.json | 5 + template/test-fixtures/parse-pp-multi.json | 5 + template/test-fixtures/parse-pp-no-type.json | 5 + template/test-fixtures/parse-pp-slice.json | 5 + template/test-fixtures/parse-pp-string.json | 3 + 10 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 template/test-fixtures/parse-pp-basic.json create mode 100644 template/test-fixtures/parse-pp-keep.json create mode 100644 template/test-fixtures/parse-pp-map.json create mode 100644 template/test-fixtures/parse-pp-multi.json create mode 100644 template/test-fixtures/parse-pp-no-type.json create mode 100644 template/test-fixtures/parse-pp-slice.json create mode 100644 template/test-fixtures/parse-pp-string.json diff --git a/template/parse.go b/template/parse.go index 47d97effa..f9dc7cba3 100644 --- a/template/parse.go +++ b/template/parse.go @@ -17,11 +17,11 @@ type rawTemplate struct { MinVersion string `mapstructure:"min_packer_version"` Description string - Builders []map[string]interface{} - Push map[string]interface{} - PostProcesors []interface{} `mapstructure:"post-processors"` - Provisioners []map[string]interface{} - Variables map[string]interface{} + Builders []map[string]interface{} + Push map[string]interface{} + PostProcessors []interface{} `mapstructure:"post-processors"` + Provisioners []map[string]interface{} + Variables map[string]interface{} } // Template returns the actual Template object built from this raw @@ -94,6 +94,49 @@ func (r *rawTemplate) Template() (*Template, error) { result.Builders[b.Name] = &b } + // Gather all the post-processors + if len(r.PostProcessors) > 0 { + result.PostProcessors = make([][]*PostProcessor, 0, len(r.PostProcessors)) + } + for i, v := range r.PostProcessors { + // Parse the configurations. We need to do this because post-processors + // can take three different formats. + configs, err := r.parsePostProcessor(i, v) + if err != nil { + errs = multierror.Append(errs, err) + continue + } + + // Parse the PostProcessors out of the configs + pps := make([]*PostProcessor, 0, len(configs)) + for j, c := range configs { + var pp PostProcessor + if err := r.decoder(&pp, nil).Decode(c); err != nil { + errs = multierror.Append(errs, fmt.Errorf( + "post-processor %d.%d: %s", i+1, j+1, err)) + continue + } + + // Type is required + if pp.Type == "" { + errs = multierror.Append(errs, fmt.Errorf( + "post-processor %d.%d: type is required", i+1, j+1)) + continue + } + + // Set the configuration + delete(c, "keep_input_artifact") + delete(c, "type") + if len(c) > 0 { + pp.Config = c + } + + pps = append(pps, &pp) + } + + result.PostProcessors = append(result.PostProcessors, pps) + } + // Gather all the provisioners if len(r.Provisioners) > 0 { result.Provisioners = make([]*Provisioner, 0, len(r.Provisioners)) @@ -152,6 +195,45 @@ func (r *rawTemplate) decoder( return d } +func (r *rawTemplate) parsePostProcessor( + i int, raw interface{}) ([]map[string]interface{}, error) { + switch v := raw.(type) { + case string: + return []map[string]interface{}{ + {"type": v}, + }, nil + case map[string]interface{}: + return []map[string]interface{}{v}, nil + case []interface{}: + var err error + result := make([]map[string]interface{}, len(v)) + for j, innerRaw := range v { + switch innerV := innerRaw.(type) { + case string: + result[j] = map[string]interface{}{"type": innerV} + case map[string]interface{}: + result[j] = innerV + case []interface{}: + err = multierror.Append(err, fmt.Errorf( + "post-processor %d.%d: sequence not allowed to be nested in a sequence", + i+1, j+1)) + default: + err = multierror.Append(err, fmt.Errorf( + "post-processor %d.%d: unknown format", + i+1, j+1)) + } + } + + if err != nil { + return nil, err + } + + return result, nil + default: + return nil, fmt.Errorf("post-processor %d: bad format", i+1) + } +} + // Parse takes the given io.Reader and parses a Template object out of it. func Parse(r io.Reader) (*Template, error) { // First, decode the object into an interface{}. We do this instead of diff --git a/template/parse_test.go b/template/parse_test.go index fcf7fcf29..b28670e40 100644 --- a/template/parse_test.go +++ b/template/parse_test.go @@ -141,6 +141,108 @@ func TestParse(t *testing.T) { }, false, }, + + { + "parse-pp-basic.json", + &Template{ + PostProcessors: [][]*PostProcessor{ + []*PostProcessor{ + &PostProcessor{ + Type: "foo", + Config: map[string]interface{}{ + "foo": "bar", + }, + }, + }, + }, + }, + false, + }, + + { + "parse-pp-keep.json", + &Template{ + PostProcessors: [][]*PostProcessor{ + []*PostProcessor{ + &PostProcessor{ + Type: "foo", + KeepInputArtifact: true, + }, + }, + }, + }, + false, + }, + + { + "parse-pp-string.json", + &Template{ + PostProcessors: [][]*PostProcessor{ + []*PostProcessor{ + &PostProcessor{ + Type: "foo", + }, + }, + }, + }, + false, + }, + + { + "parse-pp-map.json", + &Template{ + PostProcessors: [][]*PostProcessor{ + []*PostProcessor{ + &PostProcessor{ + Type: "foo", + }, + }, + }, + }, + false, + }, + + { + "parse-pp-slice.json", + &Template{ + PostProcessors: [][]*PostProcessor{ + []*PostProcessor{ + &PostProcessor{ + Type: "foo", + }, + }, + []*PostProcessor{ + &PostProcessor{ + Type: "bar", + }, + }, + }, + }, + false, + }, + + { + "parse-pp-multi.json", + &Template{ + PostProcessors: [][]*PostProcessor{ + []*PostProcessor{ + &PostProcessor{ + Type: "foo", + }, + &PostProcessor{ + Type: "bar", + }, + }, + }, + }, + false, + }, + + { + "parse-pp-no-type.json", + nil, + true, + }, } for _, tc := range cases { diff --git a/template/template.go b/template/template.go index daee508fc..8de30b1a9 100644 --- a/template/template.go +++ b/template/template.go @@ -27,10 +27,10 @@ type Builder struct { // PostProcessor represents a post-processor within the template. type PostProcessor struct { - OnlyExcept + OnlyExcept `mapstructure:",squash"` Type string - KeepInputArtifact bool + KeepInputArtifact bool `mapstructure:"keep_input_artifact"` Config map[string]interface{} } @@ -79,3 +79,11 @@ func (b *Builder) GoString() string { func (p *Provisioner) GoString() string { return fmt.Sprintf("*%#v", *p) } + +func (p *PostProcessor) GoString() string { + return fmt.Sprintf("*%#v", *p) +} + +func (v *Variable) GoString() string { + return fmt.Sprintf("*%#v", *v) +} diff --git a/template/test-fixtures/parse-pp-basic.json b/template/test-fixtures/parse-pp-basic.json new file mode 100644 index 000000000..56a1145e6 --- /dev/null +++ b/template/test-fixtures/parse-pp-basic.json @@ -0,0 +1,6 @@ +{ + "post-processors": [{ + "type": "foo", + "foo": "bar" + }] +} diff --git a/template/test-fixtures/parse-pp-keep.json b/template/test-fixtures/parse-pp-keep.json new file mode 100644 index 000000000..d0bd513e5 --- /dev/null +++ b/template/test-fixtures/parse-pp-keep.json @@ -0,0 +1,6 @@ +{ + "post-processors": [{ + "type": "foo", + "keep_input_artifact": true + }] +} diff --git a/template/test-fixtures/parse-pp-map.json b/template/test-fixtures/parse-pp-map.json new file mode 100644 index 000000000..43cc6abb8 --- /dev/null +++ b/template/test-fixtures/parse-pp-map.json @@ -0,0 +1,5 @@ +{ + "post-processors": [{ + "type": "foo" + }] +} diff --git a/template/test-fixtures/parse-pp-multi.json b/template/test-fixtures/parse-pp-multi.json new file mode 100644 index 000000000..32a60fa34 --- /dev/null +++ b/template/test-fixtures/parse-pp-multi.json @@ -0,0 +1,5 @@ +{ + "post-processors": [[{ + "type": "foo" + }, "bar"]] +} diff --git a/template/test-fixtures/parse-pp-no-type.json b/template/test-fixtures/parse-pp-no-type.json new file mode 100644 index 000000000..f4dda63e8 --- /dev/null +++ b/template/test-fixtures/parse-pp-no-type.json @@ -0,0 +1,5 @@ +{ + "post-processors": [{ + "keep_input_artifact": true + }] +} diff --git a/template/test-fixtures/parse-pp-slice.json b/template/test-fixtures/parse-pp-slice.json new file mode 100644 index 000000000..94c3a5247 --- /dev/null +++ b/template/test-fixtures/parse-pp-slice.json @@ -0,0 +1,5 @@ +{ + "post-processors": [{ + "type": "foo" + }, "bar"] +} diff --git a/template/test-fixtures/parse-pp-string.json b/template/test-fixtures/parse-pp-string.json new file mode 100644 index 000000000..8e77358ea --- /dev/null +++ b/template/test-fixtures/parse-pp-string.json @@ -0,0 +1,3 @@ +{ + "post-processors": ["foo"] +}