diff --git a/hcl2template/parser.go b/hcl2template/parser.go index 770c7209a..0bf4ce261 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -2,9 +2,6 @@ package hcl2template import ( "fmt" - "io/ioutil" - "path/filepath" - "strings" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclparse" @@ -37,39 +34,14 @@ type Parser struct { PostProcessorsSchemas packer.PostProcessorStore } -const hcl2FileExt = ".pkr.hcl" +const ( + hcl2FileExt = ".pkr.hcl" + hcl2JsonFileExt = ".pkr.json" +) func (p *Parser) parse(filename string) (*PackerConfig, hcl.Diagnostics) { - var diags hcl.Diagnostics - hclFiles := []string{} - jsonFiles := []string{} - if strings.HasSuffix(filename, hcl2FileExt) { - hclFiles = append(hclFiles, filename) - } else if strings.HasSuffix(filename, ".json") { - jsonFiles = append(jsonFiles, filename) - } else { - fileInfos, err := ioutil.ReadDir(filename) - if err != nil { - diag := &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Cannot read hcl directory", - Detail: err.Error(), - } - diags = append(diags, diag) - } - for _, fileInfo := range fileInfos { - if fileInfo.IsDir() { - continue - } - filename := filepath.Join(filename, fileInfo.Name()) - if strings.HasSuffix(filename, hcl2FileExt) { - hclFiles = append(hclFiles, filename) - } else if strings.HasSuffix(filename, ".json") { - jsonFiles = append(jsonFiles, filename) - } - } - } + hclFiles, jsonFiles, diags := GetHCL2Files(filename) var files []*hcl.File for _, filename := range hclFiles { diff --git a/hcl2template/testdata/build.pkr.hcl/basic.pkr.hcl b/hcl2template/testdata/build.pkr.hcl/basic.pkr.hcl new file mode 100644 index 000000000..34d84edb9 --- /dev/null +++ b/hcl2template/testdata/build.pkr.hcl/basic.pkr.hcl @@ -0,0 +1,125 @@ + +// starts resources to provision them. +build { + sources = [ + "source.amazon-ebs.ubuntu-1604", + "source.virtualbox-iso.ubuntu-1204", + ] + + provisioner "shell" { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + + nested { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + } + + nested_slice { + } + } + + provisioner "file" { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + + nested { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + } + + nested_slice { + } + } + + post-processor "amazon-import" { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + + nested { + string = "string" + int = 42 + int64 = 43 + bool = true + trilean = true + duration = "10s" + map_string_string { + a = "b" + c = "d" + } + slice_string = [ + "a", + "b", + "c", + ] + } + + nested_slice { + } + } +} diff --git a/hcl2template/types.build_test.go b/hcl2template/types.build_test.go index a852432ea..2a346c84c 100644 --- a/hcl2template/types.build_test.go +++ b/hcl2template/types.build_test.go @@ -21,7 +21,7 @@ func TestParse_build(t *testing.T) { Type: "amazon-ebs", Name: "ubuntu-1604", }, - ref, + refVBIsoUbuntu1204, }, ProvisionerBlocks: []*ProvisionerBlock{ { diff --git a/hcl2template/types.packer_config_test.go b/hcl2template/types.packer_config_test.go index b47ffba4a..0a04a49fb 100644 --- a/hcl2template/types.packer_config_test.go +++ b/hcl2template/types.packer_config_test.go @@ -6,7 +6,10 @@ import ( "github.com/hashicorp/packer/packer" ) -var ref = SourceRef{Type: "virtualbox-iso", Name: "ubuntu-1204"} +var ( + refVBIsoUbuntu1204 = SourceRef{Type: "virtualbox-iso", Name: "ubuntu-1204"} + refAWSEBSUbuntu1204 = SourceRef{Type: "amazon-ebs", Name: "ubuntu-1604"} +) func TestParser_complete(t *testing.T) { defaultParser := getBasicParser() @@ -17,11 +20,11 @@ func TestParser_complete(t *testing.T) { parseTestArgs{"testdata/complete"}, &PackerConfig{ Sources: map[SourceRef]*Source{ - ref: &Source{Type: "virtualbox-iso", Name: "ubuntu-1204"}, + refVBIsoUbuntu1204: &Source{Type: "virtualbox-iso", Name: "ubuntu-1204"}, }, Builds: Builds{ &BuildBlock{ - Froms: []SourceRef{ref}, + Froms: []SourceRef{refVBIsoUbuntu1204}, ProvisionerBlocks: []*ProvisionerBlock{ {PType: "shell"}, {PType: "file"}, @@ -50,6 +53,43 @@ func TestParser_complete(t *testing.T) { }, false, }, + {"dir with no config files", + defaultParser, + parseTestArgs{"testdata/"}, + nil, + true, true, + nil, + false, + }, + {name: "inexistent dir", + parser: defaultParser, + args: parseTestArgs{"testdata/inexistent"}, + parseWantCfg: nil, + parseWantDiags: true, + parseWantDiagHasErrors: true, + }, + {name: "folder named build.pkr.hcl with an unknown src", + parser: defaultParser, + args: parseTestArgs{"testdata/build.pkr.hcl"}, + parseWantCfg: &PackerConfig{ + Builds: Builds{ + &BuildBlock{ + Froms: []SourceRef{refAWSEBSUbuntu1204, refVBIsoUbuntu1204}, + ProvisionerBlocks: []*ProvisionerBlock{ + {PType: "shell"}, + {PType: "file"}, + }, + PostProcessors: []*PostProcessorBlock{ + {PType: "amazon-import"}, + }, + }, + }, + }, + parseWantDiags: false, + parseWantDiagHasErrors: false, + getBuildsWantBuilds: []packer.Build{}, + getBuildsWantDiags: true, + }, } testParse(t, tests) } diff --git a/hcl2template/utils.go b/hcl2template/utils.go index 6edb52447..52429321b 100644 --- a/hcl2template/utils.go +++ b/hcl2template/utils.go @@ -1,6 +1,13 @@ package hcl2template -import "github.com/hashicorp/hcl/v2" +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/hashicorp/hcl/v2" +) func warningErrorsToDiags(block *hcl.Block, warnings []string, err error) hcl.Diagnostics { var diags hcl.Diagnostics @@ -21,3 +28,63 @@ func warningErrorsToDiags(block *hcl.Block, warnings []string, err error) hcl.Di } return diags } + +func isDir(name string) (bool, error) { + s, err := os.Stat(name) + if err != nil { + return false, err + } + return s.IsDir(), nil +} + +func GetHCL2Files(filename string) (hclFiles, jsonFiles []string, diags hcl.Diagnostics) { + isDir, err := isDir(filename) + if err != nil { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Cannot tell wether " + filename + " is a directory", + Detail: err.Error(), + }) + return nil, nil, diags + } + if !isDir { + if strings.HasSuffix(filename, hcl2JsonFileExt) { + return nil, []string{filename}, diags + } + if strings.HasSuffix(filename, hcl2FileExt) { + return []string{filename}, nil, diags + } + } + + fileInfos, err := ioutil.ReadDir(filename) + if err != nil { + diag := &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Cannot read hcl directory", + Detail: err.Error(), + } + diags = append(diags, diag) + return nil, nil, diags + } + for _, fileInfo := range fileInfos { + if fileInfo.IsDir() { + continue + } + filename := filepath.Join(filename, fileInfo.Name()) + if strings.HasSuffix(filename, hcl2FileExt) { + hclFiles = append(hclFiles, filename) + } else if strings.HasSuffix(filename, hcl2JsonFileExt) { + jsonFiles = append(jsonFiles, filename) + } + } + if len(hclFiles)+len(jsonFiles) == 0 { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Could not find any config file in " + filename, + Detail: "A config file must be suffixed with `.pkr.hcl` or " + + "`.pkr.json`. A folder can be referenced.", + }) + } + + return hclFiles, jsonFiles, diags +}