diff --git a/builder/amazon/chroot/builder.hcl2spec.go b/builder/amazon/chroot/builder.hcl2spec.go index bcd52bb91..130ab5dd8 100644 --- a/builder/amazon/chroot/builder.hcl2spec.go +++ b/builder/amazon/chroot/builder.hcl2spec.go @@ -120,7 +120,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, "vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())}, "ami_block_device_mappings": &hcldec.BlockListSpec{TypeName: "ami_block_device_mappings", Nested: hcldec.ObjectSpec((*common.FlatBlockDevice)(nil).HCL2Spec())}, - "chroot_mounts": &hcldec.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.String), Required: false}}, + "chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false}, "command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false}, "copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false}, "device_path": &hcldec.AttrSpec{Name: "device_path", Type: cty.String, Required: false}, diff --git a/builder/azure/chroot/builder.hcl2spec.go b/builder/azure/chroot/builder.hcl2spec.go index 50a42e314..8c11adb92 100644 --- a/builder/azure/chroot/builder.hcl2spec.go +++ b/builder/azure/chroot/builder.hcl2spec.go @@ -78,7 +78,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "mount_partition": &hcldec.AttrSpec{Name: "mount_partition", Type: cty.String, Required: false}, "mount_path": &hcldec.AttrSpec{Name: "mount_path", Type: cty.String, Required: false}, "post_mount_commands": &hcldec.AttrSpec{Name: "post_mount_commands", Type: cty.List(cty.String), Required: false}, - "chroot_mounts": &hcldec.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.String), Required: false}}, + "chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false}, "copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false}, "temporary_os_disk_name": &hcldec.AttrSpec{Name: "temporary_os_disk_name", Type: cty.String, Required: false}, "os_disk_size_gb": &hcldec.AttrSpec{Name: "os_disk_size_gb", Type: cty.Number, Required: false}, diff --git a/builder/hyperone/config.hcl2spec.go b/builder/hyperone/config.hcl2spec.go index 1fa450196..849e3080d 100644 --- a/builder/hyperone/config.hcl2spec.go +++ b/builder/hyperone/config.hcl2spec.go @@ -174,7 +174,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "chroot_disk_size": &hcldec.AttrSpec{Name: "chroot_disk_size", Type: cty.Number, Required: false}, "chroot_disk_type": &hcldec.AttrSpec{Name: "chroot_disk_type", Type: cty.String, Required: false}, "chroot_mount_path": &hcldec.AttrSpec{Name: "chroot_mount_path", Type: cty.String, Required: false}, - "chroot_mounts": &hcldec.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.String), Required: false}}, + "chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false}, "chroot_copy_files": &hcldec.AttrSpec{Name: "chroot_copy_files", Type: cty.List(cty.String), Required: false}, "chroot_command_wrapper": &hcldec.AttrSpec{Name: "chroot_command_wrapper", Type: cty.String, Required: false}, "mount_options": &hcldec.AttrSpec{Name: "mount_options", Type: cty.List(cty.String), Required: false}, diff --git a/builder/osc/chroot/builder.hcl2spec.go b/builder/osc/chroot/builder.hcl2spec.go index fc83b04b4..9892a3389 100644 --- a/builder/osc/chroot/builder.hcl2spec.go +++ b/builder/osc/chroot/builder.hcl2spec.go @@ -103,7 +103,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false}, "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, - "chroot_mounts": &hcldec.BlockListSpec{TypeName: "chroot_mounts", Nested: &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.String), Required: false}}, + "chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false}, "command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false}, "copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false}, "device_path": &hcldec.AttrSpec{Name: "device_path", Type: cty.String, Required: false}, diff --git a/builder/parallels/iso/builder.hcl2spec.go b/builder/parallels/iso/builder.hcl2spec.go index 32427635e..80e2eb76e 100644 --- a/builder/parallels/iso/builder.hcl2spec.go +++ b/builder/parallels/iso/builder.hcl2spec.go @@ -135,8 +135,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, "sound": &hcldec.AttrSpec{Name: "sound", Type: cty.Bool, Required: false}, "usb": &hcldec.AttrSpec{Name: "usb", Type: cty.Bool, Required: false}, - "prlctl": &hcldec.BlockListSpec{TypeName: "prlctl", Nested: &hcldec.AttrSpec{Name: "prlctl", Type: cty.List(cty.String), Required: false}}, - "prlctl_post": &hcldec.BlockListSpec{TypeName: "prlctl_post", Nested: &hcldec.AttrSpec{Name: "prlctl_post", Type: cty.List(cty.String), Required: false}}, + "prlctl": &hcldec.AttrSpec{Name: "prlctl", Type: cty.List(cty.List(cty.String)), Required: false}, + "prlctl_post": &hcldec.AttrSpec{Name: "prlctl_post", Type: cty.List(cty.List(cty.String)), Required: false}, "prlctl_version_file": &hcldec.AttrSpec{Name: "prlctl_version_file", Type: cty.String, Required: false}, "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false}, diff --git a/builder/parallels/pvm/config.hcl2spec.go b/builder/parallels/pvm/config.hcl2spec.go index 69c186fe0..a3f0bbb11 100644 --- a/builder/parallels/pvm/config.hcl2spec.go +++ b/builder/parallels/pvm/config.hcl2spec.go @@ -101,8 +101,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - "prlctl": &hcldec.BlockListSpec{TypeName: "prlctl", Nested: &hcldec.AttrSpec{Name: "prlctl", Type: cty.List(cty.String), Required: false}}, - "prlctl_post": &hcldec.BlockListSpec{TypeName: "prlctl_post", Nested: &hcldec.AttrSpec{Name: "prlctl_post", Type: cty.List(cty.String), Required: false}}, + "prlctl": &hcldec.AttrSpec{Name: "prlctl", Type: cty.List(cty.List(cty.String)), Required: false}, + "prlctl_post": &hcldec.AttrSpec{Name: "prlctl_post", Type: cty.List(cty.List(cty.String)), Required: false}, "prlctl_version_file": &hcldec.AttrSpec{Name: "prlctl_version_file", Type: cty.String, Required: false}, "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, diff --git a/builder/qemu/builder.hcl2spec.go b/builder/qemu/builder.hcl2spec.go index 5e08510d7..6e296846e 100644 --- a/builder/qemu/builder.hcl2spec.go +++ b/builder/qemu/builder.hcl2spec.go @@ -210,7 +210,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, "net_device": &hcldec.AttrSpec{Name: "net_device", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - "qemuargs": &hcldec.BlockListSpec{TypeName: "qemuargs", Nested: &hcldec.AttrSpec{Name: "qemuargs", Type: cty.List(cty.String), Required: false}}, + "qemuargs": &hcldec.AttrSpec{Name: "qemuargs", Type: cty.List(cty.List(cty.String)), Required: false}, "qemu_binary": &hcldec.AttrSpec{Name: "qemu_binary", Type: cty.String, Required: false}, "qmp_enable": &hcldec.AttrSpec{Name: "qmp_enable", Type: cty.Bool, Required: false}, "qmp_socket_path": &hcldec.AttrSpec{Name: "qmp_socket_path", Type: cty.String, Required: false}, diff --git a/builder/virtualbox/iso/builder.hcl2spec.go b/builder/virtualbox/iso/builder.hcl2spec.go index cd4f3f0e8..fbd8342b6 100644 --- a/builder/virtualbox/iso/builder.hcl2spec.go +++ b/builder/virtualbox/iso/builder.hcl2spec.go @@ -215,8 +215,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, "sound": &hcldec.AttrSpec{Name: "sound", Type: cty.String, Required: false}, "usb": &hcldec.AttrSpec{Name: "usb", Type: cty.Bool, Required: false}, - "vboxmanage": &hcldec.BlockListSpec{TypeName: "vboxmanage", Nested: &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.String), Required: false}}, - "vboxmanage_post": &hcldec.BlockListSpec{TypeName: "vboxmanage_post", Nested: &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.String), Required: false}}, + "vboxmanage": &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.List(cty.String)), Required: false}, + "vboxmanage_post": &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.List(cty.String)), Required: false}, "virtualbox_version_file": &hcldec.AttrSpec{Name: "virtualbox_version_file", Type: cty.String, Required: false}, "bundle_iso": &hcldec.AttrSpec{Name: "bundle_iso", Type: cty.Bool, Required: false}, "guest_additions_mode": &hcldec.AttrSpec{Name: "guest_additions_mode", Type: cty.String, Required: false}, diff --git a/builder/virtualbox/ovf/config.hcl2spec.go b/builder/virtualbox/ovf/config.hcl2spec.go index 29ee23cb2..c8be73d84 100644 --- a/builder/virtualbox/ovf/config.hcl2spec.go +++ b/builder/virtualbox/ovf/config.hcl2spec.go @@ -190,8 +190,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "post_shutdown_delay": &hcldec.AttrSpec{Name: "post_shutdown_delay", Type: cty.String, Required: false}, "disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false}, "acpi_shutdown": &hcldec.AttrSpec{Name: "acpi_shutdown", Type: cty.Bool, Required: false}, - "vboxmanage": &hcldec.BlockListSpec{TypeName: "vboxmanage", Nested: &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.String), Required: false}}, - "vboxmanage_post": &hcldec.BlockListSpec{TypeName: "vboxmanage_post", Nested: &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.String), Required: false}}, + "vboxmanage": &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.List(cty.String)), Required: false}, + "vboxmanage_post": &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.List(cty.String)), Required: false}, "virtualbox_version_file": &hcldec.AttrSpec{Name: "virtualbox_version_file", Type: cty.String, Required: false}, "guest_additions_mode": &hcldec.AttrSpec{Name: "guest_additions_mode", Type: cty.String, Required: false}, "checksum": &hcldec.AttrSpec{Name: "checksum", Type: cty.String, Required: false}, diff --git a/builder/virtualbox/vm/config.hcl2spec.go b/builder/virtualbox/vm/config.hcl2spec.go index 469e6cbbb..7e68db5ad 100644 --- a/builder/virtualbox/vm/config.hcl2spec.go +++ b/builder/virtualbox/vm/config.hcl2spec.go @@ -186,8 +186,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "post_shutdown_delay": &hcldec.AttrSpec{Name: "post_shutdown_delay", Type: cty.String, Required: false}, "disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false}, "acpi_shutdown": &hcldec.AttrSpec{Name: "acpi_shutdown", Type: cty.Bool, Required: false}, - "vboxmanage": &hcldec.BlockListSpec{TypeName: "vboxmanage", Nested: &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.String), Required: false}}, - "vboxmanage_post": &hcldec.BlockListSpec{TypeName: "vboxmanage_post", Nested: &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.String), Required: false}}, + "vboxmanage": &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.List(cty.String)), Required: false}, + "vboxmanage_post": &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.List(cty.String)), Required: false}, "virtualbox_version_file": &hcldec.AttrSpec{Name: "virtualbox_version_file", Type: cty.String, Required: false}, "guest_additions_mode": &hcldec.AttrSpec{Name: "guest_additions_mode", Type: cty.String, Required: false}, "guest_additions_path": &hcldec.AttrSpec{Name: "guest_additions_path", Type: cty.String, Required: false}, diff --git a/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go b/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go index 3c890b836..8ecd09e55 100644 --- a/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go +++ b/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go @@ -201,6 +201,10 @@ type StructDef struct { Struct *types.Struct } +// outputStructHCL2SpecBody writes the map[string]hcldec.Spec that defines the HCL spec of a +// struct. Based on the layout of said struct. +// If a field of s is a struct then the HCL2Spec() function of that struct will be called, otherwise a +// cty.Type is outputed. func outputStructHCL2SpecBody(w io.Writer, s *types.Struct) { fmt.Fprintf(w, "s := map[string]hcldec.Spec{\n") @@ -217,72 +221,99 @@ func outputStructHCL2SpecBody(w io.Writer, s *types.Struct) { fmt.Fprintln(w, `return s`) } +// outputHCL2SpecField is called on each field of a struct. +// outputHCL2SpecField writes the values of the `map[string]hcldec.Spec` map +// supposed to define the HCL spec of a struct. func outputHCL2SpecField(w io.Writer, accessor string, fieldType types.Type, tag *structtag.Tags) { if m2h, err := tag.Get(""); err == nil && m2h.HasOption("self-defined") { fmt.Fprintf(w, `(&%s{}).HCL2Spec()`, fieldType.String()) return } + spec, _ := writeSpecField(accessor, fieldType) + switch spec := spec.(type) { + case string: + fmt.Fprintf(w, spec) + default: + fmt.Fprintf(w, `%#v`, spec) + } + +} + +// goFieldToCtyType is a recursive method that returns a cty.Type (or a string) based on the fieldType. +// goFieldToCtyType returns the values of the `map[string]hcldec.Spec` map +// supposed to define the HCL spec of a struct. +// To allow it to be recursive, the method returns two values: an interface that can either be +// a cty.Type or a string. The second argument is used for recursion and is the +// type that will be used by the parent. For example when fieldType is a []string; a +// recursive goFieldToCtyType call will return a cty.String. +func writeSpecField(accessor string, fieldType types.Type) (interface{}, cty.Type) { switch f := fieldType.(type) { case *types.Pointer: - outputHCL2SpecField(w, accessor, f.Elem(), tag) + return writeSpecField(accessor, f.Elem()) case *types.Basic: - fmt.Fprintf(w, `%#v`, &hcldec.AttrSpec{ + ctyType := basicKindToCtyType(f.Kind()) + return &hcldec.AttrSpec{ Name: accessor, - Type: basicKindToCtyType(f.Kind()), + Type: ctyType, Required: false, - }) + }, ctyType case *types.Map: - fmt.Fprintf(w, `%#v`, &hcldec.BlockAttrsSpec{ + return &hcldec.BlockAttrsSpec{ TypeName: accessor, ElementType: cty.String, // for now everything can be simplified to a map[string]string Required: false, - }) + }, cty.Map(cty.String) + case *types.Named: + // Named is the relative type when of a field with a struct. + // E.g. SourceAmiFilter *common.FlatAmiFilterOptions + // SourceAmiFilter will become a block with nested elements from the struct itself. + underlyingType := f.Underlying() + switch underlyingType.(type) { + case *types.Struct: + // A struct returns NilType because its HCL2Spec is written in the related file + // and we don't need to write it again. + return fmt.Sprintf(`&hcldec.BlockSpec{TypeName: "%s",`+ + ` Nested: hcldec.ObjectSpec((*%s)(nil).HCL2Spec())}`, accessor, f.String()), cty.NilType + default: + return writeSpecField(accessor, underlyingType) + } case *types.Slice: elem := f.Elem() if ptr, isPtr := elem.(*types.Pointer); isPtr { elem = ptr.Elem() } switch elem := elem.(type) { - case *types.Basic: - fmt.Fprintf(w, `%#v`, &hcldec.AttrSpec{ - Name: accessor, - Type: cty.List(basicKindToCtyType(elem.Kind())), - Required: false, - }) case *types.Named: + // A Slice of Named is the relative type of a filed with a slice of structs. + // E.g. LaunchMappings []common.FlatBlockDevice + // LaunchMappings will validate more than one block with nested elements. b := bytes.NewBuffer(nil) underlyingType := elem.Underlying() switch underlyingType.(type) { case *types.Struct: fmt.Fprintf(b, `hcldec.ObjectSpec((*%s)(nil).HCL2Spec())`, elem.String()) - default: - outputHCL2SpecField(b, accessor, elem, tag) } - fmt.Fprintf(w, `&hcldec.BlockListSpec{TypeName: "%s", Nested: %s}`, accessor, b.String()) - case *types.Slice: - b := bytes.NewBuffer(nil) - outputHCL2SpecField(b, accessor, elem.Underlying(), tag) - fmt.Fprintf(w, `&hcldec.BlockListSpec{TypeName: "%s", Nested: %s}`, accessor, b.String()) - default: - outputHCL2SpecField(w, accessor, elem.Underlying(), tag) - } - case *types.Named: - underlyingType := f.Underlying() - switch underlyingType.(type) { - case *types.Struct: - fmt.Fprintf(w, `&hcldec.BlockSpec{TypeName: "%s",`+ - ` Nested: hcldec.ObjectSpec((*%s)(nil).HCL2Spec())}`, accessor, f.String()) + return fmt.Sprintf(`&hcldec.BlockListSpec{TypeName: "%s", Nested: %s}`, accessor, b.String()), cty.NilType default: - outputHCL2SpecField(w, accessor, underlyingType, tag) + _, specType := writeSpecField(accessor, elem) + if specType == cty.NilType { + return writeSpecField(accessor, elem.Underlying()) + } + return &hcldec.AttrSpec{ + Name: accessor, + Type: cty.List(specType), + Required: false, + }, cty.List(specType) } - default: - fmt.Fprintf(w, `%#v`, &hcldec.AttrSpec{ - Name: accessor, - Type: basicKindToCtyType(types.Bool), - Required: false, - }) - fmt.Fprintf(w, `/* TODO(azr): could not find type */`) } + b := bytes.NewBuffer(nil) + fmt.Fprintf(b, `%#v`, &hcldec.AttrSpec{ + Name: accessor, + Type: basicKindToCtyType(types.Bool), + Required: false, + }) + fmt.Fprintf(b, `/* TODO(azr): could not find type */`) + return b.String(), cty.NilType } func basicKindToCtyType(kind types.BasicKind) cty.Type { diff --git a/hcl2template/common_test.go b/hcl2template/common_test.go index 474faa88c..c26d1c0db 100644 --- a/hcl2template/common_test.go +++ b/hcl2template/common_test.go @@ -194,6 +194,10 @@ var ( "b", "c", }, + SliceSliceString: [][]string{ + {"a", "b"}, + {"c", "d"}, + }, } basicMockBuilder = &MockBuilder{ diff --git a/hcl2template/mock.go b/hcl2template/mock.go index 1386eb8b7..071cfe157 100644 --- a/hcl2template/mock.go +++ b/hcl2template/mock.go @@ -20,6 +20,7 @@ type NestedMockConfig struct { Duration time.Duration `mapstructure:"duration"` MapStringString map[string]string `mapstructure:"map_string_string"` SliceString []string `mapstructure:"slice_string"` + SliceSliceString [][]string `mapstructure:"slice_slice_string"` NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string"` NamedString NamedString `mapstructure:"named_string"` } diff --git a/hcl2template/mock.hcl2spec.go b/hcl2template/mock.hcl2spec.go index c5508c9bb..d2ee8b0f4 100644 --- a/hcl2template/mock.hcl2spec.go +++ b/hcl2template/mock.hcl2spec.go @@ -17,6 +17,7 @@ type FlatMockConfig struct { Duration *string `mapstructure:"duration" cty:"duration"` MapStringString map[string]string `mapstructure:"map_string_string" cty:"map_string_string"` SliceString []string `mapstructure:"slice_string" cty:"slice_string"` + SliceSliceString [][]string `mapstructure:"slice_slice_string" cty:"slice_slice_string"` NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string" cty:"named_map_string_string"` NamedString *NamedString `mapstructure:"named_string" cty:"named_string"` Nested *FlatNestedMockConfig `mapstructure:"nested" cty:"nested"` @@ -43,6 +44,7 @@ func (*FlatMockConfig) HCL2Spec() map[string]hcldec.Spec { "duration": &hcldec.AttrSpec{Name: "duration", Type: cty.String, Required: false}, "map_string_string": &hcldec.BlockAttrsSpec{TypeName: "map_string_string", ElementType: cty.String, Required: false}, "slice_string": &hcldec.AttrSpec{Name: "slice_string", Type: cty.List(cty.String), Required: false}, + "slice_slice_string": &hcldec.AttrSpec{Name: "slice_slice_string", Type: cty.List(cty.List(cty.String)), Required: false}, "named_map_string_string": &hcldec.BlockAttrsSpec{TypeName: "named_map_string_string", ElementType: cty.String, Required: false}, "named_string": &hcldec.AttrSpec{Name: "named_string", Type: cty.String, Required: false}, "nested": &hcldec.BlockSpec{TypeName: "nested", Nested: hcldec.ObjectSpec((*FlatNestedMockConfig)(nil).HCL2Spec())}, @@ -62,6 +64,7 @@ type FlatNestedMockConfig struct { Duration *string `mapstructure:"duration" cty:"duration"` MapStringString map[string]string `mapstructure:"map_string_string" cty:"map_string_string"` SliceString []string `mapstructure:"slice_string" cty:"slice_string"` + SliceSliceString [][]string `mapstructure:"slice_slice_string" cty:"slice_slice_string"` NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string" cty:"named_map_string_string"` NamedString *NamedString `mapstructure:"named_string" cty:"named_string"` } @@ -86,6 +89,7 @@ func (*FlatNestedMockConfig) HCL2Spec() map[string]hcldec.Spec { "duration": &hcldec.AttrSpec{Name: "duration", Type: cty.String, Required: false}, "map_string_string": &hcldec.BlockAttrsSpec{TypeName: "map_string_string", ElementType: cty.String, Required: false}, "slice_string": &hcldec.AttrSpec{Name: "slice_string", Type: cty.List(cty.String), Required: false}, + "slice_slice_string": &hcldec.AttrSpec{Name: "slice_slice_string", Type: cty.List(cty.List(cty.String)), Required: false}, "named_map_string_string": &hcldec.BlockAttrsSpec{TypeName: "named_map_string_string", ElementType: cty.String, Required: false}, "named_string": &hcldec.AttrSpec{Name: "named_string", Type: cty.String, Required: false}, } diff --git a/hcl2template/testdata/build/basic.pkr.hcl b/hcl2template/testdata/build/basic.pkr.hcl index 34d84edb9..5c598ebc0 100644 --- a/hcl2template/testdata/build/basic.pkr.hcl +++ b/hcl2template/testdata/build/basic.pkr.hcl @@ -22,6 +22,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -39,6 +43,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -61,6 +69,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -78,6 +90,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -100,6 +116,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -117,6 +137,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { diff --git a/hcl2template/testdata/complete/build.pkr.hcl b/hcl2template/testdata/complete/build.pkr.hcl index bd84d42fd..7470b8091 100644 --- a/hcl2template/testdata/complete/build.pkr.hcl +++ b/hcl2template/testdata/complete/build.pkr.hcl @@ -22,6 +22,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -39,6 +43,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -61,6 +69,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -78,6 +90,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -101,6 +117,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -118,6 +138,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -140,6 +164,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -157,6 +185,10 @@ build { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { diff --git a/hcl2template/testdata/complete/sources.pkr.hcl b/hcl2template/testdata/complete/sources.pkr.hcl index b95308b5a..dcb14dd04 100644 --- a/hcl2template/testdata/complete/sources.pkr.hcl +++ b/hcl2template/testdata/complete/sources.pkr.hcl @@ -14,6 +14,10 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -31,6 +35,10 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -49,6 +57,10 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -67,5 +79,9 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } } \ No newline at end of file diff --git a/hcl2template/testdata/sources/basic.pkr.hcl b/hcl2template/testdata/sources/basic.pkr.hcl index 58d3164e5..c0e0113c3 100644 --- a/hcl2template/testdata/sources/basic.pkr.hcl +++ b/hcl2template/testdata/sources/basic.pkr.hcl @@ -15,6 +15,10 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] nested { string = "string" @@ -32,6 +36,10 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -50,6 +58,10 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } nested_slice { @@ -68,5 +80,9 @@ source "virtualbox-iso" "ubuntu-1204" { "b", "c", ] + slice_slice_string = [ + ["a","b"], + ["c","d"] + ] } } \ No newline at end of file