From a5d417867b1e5c031384571315f8b53666b07eb0 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 10 Jan 2020 13:25:49 +0100 Subject: [PATCH] WIP --- hcl2template/common_test.go | 14 +++- hcl2template/parser.go | 14 ++-- .../testdata/complete/variables.pkr.hcl | 15 ++++ hcl2template/testdata/variables/basic.pkr.hcl | 15 ++++ hcl2template/types.packer_config.go | 4 +- hcl2template/types.packer_config_test.go | 8 ++- hcl2template/types.variables.go | 71 ++++++++++++++++++- hcl2template/types.variables_test.go | 12 ++-- 8 files changed, 131 insertions(+), 22 deletions(-) diff --git a/hcl2template/common_test.go b/hcl2template/common_test.go index 74f30c2e68b..87ca16d3db0 100644 --- a/hcl2template/common_test.go +++ b/hcl2template/common_test.go @@ -62,7 +62,14 @@ func testParse(t *testing.T, tests []parseTest) { t.Fatalf("Parser.parse() unexpected diagnostics HasErrors. %s", gotDiags) } if diff := cmp.Diff(tt.parseWantCfg, gotCfg, - cmpopts.IgnoreUnexported(cty.Value{}, Source{}, ProvisionerBlock{}, PostProcessorBlock{}), + cmpopts.IgnoreUnexported( + cty.Value{}, + cty.Type{}, + Variable{}, + Source{}, + ProvisionerBlock{}, + PostProcessorBlock{}, + ), cmpopts.IgnoreTypes(HCL2Ref{}), cmpopts.IgnoreTypes([]hcl.Range{}), cmpopts.IgnoreTypes(hcl.Range{}), @@ -80,7 +87,10 @@ func testParse(t *testing.T, tests []parseTest) { t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags) } if diff := cmp.Diff(tt.getBuildsWantBuilds, gotBuilds, - cmpopts.IgnoreUnexported(packer.CoreBuild{}, + cmpopts.IgnoreUnexported( + cty.Value{}, + cty.Type{}, + packer.CoreBuild{}, packer.CoreBuildProvisioner{}, packer.CoreBuildPostProcessor{}, ), diff --git a/hcl2template/parser.go b/hcl2template/parser.go index b79c8e3bb16..59e6d7af84b 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -11,6 +11,7 @@ import ( const ( sourceLabel = "source" variablesLabel = "variables" + variableLabel = "variable" buildLabel = "build" communicatorLabel = "communicator" ) @@ -19,6 +20,7 @@ var configSchema = &hcl.BodySchema{ Blocks: []hcl.BlockHeaderSchema{ {Type: sourceLabel, LabelNames: []string{"type", "name"}}, {Type: variablesLabel}, + {Type: variableLabel, LabelNames: []string{"name"}}, {Type: buildLabel}, {Type: communicatorLabel, LabelNames: []string{"type", "name"}}, }, @@ -108,15 +110,13 @@ func (p *Parser) parseFile(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics { } cfg.Sources[ref] = source - case variablesLabel: - if cfg.Variables == nil { - cfg.Variables = PackerV1Variables{} - } + case variableLabel: moreDiags := cfg.Variables.decodeConfig(block) - if moreDiags.HasErrors() { - continue - } + diags = append(diags, moreDiags...) + + case variablesLabel: + moreDiags := cfg.Variables.decodeConfigMap(block) diags = append(diags, moreDiags...) case buildLabel: diff --git a/hcl2template/testdata/complete/variables.pkr.hcl b/hcl2template/testdata/complete/variables.pkr.hcl index e2d6141008c..67b1962b41e 100644 --- a/hcl2template/testdata/complete/variables.pkr.hcl +++ b/hcl2template/testdata/complete/variables.pkr.hcl @@ -4,3 +4,18 @@ variables { // my_secret = "foo" // image_name = "foo-image-{{user `my_secret`}}" } + +variable "image_id" { + type = string + default = "image-id-default" +} + +variable "port" { + type = number + default = 42 +} + +variable "availability_zone_names" { + type = list(string) + default = ["us-west-1a"] +} diff --git a/hcl2template/testdata/variables/basic.pkr.hcl b/hcl2template/testdata/variables/basic.pkr.hcl index d4e6512478b..53598d5f209 100644 --- a/hcl2template/testdata/variables/basic.pkr.hcl +++ b/hcl2template/testdata/variables/basic.pkr.hcl @@ -4,3 +4,18 @@ variables { my_secret = "foo" image_name = "foo-image-{{user `my_secret`}}" } + +variable "image_id" { + type = string + default = "image-id-default" +} + +variable "port" { + type = number + default = 42 +} + +variable "availability_zone_names" { + type = list(string) + default = ["us-west-1a"] +} diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index dc3b1b240c4..b7ec513fa2a 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -10,7 +10,7 @@ import ( type PackerConfig struct { Sources map[SourceRef]*Source - Variables PackerV1Variables + Variables Variables Builds Builds } @@ -56,7 +56,7 @@ func (p *Parser) getBuilds(cfg *PackerConfig) ([]packer.Build, hcl.Diagnostics) ectx := &hcl.EvalContext{ Variables: map[string]cty.Value{ - "var": cty.ObjectVal(cfg.Variables), + "var": cty.ObjectVal(cfg.Variables.Values()), }, } diff --git a/hcl2template/types.packer_config_test.go b/hcl2template/types.packer_config_test.go index 6bf56993e38..81cdd2dd4d5 100644 --- a/hcl2template/types.packer_config_test.go +++ b/hcl2template/types.packer_config_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/hashicorp/packer/packer" - "github.com/zclconf/go-cty/cty" ) var ( @@ -20,8 +19,11 @@ func TestParser_complete(t *testing.T) { defaultParser, parseTestArgs{"testdata/complete"}, &PackerConfig{ - Variables: PackerV1Variables{ - "foo": cty.StringVal("value"), + Variables: Variables{ + "foo": Variable{}, + "image_id": Variable{}, + "port": Variable{}, + "availability_zone_names": Variable{}, }, Sources: map[SourceRef]*Source{ refVBIsoUbuntu1204: &Source{Type: "virtualbox-iso", Name: "ubuntu-1204"}, diff --git a/hcl2template/types.variables.go b/hcl2template/types.variables.go index dce550f4fdb..cc95c5aba6b 100644 --- a/hcl2template/types.variables.go +++ b/hcl2template/types.variables.go @@ -2,13 +2,36 @@ package hcl2template import ( "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/ext/typeexpr" "github.com/zclconf/go-cty/cty" ) -type PackerV1Variables map[string]cty.Value +type Variable struct { + Default cty.Value + Type cty.Type + + block *hcl.Block +} + +func (v *Variable) Value() cty.Value { + return v.Default +} + +type Variables map[string]Variable + +func (variables Variables) Values() map[string]cty.Value { + res := map[string]cty.Value{} + for k, v := range variables { + res[k] = v.Value() + } + return res +} // decodeConfig decodes a "variables" section the way packer 1 used to -func (variables *PackerV1Variables) decodeConfig(block *hcl.Block) hcl.Diagnostics { +func (variables *Variables) decodeConfigMap(block *hcl.Block) hcl.Diagnostics { + if (*variables) == nil { + (*variables) = Variables{} + } attrs, diags := block.Body.JustAttributes() if diags.HasErrors() { @@ -31,8 +54,50 @@ func (variables *PackerV1Variables) decodeConfig(block *hcl.Block) hcl.Diagnosti if moreDiags.HasErrors() { continue } - (*variables)[key] = value + (*variables)[key] = Variable{ + Default: value, + Type: value.Type(), + } + } + + return diags +} + +// decodeConfig decodes a "variables" section the way packer 1 used to +func (variables *Variables) decodeConfig(block *hcl.Block) hcl.Diagnostics { + if (*variables) == nil { + (*variables) = Variables{} + } + + attrs, diags := block.Body.JustAttributes() + + if diags.HasErrors() { + return diags + } + + res := Variable{ + block: block, + } + if def, ok := attrs["default"]; ok { + defaultValue, moreDiags := def.Expr.Value(nil) + diags = append(diags, moreDiags...) + if moreDiags.HasErrors() { + return diags + } + res.Default = defaultValue + res.Type = defaultValue.Type() + } + if t, ok := attrs["type"]; ok { + tp, moreDiags := typeexpr.Type(t.Expr) + diags = append(diags, moreDiags...) + if moreDiags.HasErrors() { + return diags + } + + res.Type = tp } + (*variables)[block.Labels[0]] = res + return diags } diff --git a/hcl2template/types.variables_test.go b/hcl2template/types.variables_test.go index 80c50f33cfc..01bdfbf3bbc 100644 --- a/hcl2template/types.variables_test.go +++ b/hcl2template/types.variables_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/hashicorp/packer/packer" - "github.com/zclconf/go-cty/cty" ) func TestParse_variables(t *testing.T) { @@ -15,10 +14,13 @@ func TestParse_variables(t *testing.T) { defaultParser, parseTestArgs{"testdata/variables/basic.pkr.hcl"}, &PackerConfig{ - Variables: PackerV1Variables{ - "image_name": cty.StringVal("foo-image-{{user `my_secret`}}"), - "key": cty.StringVal("value"), - "my_secret": cty.StringVal("foo"), + Variables: Variables{ + "image_name": Variable{}, + "key": Variable{}, + "my_secret": Variable{}, + "image_id": Variable{}, + "port": Variable{}, + "availability_zone_names": Variable{}, }, }, false, false,