]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/helper/plugin/unknown.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / plugin / unknown.go
1 package plugin
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/terraform/configs/configschema"
7 "github.com/zclconf/go-cty/cty"
8 )
9
10 // SetUnknowns takes a cty.Value, and compares it to the schema setting any null
11 // values which are computed to unknown.
12 func SetUnknowns(val cty.Value, schema *configschema.Block) cty.Value {
13 if !val.IsKnown() {
14 return val
15 }
16
17 // If the object was null, we still need to handle the top level attributes
18 // which might be computed, but we don't need to expand the blocks.
19 if val.IsNull() {
20 objMap := map[string]cty.Value{}
21 allNull := true
22 for name, attr := range schema.Attributes {
23 switch {
24 case attr.Computed:
25 objMap[name] = cty.UnknownVal(attr.Type)
26 allNull = false
27 default:
28 objMap[name] = cty.NullVal(attr.Type)
29 }
30 }
31
32 // If this object has no unknown attributes, then we can leave it null.
33 if allNull {
34 return val
35 }
36
37 return cty.ObjectVal(objMap)
38 }
39
40 valMap := val.AsValueMap()
41 newVals := make(map[string]cty.Value)
42
43 for name, attr := range schema.Attributes {
44 v := valMap[name]
45
46 if attr.Computed && v.IsNull() {
47 newVals[name] = cty.UnknownVal(attr.Type)
48 continue
49 }
50
51 newVals[name] = v
52 }
53
54 for name, blockS := range schema.BlockTypes {
55 blockVal := valMap[name]
56 if blockVal.IsNull() || !blockVal.IsKnown() {
57 newVals[name] = blockVal
58 continue
59 }
60
61 blockValType := blockVal.Type()
62 blockElementType := blockS.Block.ImpliedType()
63
64 // This switches on the value type here, so we can correctly switch
65 // between Tuples/Lists and Maps/Objects.
66 switch {
67 case blockS.Nesting == configschema.NestingSingle || blockS.Nesting == configschema.NestingGroup:
68 // NestingSingle is the only exception here, where we treat the
69 // block directly as an object
70 newVals[name] = SetUnknowns(blockVal, &blockS.Block)
71
72 case blockValType.IsSetType(), blockValType.IsListType(), blockValType.IsTupleType():
73 listVals := blockVal.AsValueSlice()
74 newListVals := make([]cty.Value, 0, len(listVals))
75
76 for _, v := range listVals {
77 newListVals = append(newListVals, SetUnknowns(v, &blockS.Block))
78 }
79
80 switch {
81 case blockValType.IsSetType():
82 switch len(newListVals) {
83 case 0:
84 newVals[name] = cty.SetValEmpty(blockElementType)
85 default:
86 newVals[name] = cty.SetVal(newListVals)
87 }
88 case blockValType.IsListType():
89 switch len(newListVals) {
90 case 0:
91 newVals[name] = cty.ListValEmpty(blockElementType)
92 default:
93 newVals[name] = cty.ListVal(newListVals)
94 }
95 case blockValType.IsTupleType():
96 newVals[name] = cty.TupleVal(newListVals)
97 }
98
99 case blockValType.IsMapType(), blockValType.IsObjectType():
100 mapVals := blockVal.AsValueMap()
101 newMapVals := make(map[string]cty.Value)
102
103 for k, v := range mapVals {
104 newMapVals[k] = SetUnknowns(v, &blockS.Block)
105 }
106
107 switch {
108 case blockValType.IsMapType():
109 switch len(newMapVals) {
110 case 0:
111 newVals[name] = cty.MapValEmpty(blockElementType)
112 default:
113 newVals[name] = cty.MapVal(newMapVals)
114 }
115 case blockValType.IsObjectType():
116 if len(newMapVals) == 0 {
117 // We need to populate empty values to make a valid object.
118 for attr, ty := range blockElementType.AttributeTypes() {
119 newMapVals[attr] = cty.NullVal(ty)
120 }
121 }
122 newVals[name] = cty.ObjectVal(newMapVals)
123 }
124
125 default:
126 panic(fmt.Sprintf("failed to set unknown values for nested block %q:%#v", name, blockValType))
127 }
128 }
129
130 return cty.ObjectVal(newVals)
131 }