Merge pull request #412 from hashicorp/mitchellh/body
"body" struct tag to capture entire body for a block decode
This commit is contained in:
commit
3de61ecba2
@ -65,6 +65,19 @@ func decodeBodyToStruct(body hcl.Body, ctx *hcl.EvalContext, val reflect.Value)
|
|||||||
|
|
||||||
tags := getFieldTags(val.Type())
|
tags := getFieldTags(val.Type())
|
||||||
|
|
||||||
|
if tags.Body != nil {
|
||||||
|
fieldIdx := *tags.Body
|
||||||
|
field := val.Type().Field(fieldIdx)
|
||||||
|
fieldV := val.Field(fieldIdx)
|
||||||
|
switch {
|
||||||
|
case bodyType.AssignableTo(field.Type):
|
||||||
|
fieldV.Set(reflect.ValueOf(body))
|
||||||
|
|
||||||
|
default:
|
||||||
|
diags = append(diags, decodeBodyToValue(body, ctx, fieldV)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if tags.Remain != nil {
|
if tags.Remain != nil {
|
||||||
fieldIdx := *tags.Remain
|
fieldIdx := *tags.Remain
|
||||||
field := val.Type().Field(fieldIdx)
|
field := val.Type().Field(fieldIdx)
|
||||||
|
@ -217,6 +217,30 @@ func TestDecodeBody(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "Ermintrude",
|
||||||
|
"age": 50,
|
||||||
|
},
|
||||||
|
makeInstantiateType(struct {
|
||||||
|
Name string `hcl:"name"`
|
||||||
|
Body hcl.Body `hcl:",body"`
|
||||||
|
Remain hcl.Body `hcl:",remain"`
|
||||||
|
}{}),
|
||||||
|
func(gotI interface{}) bool {
|
||||||
|
got := gotI.(struct {
|
||||||
|
Name string `hcl:"name"`
|
||||||
|
Body hcl.Body `hcl:",body"`
|
||||||
|
Remain hcl.Body `hcl:",remain"`
|
||||||
|
})
|
||||||
|
|
||||||
|
attrs, _ := got.Body.JustAttributes()
|
||||||
|
|
||||||
|
return got.Name == "Ermintrude" && len(attrs) == 2 &&
|
||||||
|
attrs["name"] != nil && attrs["age"] != nil
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"noodle": map[string]interface{}{},
|
"noodle": map[string]interface{}{},
|
||||||
|
@ -30,6 +30,13 @@
|
|||||||
// in which case multiple blocks of the corresponding type are decoded into
|
// in which case multiple blocks of the corresponding type are decoded into
|
||||||
// the slice.
|
// the slice.
|
||||||
//
|
//
|
||||||
|
// "body" can be placed on a single field of type hcl.Body to capture
|
||||||
|
// the full hcl.Body that was decoded for a block. This does not allow leftover
|
||||||
|
// values like "remain", so a decoding error will still be returned if leftover
|
||||||
|
// fields are given. If you want to capture the decoding body PLUS leftover
|
||||||
|
// fields, you must specify a "remain" field as well to prevent errors. The
|
||||||
|
// body field and the remain field will both contain the leftover fields.
|
||||||
|
//
|
||||||
// "label" fields are considered only in a struct used as the type of a field
|
// "label" fields are considered only in a struct used as the type of a field
|
||||||
// marked as "block", and are used sequentially to capture the labels of
|
// marked as "block", and are used sequentially to capture the labels of
|
||||||
// the blocks being decoded. In this case, the name token is used only as
|
// the blocks being decoded. In this case, the name token is used only as
|
||||||
|
@ -113,6 +113,7 @@ type fieldTags struct {
|
|||||||
Blocks map[string]int
|
Blocks map[string]int
|
||||||
Labels []labelField
|
Labels []labelField
|
||||||
Remain *int
|
Remain *int
|
||||||
|
Body *int
|
||||||
Optional map[string]bool
|
Optional map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +163,12 @@ func getFieldTags(ty reflect.Type) *fieldTags {
|
|||||||
}
|
}
|
||||||
idx := i // copy, because this loop will continue assigning to i
|
idx := i // copy, because this loop will continue assigning to i
|
||||||
ret.Remain = &idx
|
ret.Remain = &idx
|
||||||
|
case "body":
|
||||||
|
if ret.Body != nil {
|
||||||
|
panic("only one 'body' tag is permitted")
|
||||||
|
}
|
||||||
|
idx := i // copy, because this loop will continue assigning to i
|
||||||
|
ret.Body = &idx
|
||||||
case "optional":
|
case "optional":
|
||||||
ret.Attributes[name] = i
|
ret.Attributes[name] = i
|
||||||
ret.Optional[name] = true
|
ret.Optional[name] = true
|
||||||
|
Loading…
Reference in New Issue
Block a user