Merge pull request #8874 from hashicorp/jbardin/json-hcl
Fix #8820 Regression in loading variables.tf.json from module
This commit is contained in:
commit
458e921dea
|
@ -327,6 +327,53 @@ func TestLoadJSONBasic(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLoadJSONAmbiguous(t *testing.T) {
|
||||
js := `
|
||||
{
|
||||
"variable": {
|
||||
"first": {
|
||||
"default": {
|
||||
"key": "val"
|
||||
}
|
||||
},
|
||||
"second": {
|
||||
"description": "Described",
|
||||
"default": {
|
||||
"key": "val"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
c, err := LoadJSON([]byte(js))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(c.Variables) != 2 {
|
||||
t.Fatal("config should have 2 variables, found", len(c.Variables))
|
||||
}
|
||||
|
||||
first := &Variable{
|
||||
Name: "first",
|
||||
Default: map[string]interface{}{"key": "val"},
|
||||
}
|
||||
second := &Variable{
|
||||
Name: "second",
|
||||
Description: "Described",
|
||||
Default: map[string]interface{}{"key": "val"},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(first, c.Variables[0]) {
|
||||
t.Fatalf("\nexpected: %#v\ngot: %#v", first, c.Variables[0])
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(second, c.Variables[1]) {
|
||||
t.Fatalf("\nexpected: %#v\ngot: %#v", second, c.Variables[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileBasic_jsonNoName(t *testing.T) {
|
||||
c, err := LoadFile(filepath.Join(fixtureDir, "resource-no-name.tf.json"))
|
||||
if err != nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ fmt: generate
|
|||
go fmt ./...
|
||||
|
||||
test: generate
|
||||
go get -t ./...
|
||||
go test $(TEST) $(TESTARGS)
|
||||
|
||||
generate:
|
||||
|
|
|
@ -12,5 +12,8 @@ install:
|
|||
go version
|
||||
|
||||
go env
|
||||
|
||||
go get -t ./...
|
||||
|
||||
build_script:
|
||||
- cmd: go test -v ./...
|
||||
|
|
|
@ -409,7 +409,6 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
|
|||
if result.Kind() == reflect.Interface {
|
||||
result = result.Elem()
|
||||
}
|
||||
|
||||
// Create the slice if it isn't nil
|
||||
resultType := result.Type()
|
||||
resultElemType := resultType.Elem()
|
||||
|
@ -443,6 +442,12 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
|
|||
|
||||
// Decode
|
||||
val := reflect.Indirect(reflect.New(resultElemType))
|
||||
|
||||
// if item is an object that was decoded from ambiguous JSON and
|
||||
// flattened, make sure it's expanded if it needs to decode into a
|
||||
// defined structure.
|
||||
item := expandObject(item, val)
|
||||
|
||||
if err := d.decode(fieldName, item, val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -455,6 +460,57 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
|
|||
return nil
|
||||
}
|
||||
|
||||
// expandObject detects if an ambiguous JSON object was flattened to a List which
|
||||
// should be decoded into a struct, and expands the ast to properly deocode.
|
||||
func expandObject(node ast.Node, result reflect.Value) ast.Node {
|
||||
item, ok := node.(*ast.ObjectItem)
|
||||
if !ok {
|
||||
return node
|
||||
}
|
||||
|
||||
elemType := result.Type()
|
||||
|
||||
// our target type must be a struct
|
||||
switch elemType.Kind() {
|
||||
case reflect.Ptr:
|
||||
switch elemType.Elem().Kind() {
|
||||
case reflect.Struct:
|
||||
//OK
|
||||
default:
|
||||
return node
|
||||
}
|
||||
case reflect.Struct:
|
||||
//OK
|
||||
default:
|
||||
return node
|
||||
}
|
||||
|
||||
// A list value will have a key and field name. If it had more fields,
|
||||
// it wouldn't have been flattened.
|
||||
if len(item.Keys) != 2 {
|
||||
return node
|
||||
}
|
||||
|
||||
keyToken := item.Keys[0].Token
|
||||
item.Keys = item.Keys[1:]
|
||||
|
||||
// we need to un-flatten the ast enough to decode
|
||||
newNode := &ast.ObjectItem{
|
||||
Keys: []*ast.ObjectKey{
|
||||
&ast.ObjectKey{
|
||||
Token: keyToken,
|
||||
},
|
||||
},
|
||||
Val: &ast.ObjectType{
|
||||
List: &ast.ObjectList{
|
||||
Items: []*ast.ObjectItem{item},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return newNode
|
||||
}
|
||||
|
||||
func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error {
|
||||
switch n := node.(type) {
|
||||
case *ast.LiteralType:
|
||||
|
@ -606,6 +662,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
|||
// match (only object with the field), then we decode it exactly.
|
||||
// If it is a prefix match, then we decode the matches.
|
||||
filter := list.Filter(fieldName)
|
||||
|
||||
prefixMatches := filter.Children()
|
||||
matches := filter.Elem()
|
||||
if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 {
|
||||
|
|
|
@ -1176,10 +1176,10 @@
|
|||
"revision": "7e3c02b30806fa5779d3bdfc152ce4c6f40e7b38"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "fa9G5tEr4oJJc3vtgn/B0NWZXfA=",
|
||||
"checksumSHA1": "8OPDk+bKyRGJoKcS4QNw9F7dpE8=",
|
||||
"path": "github.com/hashicorp/hcl",
|
||||
"revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e",
|
||||
"revisionTime": "2016-09-02T16:52:19Z"
|
||||
"revision": "ef8133da8cda503718a74741312bf50821e6de79",
|
||||
"revisionTime": "2016-09-16T13:01:00Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "67DfevLBglV52Y2eAuhFc/xQni0=",
|
||||
|
|
Loading…
Reference in New Issue