diff options
author | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
---|---|---|
committer | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
commit | bae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch) | |
tree | ca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go | |
parent | 254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff) | |
download | terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.gz terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.zst terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.zip |
Initial transfer of provider code
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go new file mode 100644 index 0000000..9533981 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go | |||
@@ -0,0 +1,232 @@ | |||
1 | package schema | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "strings" | ||
6 | ) | ||
7 | |||
8 | // MapFieldReader reads fields out of an untyped map[string]string to | ||
9 | // the best of its ability. | ||
10 | type MapFieldReader struct { | ||
11 | Map MapReader | ||
12 | Schema map[string]*Schema | ||
13 | } | ||
14 | |||
15 | func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) { | ||
16 | k := strings.Join(address, ".") | ||
17 | schemaList := addrToSchema(address, r.Schema) | ||
18 | if len(schemaList) == 0 { | ||
19 | return FieldReadResult{}, nil | ||
20 | } | ||
21 | |||
22 | schema := schemaList[len(schemaList)-1] | ||
23 | switch schema.Type { | ||
24 | case TypeBool, TypeInt, TypeFloat, TypeString: | ||
25 | return r.readPrimitive(address, schema) | ||
26 | case TypeList: | ||
27 | return readListField(r, address, schema) | ||
28 | case TypeMap: | ||
29 | return r.readMap(k, schema) | ||
30 | case TypeSet: | ||
31 | return r.readSet(address, schema) | ||
32 | case typeObject: | ||
33 | return readObjectField(r, address, schema.Elem.(map[string]*Schema)) | ||
34 | default: | ||
35 | panic(fmt.Sprintf("Unknown type: %s", schema.Type)) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | func (r *MapFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) { | ||
40 | result := make(map[string]interface{}) | ||
41 | resultSet := false | ||
42 | |||
43 | // If the name of the map field is directly in the map with an | ||
44 | // empty string, it means that the map is being deleted, so mark | ||
45 | // that is is set. | ||
46 | if v, ok := r.Map.Access(k); ok && v == "" { | ||
47 | resultSet = true | ||
48 | } | ||
49 | |||
50 | prefix := k + "." | ||
51 | r.Map.Range(func(k, v string) bool { | ||
52 | if strings.HasPrefix(k, prefix) { | ||
53 | resultSet = true | ||
54 | |||
55 | key := k[len(prefix):] | ||
56 | if key != "%" && key != "#" { | ||
57 | result[key] = v | ||
58 | } | ||
59 | } | ||
60 | |||
61 | return true | ||
62 | }) | ||
63 | |||
64 | err := mapValuesToPrimitive(result, schema) | ||
65 | if err != nil { | ||
66 | return FieldReadResult{}, nil | ||
67 | } | ||
68 | |||
69 | var resultVal interface{} | ||
70 | if resultSet { | ||
71 | resultVal = result | ||
72 | } | ||
73 | |||
74 | return FieldReadResult{ | ||
75 | Value: resultVal, | ||
76 | Exists: resultSet, | ||
77 | }, nil | ||
78 | } | ||
79 | |||
80 | func (r *MapFieldReader) readPrimitive( | ||
81 | address []string, schema *Schema) (FieldReadResult, error) { | ||
82 | k := strings.Join(address, ".") | ||
83 | result, ok := r.Map.Access(k) | ||
84 | if !ok { | ||
85 | return FieldReadResult{}, nil | ||
86 | } | ||
87 | |||
88 | returnVal, err := stringToPrimitive(result, false, schema) | ||
89 | if err != nil { | ||
90 | return FieldReadResult{}, err | ||
91 | } | ||
92 | |||
93 | return FieldReadResult{ | ||
94 | Value: returnVal, | ||
95 | Exists: true, | ||
96 | }, nil | ||
97 | } | ||
98 | |||
99 | func (r *MapFieldReader) readSet( | ||
100 | address []string, schema *Schema) (FieldReadResult, error) { | ||
101 | // Get the number of elements in the list | ||
102 | countRaw, err := r.readPrimitive( | ||
103 | append(address, "#"), &Schema{Type: TypeInt}) | ||
104 | if err != nil { | ||
105 | return FieldReadResult{}, err | ||
106 | } | ||
107 | if !countRaw.Exists { | ||
108 | // No count, means we have no list | ||
109 | countRaw.Value = 0 | ||
110 | } | ||
111 | |||
112 | // Create the set that will be our result | ||
113 | set := schema.ZeroValue().(*Set) | ||
114 | |||
115 | // If we have an empty list, then return an empty list | ||
116 | if countRaw.Computed || countRaw.Value.(int) == 0 { | ||
117 | return FieldReadResult{ | ||
118 | Value: set, | ||
119 | Exists: countRaw.Exists, | ||
120 | Computed: countRaw.Computed, | ||
121 | }, nil | ||
122 | } | ||
123 | |||
124 | // Go through the map and find all the set items | ||
125 | prefix := strings.Join(address, ".") + "." | ||
126 | countExpected := countRaw.Value.(int) | ||
127 | countActual := make(map[string]struct{}) | ||
128 | completed := r.Map.Range(func(k, _ string) bool { | ||
129 | if !strings.HasPrefix(k, prefix) { | ||
130 | return true | ||
131 | } | ||
132 | if strings.HasPrefix(k, prefix+"#") { | ||
133 | // Ignore the count field | ||
134 | return true | ||
135 | } | ||
136 | |||
137 | // Split the key, since it might be a sub-object like "idx.field" | ||
138 | parts := strings.Split(k[len(prefix):], ".") | ||
139 | idx := parts[0] | ||
140 | |||
141 | var raw FieldReadResult | ||
142 | raw, err = r.ReadField(append(address, idx)) | ||
143 | if err != nil { | ||
144 | return false | ||
145 | } | ||
146 | if !raw.Exists { | ||
147 | // This shouldn't happen because we just verified it does exist | ||
148 | panic("missing field in set: " + k + "." + idx) | ||
149 | } | ||
150 | |||
151 | set.Add(raw.Value) | ||
152 | |||
153 | // Due to the way multimap readers work, if we've seen the number | ||
154 | // of fields we expect, then exit so that we don't read later values. | ||
155 | // For example: the "set" map might have "ports.#", "ports.0", and | ||
156 | // "ports.1", but the "state" map might have those plus "ports.2". | ||
157 | // We don't want "ports.2" | ||
158 | countActual[idx] = struct{}{} | ||
159 | if len(countActual) >= countExpected { | ||
160 | return false | ||
161 | } | ||
162 | |||
163 | return true | ||
164 | }) | ||
165 | if !completed && err != nil { | ||
166 | return FieldReadResult{}, err | ||
167 | } | ||
168 | |||
169 | return FieldReadResult{ | ||
170 | Value: set, | ||
171 | Exists: true, | ||
172 | }, nil | ||
173 | } | ||
174 | |||
175 | // MapReader is an interface that is given to MapFieldReader for accessing | ||
176 | // a "map". This can be used to have alternate implementations. For a basic | ||
177 | // map[string]string, use BasicMapReader. | ||
178 | type MapReader interface { | ||
179 | Access(string) (string, bool) | ||
180 | Range(func(string, string) bool) bool | ||
181 | } | ||
182 | |||
183 | // BasicMapReader implements MapReader for a single map. | ||
184 | type BasicMapReader map[string]string | ||
185 | |||
186 | func (r BasicMapReader) Access(k string) (string, bool) { | ||
187 | v, ok := r[k] | ||
188 | return v, ok | ||
189 | } | ||
190 | |||
191 | func (r BasicMapReader) Range(f func(string, string) bool) bool { | ||
192 | for k, v := range r { | ||
193 | if cont := f(k, v); !cont { | ||
194 | return false | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return true | ||
199 | } | ||
200 | |||
201 | // MultiMapReader reads over multiple maps, preferring keys that are | ||
202 | // founder earlier (lower number index) vs. later (higher number index) | ||
203 | type MultiMapReader []map[string]string | ||
204 | |||
205 | func (r MultiMapReader) Access(k string) (string, bool) { | ||
206 | for _, m := range r { | ||
207 | if v, ok := m[k]; ok { | ||
208 | return v, ok | ||
209 | } | ||
210 | } | ||
211 | |||
212 | return "", false | ||
213 | } | ||
214 | |||
215 | func (r MultiMapReader) Range(f func(string, string) bool) bool { | ||
216 | done := make(map[string]struct{}) | ||
217 | for _, m := range r { | ||
218 | for k, v := range m { | ||
219 | if _, ok := done[k]; ok { | ||
220 | continue | ||
221 | } | ||
222 | |||
223 | if cont := f(k, v); !cont { | ||
224 | return false | ||
225 | } | ||
226 | |||
227 | done[k] = struct{}{} | ||
228 | } | ||
229 | } | ||
230 | |||
231 | return true | ||
232 | } | ||