]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/flatmap/expand.go
e0b81b6410edb92ae71f4ff1dd6ccac03c6bc0cc
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / flatmap / expand.go
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 }