diff --git a/engine/graph/sendrecv.go b/engine/graph/sendrecv.go index db6060ae..ec543e87 100644 --- a/engine/graph/sendrecv.go +++ b/engine/graph/sendrecv.go @@ -23,6 +23,7 @@ import ( "github.com/purpleidea/mgmt/engine" engineUtil "github.com/purpleidea/mgmt/engine/util" + "github.com/purpleidea/mgmt/lang/types" "github.com/purpleidea/mgmt/util/errwrap" ) @@ -93,15 +94,15 @@ func (obj *Engine) SendRecv(res engine.RecvableRes) (map[string]bool, error) { value2 := obj2.FieldByName(key2) kind2 := value2.Kind() + //orig := value1 dest := value2 // save the o.g. because we need the real dest! // For situations where we send a variant to the resource! - // TODO: should this be a for loop to un-nest multiple times? - if kind1 == reflect.Interface { + for kind1 == reflect.Interface || kind1 == reflect.Ptr { value1 = value1.Elem() // un-nest one interface kind1 = value1.Kind() } - if kind2 == reflect.Interface { + for kind2 == reflect.Interface || kind2 == reflect.Ptr { value2 = value2.Elem() // un-nest one interface kind2 = value2.Kind() } @@ -152,7 +153,20 @@ func (obj *Engine) SendRecv(res engine.RecvableRes) (map[string]bool, error) { // TODO: can we catch the panics here in case they happen? - dest.Set(value1) // do it for all types that match + fv, e := types.ValueOf(value1) + if e != nil { + e := errwrap.Wrapf(e, "bad value %s.%s", v.Res, v.Key) + err = errwrap.Append(err, e) // list of errors + continue + } + + // mutate the struct field dest with the mcl data in fv + if e := types.Into(fv, dest); e != nil { + e := errwrap.Wrapf(e, "bad dest %s.%s", v.Res, v.Key) + err = errwrap.Append(err, e) // list of errors + continue + } + //dest.Set(orig) // do it for all types that match updated[k] = true // we updated this key! v.Changed = true // tag this key as updated! obj.Logf("SendRecv: %s.%s -> %s.%s", v.Res, v.Key, res, k) diff --git a/engine/util/util.go b/engine/util/util.go index 9668b2ef..17489efb 100644 --- a/engine/util/util.go +++ b/engine/util/util.go @@ -193,7 +193,7 @@ func StructFieldCompat(st1 interface{}, key1 string, st2 interface{}, key2 strin } // If we're sending _from_ an interface... - if kind1 == reflect.Interface { + if kind1 == reflect.Interface || kind1 == reflect.Ptr { // TODO: Can we do more checks instead of only returning early? return nil } diff --git a/lang/types/value.go b/lang/types/value.go index d8d04b9f..2042b4ab 100644 --- a/lang/types/value.go +++ b/lang/types/value.go @@ -234,16 +234,28 @@ func ValueOf(v reflect.Value) (Value, error) { // TODO: should this return a variant value? // TODO: add this into ConfigurableValueOf like ConfigurableTypeOf ? - //case reflect.Interface: - // t, err := TypeOf(value.Type()) - // if err != nil { - // return nil, errwrap.Wrapf(err, "can't determine type of %+v", value) - // } - // - // return &VariantValue{ - // T: NewType(?), - // V: ?, - // }, nil + case reflect.Interface: + opts := []TypeOfOption{ + //StructTagOpt(StructTag), + //StrictStructTagOpt(false), + //SkipBadStructFieldsOpt(false), + AllowInterfaceTypeOpt(true), + } + t, err := ConfigurableTypeOf(value.Type(), opts...) + //t, err := TypeOf(value.Type()) + if err != nil { + return nil, errwrap.Wrapf(err, "can't determine type of %+v", value) + } + + v, err := ValueOf(value.Elem()) // recurse + if err != nil { + return nil, errwrap.Wrapf(err, "can't determine value of %+v", value) + } + + return &VariantValue{ + T: t, + V: v, + }, nil default: return nil, fmt.Errorf("unable to represent value of %+v which has kind: %v", v, kind)