diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/flatmap/expand.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/flatmap/expand.go | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/flatmap/expand.go b/vendor/github.com/hashicorp/terraform/flatmap/expand.go new file mode 100644 index 0000000..e0b81b6 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/flatmap/expand.go | |||
@@ -0,0 +1,147 @@ | |||
1 | package flatmap | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "sort" | ||
6 | "strconv" | ||
7 | "strings" | ||
8 | |||
9 | "github.com/hashicorp/hil" | ||
10 | ) | ||
11 | |||
12 | // Expand takes a map and a key (prefix) and expands that value into | ||
13 | // a more complex structure. This is the reverse of the Flatten operation. | ||
14 | func Expand(m map[string]string, key string) interface{} { | ||
15 | // If the key is exactly a key in the map, just return it | ||
16 | if v, ok := m[key]; ok { | ||
17 | if v == "true" { | ||
18 | return true | ||
19 | } else if v == "false" { | ||
20 | return false | ||
21 | } | ||
22 | |||
23 | return v | ||
24 | } | ||
25 | |||
26 | // Check if the key is an array, and if so, expand the array | ||
27 | if v, ok := m[key+".#"]; ok { | ||
28 | // If the count of the key is unknown, then just put the unknown | ||
29 | // value in the value itself. This will be detected by Terraform | ||
30 | // core later. | ||
31 | if v == hil.UnknownValue { | ||
32 | return v | ||
33 | } | ||
34 | |||
35 | return expandArray(m, key) | ||
36 | } | ||
37 | |||
38 | // Check if this is a prefix in the map | ||
39 | prefix := key + "." | ||
40 | for k := range m { | ||
41 | if strings.HasPrefix(k, prefix) { | ||
42 | return expandMap(m, prefix) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | return nil | ||
47 | } | ||
48 | |||
49 | func expandArray(m map[string]string, prefix string) []interface{} { | ||
50 | num, err := strconv.ParseInt(m[prefix+".#"], 0, 0) | ||
51 | if err != nil { | ||
52 | panic(err) | ||
53 | } | ||
54 | |||
55 | // If the number of elements in this array is 0, then return an | ||
56 | // empty slice as there is nothing to expand. Trying to expand it | ||
57 | // anyway could lead to crashes as any child maps, arrays or sets | ||
58 | // that no longer exist are still shown as empty with a count of 0. | ||
59 | if num == 0 { | ||
60 | return []interface{}{} | ||
61 | } | ||
62 | |||
63 | // The Schema "Set" type stores its values in an array format, but | ||
64 | // using numeric hash values instead of ordinal keys. Take the set | ||
65 | // of keys regardless of value, and expand them in numeric order. | ||
66 | // See GH-11042 for more details. | ||
67 | keySet := map[int]bool{} | ||
68 | computed := map[string]bool{} | ||
69 | for k := range m { | ||
70 | if !strings.HasPrefix(k, prefix+".") { | ||
71 | continue | ||
72 | } | ||
73 | |||
74 | key := k[len(prefix)+1:] | ||
75 | idx := strings.Index(key, ".") | ||
76 | if idx != -1 { | ||
77 | key = key[:idx] | ||
78 | } | ||
79 | |||
80 | // skip the count value | ||
81 | if key == "#" { | ||
82 | continue | ||
83 | } | ||
84 | |||
85 | // strip the computed flag if there is one | ||
86 | if strings.HasPrefix(key, "~") { | ||
87 | key = key[1:] | ||
88 | computed[key] = true | ||
89 | } | ||
90 | |||
91 | k, err := strconv.Atoi(key) | ||
92 | if err != nil { | ||
93 | panic(err) | ||
94 | } | ||
95 | keySet[int(k)] = true | ||
96 | } | ||
97 | |||
98 | keysList := make([]int, 0, num) | ||
99 | for key := range keySet { | ||
100 | keysList = append(keysList, key) | ||
101 | } | ||
102 | sort.Ints(keysList) | ||
103 | |||
104 | result := make([]interface{}, num) | ||
105 | for i, key := range keysList { | ||
106 | keyString := strconv.Itoa(key) | ||
107 | if computed[keyString] { | ||
108 | keyString = "~" + keyString | ||
109 | } | ||
110 | result[i] = Expand(m, fmt.Sprintf("%s.%s", prefix, keyString)) | ||
111 | } | ||
112 | |||
113 | return result | ||
114 | } | ||
115 | |||
116 | func expandMap(m map[string]string, prefix string) map[string]interface{} { | ||
117 | // Submaps may not have a '%' key, so we can't count on this value being | ||
118 | // here. If we don't have a count, just proceed as if we have have a map. | ||
119 | if count, ok := m[prefix+"%"]; ok && count == "0" { | ||
120 | return map[string]interface{}{} | ||
121 | } | ||
122 | |||
123 | result := make(map[string]interface{}) | ||
124 | for k := range m { | ||
125 | if !strings.HasPrefix(k, prefix) { | ||
126 | continue | ||
127 | } | ||
128 | |||
129 | key := k[len(prefix):] | ||
130 | idx := strings.Index(key, ".") | ||
131 | if idx != -1 { | ||
132 | key = key[:idx] | ||
133 | } | ||
134 | if _, ok := result[key]; ok { | ||
135 | continue | ||
136 | } | ||
137 | |||
138 | // skip the map count value | ||
139 | if key == "%" { | ||
140 | continue | ||
141 | } | ||
142 | |||
143 | result[key] = Expand(m, k[:len(prefix)+len(key)]) | ||
144 | } | ||
145 | |||
146 | return result | ||
147 | } | ||