From 93cda6dbd20852b488cf9079e217788ce5751d93 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sat, 16 Jun 2018 11:12:04 -0700 Subject: [PATCH] govendor fetch github.com/zclconf/go-cty/cty/... This allows automatic conversions between different object types as long as the target type is a subset of the given type. --- .../zclconf/go-cty/cty/convert/conversion.go | 3 + .../go-cty/cty/convert/conversion_object.go | 76 +++++++++++ .../go-cty/cty/convert/mismatch_msg.go | 120 ++++++++++++++++++ .../zclconf/go-cty/cty/convert/public.go | 4 +- vendor/vendor.json | 34 ++--- 5 files changed, 218 insertions(+), 19 deletions(-) create mode 100644 vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go create mode 100644 vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go index 8afdc727c..dd55bbf3e 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go @@ -57,6 +57,9 @@ func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion { } return nil + case out.IsObjectType() && in.IsObjectType(): + return conversionObjectToObject(in, out, unsafe) + case out.IsListType() && (in.IsListType() || in.IsSetType()): inEty := in.ElementType() outEty := out.ElementType() diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go new file mode 100644 index 000000000..62dabb8d1 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_object.go @@ -0,0 +1,76 @@ +package convert + +import ( + "github.com/zclconf/go-cty/cty" +) + +// conversionObjectToObject returns a conversion that will make the input +// object type conform to the output object type, if possible. +// +// Conversion is possible only if the output type is a subset of the input +// type, meaning that each attribute of the output type has a corresponding +// attribute in the input type where a recursive conversion is available. +// +// Shallow object conversions work the same for both safe and unsafe modes, +// but the safety flag is passed on to recursive conversions and may thus +// limit the above definition of "subset". +func conversionObjectToObject(in, out cty.Type, unsafe bool) conversion { + inAtys := in.AttributeTypes() + outAtys := out.AttributeTypes() + attrConvs := make(map[string]conversion) + + for name, outAty := range outAtys { + inAty, exists := inAtys[name] + if !exists { + // No conversion is available, then. + return nil + } + + if inAty.Equals(outAty) { + // No conversion needed, but we'll still record the attribute + // in our map for later reference. + attrConvs[name] = nil + continue + } + + attrConvs[name] = getConversion(inAty, outAty, unsafe) + if attrConvs[name] == nil { + // If a recursive conversion isn't available, then our top-level + // configuration is impossible too. + return nil + } + } + + // If we get here then a conversion is possible, using the attribute + // conversions given in attrConvs. + return func(val cty.Value, path cty.Path) (cty.Value, error) { + attrVals := make(map[string]cty.Value, len(attrConvs)) + path = append(path, nil) + pathStep := &path[len(path)-1] + + for it := val.ElementIterator(); it.Next(); { + nameVal, val := it.Element() + var err error + + name := nameVal.AsString() + *pathStep = cty.GetAttrStep{ + Name: name, + } + + conv, exists := attrConvs[name] + if !exists { + continue + } + if conv != nil { + val, err = conv(val, path) + if err != nil { + return cty.NilVal, err + } + } + + attrVals[name] = val + } + + return cty.ObjectVal(attrVals), nil + } +} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go b/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go new file mode 100644 index 000000000..fffce1df0 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/mismatch_msg.go @@ -0,0 +1,120 @@ +package convert + +import ( + "bytes" + "fmt" + "sort" + + "github.com/zclconf/go-cty/cty" +) + +// MismatchMessage is a helper to return an English-language description of +// the differences between got and want, phrased as a reason why got does +// not conform to want. +// +// This function does not itself attempt conversion, and so it should generally +// be used only after a conversion has failed, to report the conversion failure +// to an English-speaking user. The result will be confusing got is actually +// conforming to or convertable to want. +// +// The shorthand helper function Convert uses this function internally to +// produce its error messages, so callers of that function do not need to +// also use MismatchMessage. +// +// This function is similar to Type.TestConformance, but it is tailored to +// describing conversion failures and so the messages it generates relate +// specifically to the conversion rules implemented in this package. +func MismatchMessage(got, want cty.Type) string { + switch { + + case got.IsObjectType() && want.IsObjectType(): + // If both types are object types then we may be able to say something + // about their respective attributes. + return mismatchMessageObjects(got, want) + + default: + // If we have nothing better to say, we'll just state what was required. + return want.FriendlyName() + " required" + } +} + +func mismatchMessageObjects(got, want cty.Type) string { + // Per our conversion rules, "got" is allowed to be a superset of "want", + // and so we'll produce error messages here under that assumption. + gotAtys := got.AttributeTypes() + wantAtys := want.AttributeTypes() + + // If we find missing attributes then we'll report those in preference, + // but if not then we will report a maximum of one non-conforming + // attribute, just to keep our messages relatively terse. + // We'll also prefer to report a recursive type error from an _unsafe_ + // conversion over a safe one, because these are subjectively more + // "serious". + var missingAttrs []string + var unsafeMismatchAttr string + var safeMismatchAttr string + + for name, wantAty := range wantAtys { + gotAty, exists := gotAtys[name] + if !exists { + missingAttrs = append(missingAttrs, name) + continue + } + + // We'll now try to convert these attributes in isolation and + // see if we have a nested conversion error to report. + // We'll try an unsafe conversion first, and then fall back on + // safe if unsafe is possible. + + // If we already have an unsafe mismatch attr error then we won't bother + // hunting for another one. + if unsafeMismatchAttr != "" { + continue + } + if conv := GetConversionUnsafe(gotAty, wantAty); conv == nil { + unsafeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty)) + } + + // If we already have a safe mismatch attr error then we won't bother + // hunting for another one. + if safeMismatchAttr != "" { + continue + } + if conv := GetConversion(gotAty, wantAty); conv == nil { + safeMismatchAttr = fmt.Sprintf("attribute %q: %s", name, MismatchMessage(gotAty, wantAty)) + } + } + + // We should now have collected at least one problem. If we have more than + // one then we'll use our preference order to decide what is most important + // to report. + switch { + + case len(missingAttrs) != 0: + switch len(missingAttrs) { + case 1: + return fmt.Sprintf("attribute %q is required", missingAttrs[0]) + case 2: + return fmt.Sprintf("attributes %q and %q are required", missingAttrs[0], missingAttrs[1]) + default: + sort.Strings(missingAttrs) + var buf bytes.Buffer + for _, name := range missingAttrs[:len(missingAttrs)-1] { + fmt.Fprintf(&buf, "%q, ", name) + } + fmt.Fprintf(&buf, "and %q", missingAttrs[len(missingAttrs)-1]) + return fmt.Sprintf("attributes %s are required", buf.Bytes()) + } + + case unsafeMismatchAttr != "": + return unsafeMismatchAttr + + case safeMismatchAttr != "": + return safeMismatchAttr + + default: + // We should never get here, but if we do then we'll return + // just a generic message. + return "incorrect object attributes" + } +} diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/public.go b/vendor/github.com/zclconf/go-cty/cty/convert/public.go index 55f44aeca..af19bdc50 100644 --- a/vendor/github.com/zclconf/go-cty/cty/convert/public.go +++ b/vendor/github.com/zclconf/go-cty/cty/convert/public.go @@ -1,7 +1,7 @@ package convert import ( - "fmt" + "errors" "github.com/zclconf/go-cty/cty" ) @@ -46,7 +46,7 @@ func Convert(in cty.Value, want cty.Type) (cty.Value, error) { conv := GetConversionUnsafe(in.Type(), want) if conv == nil { - return cty.NilVal, fmt.Errorf("incorrect type; %s required", want.FriendlyName()) + return cty.NilVal, errors.New(MismatchMessage(in.Type(), want)) } return conv(in) } diff --git a/vendor/vendor.json b/vendor/vendor.json index cb4e6d402..0e0df9de4 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2442,50 +2442,50 @@ { "checksumSHA1": "4REWNRi5Dg7Kxj1US72+/oVii3Q=", "path": "github.com/zclconf/go-cty/cty", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { - "checksumSHA1": "g3pPIVGKkD4gt8TasyLxSX+qdP0=", + "checksumSHA1": "3bFMqSB6IxIwhzIw8hyLfd7ayrY=", "path": "github.com/zclconf/go-cty/cty/convert", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "MyyLCGg3RREMllTJyK6ehZl/dHk=", "path": "github.com/zclconf/go-cty/cty/function", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "kcTJOuL131/stXJ4U9tC3SASQLs=", "path": "github.com/zclconf/go-cty/cty/function/stdlib", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "tmCzwfNXOEB1sSO7TKVzilb2vjA=", "path": "github.com/zclconf/go-cty/cty/gocty", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "1ApmO+Q33+Oem/3f6BU6sztJWNc=", "path": "github.com/zclconf/go-cty/cty/json", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "55JE44+FFgAo5WZEC23gp4X5tak=", "path": "github.com/zclconf/go-cty/cty/msgpack", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "y5Sk+n6SOspFj8mlyb8swr4DMIs=", "path": "github.com/zclconf/go-cty/cty/set", - "revision": "ba988ce11d9994867838957d4c40bb1ad78b433d", - "revisionTime": "2018-05-24T00:26:36Z" + "revision": "c96d660229f9ad0a16eb5869819ea51e1ed49896", + "revisionTime": "2018-06-16T18:02:17Z" }, { "checksumSHA1": "vE43s37+4CJ2CDU6TlOUOYE0K9c=",