vendor vendors
This commit is contained in:
parent
f013164298
commit
e195c627fb
|
@ -138,6 +138,15 @@ func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion {
|
|||
outEty := out.ElementType()
|
||||
return conversionObjectToMap(in, outEty, unsafe)
|
||||
|
||||
case out.IsObjectType() && in.IsMapType():
|
||||
if !unsafe {
|
||||
// Converting a map to an object is an "unsafe" conversion,
|
||||
// because we don't know if all the map keys will correspond to
|
||||
// object attributes.
|
||||
return nil
|
||||
}
|
||||
return conversionMapToObject(in, out, unsafe)
|
||||
|
||||
case in.IsCapsuleType() || out.IsCapsuleType():
|
||||
if !unsafe {
|
||||
// Capsule types can only participate in "unsafe" conversions,
|
||||
|
|
|
@ -15,18 +15,18 @@ func conversionCollectionToList(ety cty.Type, conv conversion) conversion {
|
|||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, val.LengthInt())
|
||||
i := int64(0)
|
||||
path = append(path, nil)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ func conversionCollectionToList(ety cty.Type, conv conversion) conversion {
|
|||
}
|
||||
|
||||
if len(elems) == 0 {
|
||||
if ety == cty.DynamicPseudoType {
|
||||
ety = val.Type().ElementType()
|
||||
}
|
||||
return cty.ListValEmpty(ety), nil
|
||||
}
|
||||
|
||||
|
@ -55,18 +58,18 @@ func conversionCollectionToSet(ety cty.Type, conv conversion) conversion {
|
|||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, val.LengthInt())
|
||||
i := int64(0)
|
||||
path = append(path, nil)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
@ -77,6 +80,11 @@ func conversionCollectionToSet(ety cty.Type, conv conversion) conversion {
|
|||
}
|
||||
|
||||
if len(elems) == 0 {
|
||||
// Prefer a concrete type over a dynamic type when returning an
|
||||
// empty set
|
||||
if ety == cty.DynamicPseudoType {
|
||||
ety = val.Type().ElementType()
|
||||
}
|
||||
return cty.SetValEmpty(ety), nil
|
||||
}
|
||||
|
||||
|
@ -93,13 +101,13 @@ func conversionCollectionToSet(ety cty.Type, conv conversion) conversion {
|
|||
func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make(map[string]cty.Value, 0)
|
||||
path = append(path, nil)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
key, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
|
@ -107,11 +115,11 @@ func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
|
|||
if err != nil {
|
||||
// Should never happen, because keys can only be numbers or
|
||||
// strings and both can convert to string.
|
||||
return cty.DynamicVal, path.NewErrorf("cannot convert key type %s to string for map", key.Type().FriendlyName())
|
||||
return cty.DynamicVal, elemPath.NewErrorf("cannot convert key type %s to string for map", key.Type().FriendlyName())
|
||||
}
|
||||
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
@ -121,9 +129,25 @@ func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
|
|||
}
|
||||
|
||||
if len(elems) == 0 {
|
||||
// Prefer a concrete type over a dynamic type when returning an
|
||||
// empty map
|
||||
if ety == cty.DynamicPseudoType {
|
||||
ety = val.Type().ElementType()
|
||||
}
|
||||
return cty.MapValEmpty(ety), nil
|
||||
}
|
||||
|
||||
if ety.IsCollectionType() || ety.IsObjectType() {
|
||||
var err error
|
||||
if elems, err = conversionUnifyCollectionElements(elems, path, false); err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := conversionCheckMapElementTypes(elems, path); err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
||||
return cty.MapVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
@ -171,20 +195,20 @@ func conversionTupleToSet(tupleType cty.Type, listEty cty.Type, unsafe bool) con
|
|||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
i := int64(0)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
conv := elemConvs[i]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
@ -241,20 +265,20 @@ func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) co
|
|||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make([]cty.Value, 0, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
i := int64(0)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
_, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(i),
|
||||
}
|
||||
|
||||
conv := elemConvs[i]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
@ -315,19 +339,19 @@ func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) co
|
|||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make(map[string]cty.Value, len(elemConvs))
|
||||
path = append(path, nil)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
name, val := it.Element()
|
||||
var err error
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: name,
|
||||
}
|
||||
|
||||
conv := elemConvs[name.AsString()]
|
||||
if conv != nil {
|
||||
val, err = conv(val, path)
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
@ -335,6 +359,130 @@ func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) co
|
|||
elems[name.AsString()] = val
|
||||
}
|
||||
|
||||
if mapEty.IsCollectionType() || mapEty.IsObjectType() {
|
||||
var err error
|
||||
if elems, err = conversionUnifyCollectionElements(elems, path, unsafe); err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := conversionCheckMapElementTypes(elems, path); err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
||||
return cty.MapVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
// conversionMapToObject returns a conversion that will take a value of the
|
||||
// given map type and return an object of the given type. The object attribute
|
||||
// types must all be compatible with the map element type.
|
||||
//
|
||||
// Will panic if the given mapType and objType are not maps and objects
|
||||
// respectively.
|
||||
func conversionMapToObject(mapType cty.Type, objType cty.Type, unsafe bool) conversion {
|
||||
objectAtys := objType.AttributeTypes()
|
||||
mapEty := mapType.ElementType()
|
||||
|
||||
elemConvs := make(map[string]conversion, len(objectAtys))
|
||||
for name, objectAty := range objectAtys {
|
||||
if objectAty.Equals(mapEty) {
|
||||
// no conversion required
|
||||
continue
|
||||
}
|
||||
|
||||
elemConvs[name] = getConversion(mapEty, objectAty, unsafe)
|
||||
if elemConvs[name] == nil {
|
||||
// If any of our element conversions are impossible, then the our
|
||||
// whole conversion is impossible.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we fall out here then a conversion is possible, using the
|
||||
// element conversions in elemConvs
|
||||
return func(val cty.Value, path cty.Path) (cty.Value, error) {
|
||||
elems := make(map[string]cty.Value, len(elemConvs))
|
||||
elemPath := append(path.Copy(), nil)
|
||||
it := val.ElementIterator()
|
||||
for it.Next() {
|
||||
name, val := it.Element()
|
||||
|
||||
// if there is no corresponding attribute, we skip this key
|
||||
if _, ok := objectAtys[name.AsString()]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: name,
|
||||
}
|
||||
|
||||
conv := elemConvs[name.AsString()]
|
||||
if conv != nil {
|
||||
val, err = conv(val, elemPath)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
}
|
||||
|
||||
elems[name.AsString()] = val
|
||||
}
|
||||
|
||||
return cty.ObjectVal(elems), nil
|
||||
}
|
||||
}
|
||||
|
||||
func conversionUnifyCollectionElements(elems map[string]cty.Value, path cty.Path, unsafe bool) (map[string]cty.Value, error) {
|
||||
elemTypes := make([]cty.Type, 0, len(elems))
|
||||
for _, elem := range elems {
|
||||
elemTypes = append(elemTypes, elem.Type())
|
||||
}
|
||||
unifiedType, _ := unify(elemTypes, unsafe)
|
||||
if unifiedType == cty.NilType {
|
||||
}
|
||||
|
||||
unifiedElems := make(map[string]cty.Value)
|
||||
elemPath := append(path.Copy(), nil)
|
||||
|
||||
for name, elem := range elems {
|
||||
if elem.Type().Equals(unifiedType) {
|
||||
unifiedElems[name] = elem
|
||||
continue
|
||||
}
|
||||
conv := getConversion(elem.Type(), unifiedType, unsafe)
|
||||
if conv == nil {
|
||||
}
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: cty.StringVal(name),
|
||||
}
|
||||
val, err := conv(elem, elemPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unifiedElems[name] = val
|
||||
}
|
||||
|
||||
return unifiedElems, nil
|
||||
}
|
||||
|
||||
func conversionCheckMapElementTypes(elems map[string]cty.Value, path cty.Path) error {
|
||||
elementType := cty.NilType
|
||||
elemPath := append(path.Copy(), nil)
|
||||
|
||||
for name, elem := range elems {
|
||||
if elementType == cty.NilType {
|
||||
elementType = elem.Type()
|
||||
continue
|
||||
}
|
||||
if !elementType.Equals(elem.Type()) {
|
||||
elemPath[len(elemPath)-1] = cty.IndexStep{
|
||||
Key: cty.StringVal(name),
|
||||
}
|
||||
return elemPath.NewErrorf("%s is required", elementType.FriendlyName())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -28,11 +28,14 @@ func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
|
|||
// a subset of that type, which would be a much less useful conversion for
|
||||
// unification purposes.
|
||||
{
|
||||
mapCt := 0
|
||||
objectCt := 0
|
||||
tupleCt := 0
|
||||
dynamicCt := 0
|
||||
for _, ty := range types {
|
||||
switch {
|
||||
case ty.IsMapType():
|
||||
mapCt++
|
||||
case ty.IsObjectType():
|
||||
objectCt++
|
||||
case ty.IsTupleType():
|
||||
|
@ -44,6 +47,8 @@ func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
|
|||
}
|
||||
}
|
||||
switch {
|
||||
case mapCt > 0 && (mapCt+dynamicCt) == len(types):
|
||||
return unifyMapTypes(types, unsafe, dynamicCt > 0)
|
||||
case objectCt > 0 && (objectCt+dynamicCt) == len(types):
|
||||
return unifyObjectTypes(types, unsafe, dynamicCt > 0)
|
||||
case tupleCt > 0 && (tupleCt+dynamicCt) == len(types):
|
||||
|
@ -95,6 +100,44 @@ Preferences:
|
|||
return cty.NilType, nil
|
||||
}
|
||||
|
||||
func unifyMapTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) {
|
||||
// If we had any dynamic types in the input here then we can't predict
|
||||
// what path we'll take through here once these become known types, so
|
||||
// we'll conservatively produce DynamicVal for these.
|
||||
if hasDynamic {
|
||||
return unifyAllAsDynamic(types)
|
||||
}
|
||||
|
||||
elemTypes := make([]cty.Type, 0, len(types))
|
||||
for _, ty := range types {
|
||||
elemTypes = append(elemTypes, ty.ElementType())
|
||||
}
|
||||
retElemType, _ := unify(elemTypes, unsafe)
|
||||
if retElemType == cty.NilType {
|
||||
return cty.NilType, nil
|
||||
}
|
||||
|
||||
retTy := cty.Map(retElemType)
|
||||
|
||||
conversions := make([]Conversion, len(types))
|
||||
for i, ty := range types {
|
||||
if ty.Equals(retTy) {
|
||||
continue
|
||||
}
|
||||
if unsafe {
|
||||
conversions[i] = GetConversionUnsafe(ty, retTy)
|
||||
} else {
|
||||
conversions[i] = GetConversion(ty, retTy)
|
||||
}
|
||||
if conversions[i] == nil {
|
||||
// Shouldn't be reachable, since we were able to unify
|
||||
return cty.NilType, nil
|
||||
}
|
||||
}
|
||||
|
||||
return retTy, conversions
|
||||
}
|
||||
|
||||
func unifyObjectTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) {
|
||||
// If we had any dynamic types in the input here then we can't predict
|
||||
// what path we'll take through here once these become known types, so
|
||||
|
|
|
@ -299,7 +299,7 @@ var ContainsFunc = function.New(&function.Spec{
|
|||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.Bool),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
arg := args[0]
|
||||
ty := arg.Type()
|
||||
|
||||
|
@ -307,12 +307,39 @@ var ContainsFunc = function.New(&function.Spec{
|
|||
return cty.NilVal, errors.New("argument must be list, tuple, or set")
|
||||
}
|
||||
|
||||
_, err = Index(cty.TupleVal(arg.AsValueSlice()), args[1])
|
||||
if err != nil {
|
||||
if args[0].IsNull() {
|
||||
return cty.NilVal, errors.New("cannot search a nil list or set")
|
||||
}
|
||||
|
||||
if args[0].LengthInt() == 0 {
|
||||
return cty.False, nil
|
||||
}
|
||||
|
||||
return cty.True, nil
|
||||
if !args[0].IsKnown() || !args[1].IsKnown() {
|
||||
return cty.UnknownVal(cty.Bool), nil
|
||||
}
|
||||
|
||||
containsUnknown := false
|
||||
for it := args[0].ElementIterator(); it.Next(); {
|
||||
_, v := it.Element()
|
||||
eq := args[1].Equals(v)
|
||||
if !eq.IsKnown() {
|
||||
// We may have an unknown value which could match later, but we
|
||||
// first need to continue checking all values for an exact
|
||||
// match.
|
||||
containsUnknown = true
|
||||
continue
|
||||
}
|
||||
if eq.True() {
|
||||
return cty.True, nil
|
||||
}
|
||||
}
|
||||
|
||||
if containsUnknown {
|
||||
return cty.UnknownVal(cty.Bool), nil
|
||||
}
|
||||
|
||||
return cty.False, nil
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -566,19 +593,12 @@ var LookupFunc = function.New(&function.Spec{
|
|||
Name: "key",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
VarParam: &function.Parameter{
|
||||
Name: "default",
|
||||
Type: cty.DynamicPseudoType,
|
||||
AllowUnknown: true,
|
||||
AllowDynamicType: true,
|
||||
AllowNull: true,
|
||||
{
|
||||
Name: "default",
|
||||
Type: cty.DynamicPseudoType,
|
||||
},
|
||||
},
|
||||
Type: func(args []cty.Value) (ret cty.Type, err error) {
|
||||
if len(args) < 1 || len(args) > 3 {
|
||||
return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
|
||||
}
|
||||
|
||||
ty := args[0].Type()
|
||||
|
||||
switch {
|
||||
|
@ -609,13 +629,7 @@ var LookupFunc = function.New(&function.Spec{
|
|||
}
|
||||
},
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
var defaultVal cty.Value
|
||||
defaultValueSet := false
|
||||
|
||||
if len(args) == 3 {
|
||||
defaultVal = args[2]
|
||||
defaultValueSet = true
|
||||
}
|
||||
defaultVal := args[2]
|
||||
|
||||
mapVar := args[0]
|
||||
lookupKey := args[1].AsString()
|
||||
|
@ -632,48 +646,128 @@ var LookupFunc = function.New(&function.Spec{
|
|||
return mapVar.Index(cty.StringVal(lookupKey)), nil
|
||||
}
|
||||
|
||||
if defaultValueSet {
|
||||
defaultVal, err = convert.Convert(defaultVal, retType)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
return defaultVal, nil
|
||||
defaultVal, err = convert.Convert(defaultVal, retType)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
||||
return cty.UnknownVal(cty.DynamicPseudoType), fmt.Errorf(
|
||||
"lookup failed to find '%s'", lookupKey)
|
||||
return defaultVal, nil
|
||||
},
|
||||
})
|
||||
|
||||
// MergeFunc is a function that takes an arbitrary number of maps and
|
||||
// returns a single map that contains a merged set of elements from all of the maps.
|
||||
// MergeFunc constructs a function that takes an arbitrary number of maps or
|
||||
// objects, and returns a single value that contains a merged set of keys and
|
||||
// values from all of the inputs.
|
||||
//
|
||||
// If more than one given map defines the same key then the one that is later in
|
||||
// the argument sequence takes precedence.
|
||||
// If more than one given map or object defines the same key then the one that
|
||||
// is later in the argument sequence takes precedence.
|
||||
var MergeFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{},
|
||||
VarParam: &function.Parameter{
|
||||
Name: "maps",
|
||||
Type: cty.DynamicPseudoType,
|
||||
AllowDynamicType: true,
|
||||
AllowNull: true,
|
||||
},
|
||||
Type: func(args []cty.Value) (cty.Type, error) {
|
||||
// empty args is accepted, so assume an empty object since we have no
|
||||
// key-value types.
|
||||
if len(args) == 0 {
|
||||
return cty.EmptyObject, nil
|
||||
}
|
||||
|
||||
// collect the possible object attrs
|
||||
attrs := map[string]cty.Type{}
|
||||
|
||||
first := cty.NilType
|
||||
matching := true
|
||||
attrsKnown := true
|
||||
for i, arg := range args {
|
||||
ty := arg.Type()
|
||||
// any dynamic args mean we can't compute a type
|
||||
if ty.Equals(cty.DynamicPseudoType) {
|
||||
return cty.DynamicPseudoType, nil
|
||||
}
|
||||
|
||||
// check for invalid arguments
|
||||
if !ty.IsMapType() && !ty.IsObjectType() {
|
||||
return cty.NilType, fmt.Errorf("arguments must be maps or objects, got %#v", ty.FriendlyName())
|
||||
}
|
||||
|
||||
switch {
|
||||
case ty.IsObjectType() && !arg.IsNull():
|
||||
for attr, aty := range ty.AttributeTypes() {
|
||||
attrs[attr] = aty
|
||||
}
|
||||
case ty.IsMapType():
|
||||
switch {
|
||||
case arg.IsNull():
|
||||
// pass, nothing to add
|
||||
case arg.IsKnown():
|
||||
ety := arg.Type().ElementType()
|
||||
for it := arg.ElementIterator(); it.Next(); {
|
||||
attr, _ := it.Element()
|
||||
attrs[attr.AsString()] = ety
|
||||
}
|
||||
default:
|
||||
// any unknown maps means we don't know all possible attrs
|
||||
// for the return type
|
||||
attrsKnown = false
|
||||
}
|
||||
}
|
||||
|
||||
// record the first argument type for comparison
|
||||
if i == 0 {
|
||||
first = arg.Type()
|
||||
continue
|
||||
}
|
||||
|
||||
if !ty.Equals(first) && matching {
|
||||
matching = false
|
||||
}
|
||||
}
|
||||
|
||||
// the types all match, so use the first argument type
|
||||
if matching {
|
||||
return first, nil
|
||||
}
|
||||
|
||||
// We had a mix of unknown maps and objects, so we can't predict the
|
||||
// attributes
|
||||
if !attrsKnown {
|
||||
return cty.DynamicPseudoType, nil
|
||||
}
|
||||
|
||||
return cty.Object(attrs), nil
|
||||
},
|
||||
Type: function.StaticReturnType(cty.DynamicPseudoType),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
outputMap := make(map[string]cty.Value)
|
||||
|
||||
// if all inputs are null, return a null value rather than an object
|
||||
// with null attributes
|
||||
allNull := true
|
||||
for _, arg := range args {
|
||||
if !arg.IsWhollyKnown() {
|
||||
return cty.UnknownVal(retType), nil
|
||||
}
|
||||
if !arg.Type().IsObjectType() && !arg.Type().IsMapType() {
|
||||
return cty.NilVal, fmt.Errorf("arguments must be maps or objects, got %#v", arg.Type().FriendlyName())
|
||||
if arg.IsNull() {
|
||||
continue
|
||||
} else {
|
||||
allNull = false
|
||||
}
|
||||
|
||||
for it := arg.ElementIterator(); it.Next(); {
|
||||
k, v := it.Element()
|
||||
outputMap[k.AsString()] = v
|
||||
}
|
||||
}
|
||||
return cty.ObjectVal(outputMap), nil
|
||||
|
||||
switch {
|
||||
case allNull:
|
||||
return cty.NullVal(retType), nil
|
||||
case retType.IsMapType():
|
||||
return cty.MapVal(outputMap), nil
|
||||
case retType.IsObjectType(), retType.Equals(cty.DynamicPseudoType):
|
||||
return cty.ObjectVal(outputMap), nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected return type: %#v", retType))
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -1184,8 +1278,8 @@ func Keys(inputMap cty.Value) (cty.Value, error) {
|
|||
// Lookup performs a dynamic lookup into a map.
|
||||
// There are two required arguments, map and key, plus an optional default,
|
||||
// which is a value to return if no key is found in map.
|
||||
func Lookup(args ...cty.Value) (cty.Value, error) {
|
||||
return LookupFunc.Call(args)
|
||||
func Lookup(inputMap, key, defaultValue cty.Value) (cty.Value, error) {
|
||||
return LookupFunc.Call([]cty.Value{inputMap, key, defaultValue})
|
||||
}
|
||||
|
||||
// Merge takes an arbitrary number of maps and returns a single map that contains
|
||||
|
|
|
@ -217,7 +217,7 @@ var TimeAddFunc = function.New(&function.Spec{
|
|||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
ts, err := time.Parse(time.RFC3339, args[0].AsString())
|
||||
ts, err := parseTimestamp(args[0].AsString())
|
||||
if err != nil {
|
||||
return cty.UnknownVal(cty.String), err
|
||||
}
|
||||
|
|
|
@ -638,7 +638,7 @@ github.com/yandex-cloud/go-sdk/pkg/retry
|
|||
github.com/yandex-cloud/go-sdk/pkg/sdkerrors
|
||||
github.com/yandex-cloud/go-sdk/pkg/singleflight
|
||||
github.com/yandex-cloud/go-sdk/sdkresolvers
|
||||
# github.com/zclconf/go-cty v1.2.1 => github.com/azr/go-cty v1.1.1-0.20200203143058-28fcda2fe0cc
|
||||
# github.com/zclconf/go-cty v1.3.1
|
||||
github.com/zclconf/go-cty/cty
|
||||
github.com/zclconf/go-cty/cty/convert
|
||||
github.com/zclconf/go-cty/cty/function
|
||||
|
|
Loading…
Reference in New Issue