hashicorp / hcl

HCL is the HashiCorp configuration language.
Mozilla Public License 2.0
5.24k stars 591 forks source link

gohcl: Composition of types is not supported #290

Open VoyTechnology opened 5 years ago

VoyTechnology commented 5 years ago

Issue description

When using composition of a Go structures, the HCL cannot be parsed using gohcl.

Steps to reproduce the issue

  1. Sample code file:
    
    package main

import ( "encoding/json" "fmt"

"github.com/hashicorp/hcl2/gohcl"
"github.com/hashicorp/hcl2/hclparse"

)

type File struct { A A hcl:"a,block" json:"a" }

type A struct { B }

type B struct { Foo string json:"foo" hcl:"foo" }

var hclBody = []byte( a { foo = "bar" } )

var jsonBody = []byte( { "a":{ "foo":"bar" } })

func main() { // JSON var j File if err := json.Unmarshal(jsonBody, &j); err != nil { fmt.Println("json.Unmarshal:", err) return } js, _ := json.MarshalIndent(j, "", "\t") fmt.Println(string(js))

// HCL
p := hclparse.NewParser()
f, err := p.ParseHCL(hclBody, "test.hcl")
if err != nil {
    fmt.Println("p.ParseHCL:", err)
    return
}

var h File
if err := gohcl.DecodeBody(f.Body, nil, &h); err != nil {
    fmt.Println("gohcl.DecodeBody:", err)
    return
}
hs, _ := json.MarshalIndent(h, "", "\t")
fmt.Println(string(hs))

}

2. Run the file to see the given error
3. Move the `Foo string` from `B` into `A`
4. Run the file again to see the file working

### What's the expected result

The file is correctly parsed as if `Foo string` from `B` was in `A`, just like its the case with JSON

Output after doing step `3`:
```json
{
    "a": {
        "foo": "bar"
    }
}
{
    "a": {
        "foo": "bar"
    }
}

What's the actual result

Error is being thrown

{
    "a": {
        "foo": "bar"
    }
}
gohcl.DecodeBody: test.hcl:3,2-5: Unsupported argument; An argument named "foo" is not expected here.

Additional details

apparentlymart commented 5 years ago

Hi @VoyTechnology! Thanks for reporting this.

gohcl currently intentionally ignores any field that doesn't have a hcl: struct tag on it, so this behavior is consistent with that decision, but I agree that it could be useful to make an exception in this case to treat an embedded struct as if its fields were just inline in the embedder.

I expect we will not have time to work on this in the near future, but if you have the time and motivation to work on it I'd be happy to review a pull request.