gohcl: Decode missing hcl.Expression as a cty Null
Rather than writing a nil hcl.Expression, as a special case we'll deal with this within the cty type system, which we assume is what the caller wants if they are decoding into a hcl.Expression rather than a native Go type.
This commit is contained in:
parent
339b9cfc34
commit
f44382c4fa
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/hcl2/hcl"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
"github.com/zclconf/go-cty/cty/gocty"
|
||||
@ -81,11 +83,25 @@ func decodeBodyToStruct(body hcl.Body, ctx *hcl.EvalContext, val reflect.Value)
|
||||
}
|
||||
}
|
||||
|
||||
for name, attr := range content.Attributes {
|
||||
fieldIdx := tags.Attributes[name]
|
||||
for name, fieldIdx := range tags.Attributes {
|
||||
attr := content.Attributes[name]
|
||||
field := val.Type().Field(fieldIdx)
|
||||
fieldV := val.Field(fieldIdx)
|
||||
|
||||
if attr == nil {
|
||||
if !exprType.AssignableTo(field.Type) {
|
||||
continue
|
||||
}
|
||||
|
||||
// As a special case, if the target is of type hcl.Expression then
|
||||
// we'll assign an actual expression that evalues to a cty null,
|
||||
// so the caller can deal with it within the cty realm rather
|
||||
// than within the Go realm.
|
||||
synthExpr := hcl.StaticExpr(cty.NullVal(cty.DynamicPseudoType), body.MissingItemRange())
|
||||
fieldV.Set(reflect.ValueOf(synthExpr))
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case attrType.AssignableTo(field.Type):
|
||||
fieldV.Set(reflect.ValueOf(attr))
|
||||
|
@ -19,6 +19,10 @@ func TestDecodeBody(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type withNameExpression struct {
|
||||
Name hcl.Expression `hcl:"name"`
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
Body map[string]interface{}
|
||||
Target interface{}
|
||||
@ -51,6 +55,60 @@ func TestDecodeBody(t *testing.T) {
|
||||
}{}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{},
|
||||
withNameExpression{},
|
||||
func(v interface{}) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
wne, valid := v.(withNameExpression)
|
||||
if !valid {
|
||||
return false
|
||||
}
|
||||
|
||||
if wne.Name == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
nameVal, _ := wne.Name.Value(nil)
|
||||
if !nameVal.IsNull() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"name": "Ermintrude",
|
||||
},
|
||||
withNameExpression{},
|
||||
func(v interface{}) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
wne, valid := v.(withNameExpression)
|
||||
if !valid {
|
||||
return false
|
||||
}
|
||||
|
||||
if wne.Name == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
nameVal, _ := wne.Name.Value(nil)
|
||||
if !nameVal.Equals(cty.StringVal("Ermintrude")).True() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"name": "Ermintrude",
|
||||
|
@ -43,9 +43,23 @@ func ImpliedBodySchema(val interface{}) (schema *hcl.BodySchema, partial bool) {
|
||||
for _, n := range attrNames {
|
||||
idx := tags.Attributes[n]
|
||||
field := ty.Field(idx)
|
||||
var required bool
|
||||
|
||||
switch {
|
||||
case field.Type.AssignableTo(exprType):
|
||||
// If we're decoding to hcl.Expression then absense can be
|
||||
// indicated via a null value, so we don't specify that
|
||||
// the field is required during decoding.
|
||||
required = false
|
||||
case field.Type.Kind() != reflect.Ptr:
|
||||
required = true
|
||||
default:
|
||||
required = false
|
||||
}
|
||||
|
||||
attrSchemas = append(attrSchemas, hcl.AttributeSchema{
|
||||
Name: n,
|
||||
Required: field.Type.Kind() != reflect.Ptr,
|
||||
Required: required,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -179,6 +179,20 @@ func TestImpliedBodySchema(t *testing.T) {
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
struct {
|
||||
Expr hcl.Expression `hcl:"expr"`
|
||||
}{},
|
||||
&hcl.BodySchema{
|
||||
Attributes: []hcl.AttributeSchema{
|
||||
{
|
||||
Name: "expr",
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
Loading…
Reference in New Issue
Block a user