diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/merge.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/config/merge.go | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/merge.go b/vendor/github.com/hashicorp/terraform/config/merge.go new file mode 100644 index 0000000..db214be --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/config/merge.go | |||
@@ -0,0 +1,193 @@ | |||
1 | package config | ||
2 | |||
3 | // Merge merges two configurations into a single configuration. | ||
4 | // | ||
5 | // Merge allows for the two configurations to have duplicate resources, | ||
6 | // because the resources will be merged. This differs from a single | ||
7 | // Config which must only have unique resources. | ||
8 | func Merge(c1, c2 *Config) (*Config, error) { | ||
9 | c := new(Config) | ||
10 | |||
11 | // Merge unknown keys | ||
12 | unknowns := make(map[string]struct{}) | ||
13 | for _, k := range c1.unknownKeys { | ||
14 | _, present := unknowns[k] | ||
15 | if !present { | ||
16 | unknowns[k] = struct{}{} | ||
17 | c.unknownKeys = append(c.unknownKeys, k) | ||
18 | } | ||
19 | } | ||
20 | for _, k := range c2.unknownKeys { | ||
21 | _, present := unknowns[k] | ||
22 | if !present { | ||
23 | unknowns[k] = struct{}{} | ||
24 | c.unknownKeys = append(c.unknownKeys, k) | ||
25 | } | ||
26 | } | ||
27 | |||
28 | // Merge Atlas configuration. This is a dumb one overrides the other | ||
29 | // sort of merge. | ||
30 | c.Atlas = c1.Atlas | ||
31 | if c2.Atlas != nil { | ||
32 | c.Atlas = c2.Atlas | ||
33 | } | ||
34 | |||
35 | // Merge the Terraform configuration | ||
36 | if c1.Terraform != nil { | ||
37 | c.Terraform = c1.Terraform | ||
38 | if c2.Terraform != nil { | ||
39 | c.Terraform.Merge(c2.Terraform) | ||
40 | } | ||
41 | } else { | ||
42 | c.Terraform = c2.Terraform | ||
43 | } | ||
44 | |||
45 | // NOTE: Everything below is pretty gross. Due to the lack of generics | ||
46 | // in Go, there is some hoop-jumping involved to make this merging a | ||
47 | // little more test-friendly and less repetitive. Ironically, making it | ||
48 | // less repetitive involves being a little repetitive, but I prefer to | ||
49 | // be repetitive with things that are less error prone than things that | ||
50 | // are more error prone (more logic). Type conversions to an interface | ||
51 | // are pretty low-error. | ||
52 | |||
53 | var m1, m2, mresult []merger | ||
54 | |||
55 | // Modules | ||
56 | m1 = make([]merger, 0, len(c1.Modules)) | ||
57 | m2 = make([]merger, 0, len(c2.Modules)) | ||
58 | for _, v := range c1.Modules { | ||
59 | m1 = append(m1, v) | ||
60 | } | ||
61 | for _, v := range c2.Modules { | ||
62 | m2 = append(m2, v) | ||
63 | } | ||
64 | mresult = mergeSlice(m1, m2) | ||
65 | if len(mresult) > 0 { | ||
66 | c.Modules = make([]*Module, len(mresult)) | ||
67 | for i, v := range mresult { | ||
68 | c.Modules[i] = v.(*Module) | ||
69 | } | ||
70 | } | ||
71 | |||
72 | // Outputs | ||
73 | m1 = make([]merger, 0, len(c1.Outputs)) | ||
74 | m2 = make([]merger, 0, len(c2.Outputs)) | ||
75 | for _, v := range c1.Outputs { | ||
76 | m1 = append(m1, v) | ||
77 | } | ||
78 | for _, v := range c2.Outputs { | ||
79 | m2 = append(m2, v) | ||
80 | } | ||
81 | mresult = mergeSlice(m1, m2) | ||
82 | if len(mresult) > 0 { | ||
83 | c.Outputs = make([]*Output, len(mresult)) | ||
84 | for i, v := range mresult { | ||
85 | c.Outputs[i] = v.(*Output) | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // Provider Configs | ||
90 | m1 = make([]merger, 0, len(c1.ProviderConfigs)) | ||
91 | m2 = make([]merger, 0, len(c2.ProviderConfigs)) | ||
92 | for _, v := range c1.ProviderConfigs { | ||
93 | m1 = append(m1, v) | ||
94 | } | ||
95 | for _, v := range c2.ProviderConfigs { | ||
96 | m2 = append(m2, v) | ||
97 | } | ||
98 | mresult = mergeSlice(m1, m2) | ||
99 | if len(mresult) > 0 { | ||
100 | c.ProviderConfigs = make([]*ProviderConfig, len(mresult)) | ||
101 | for i, v := range mresult { | ||
102 | c.ProviderConfigs[i] = v.(*ProviderConfig) | ||
103 | } | ||
104 | } | ||
105 | |||
106 | // Resources | ||
107 | m1 = make([]merger, 0, len(c1.Resources)) | ||
108 | m2 = make([]merger, 0, len(c2.Resources)) | ||
109 | for _, v := range c1.Resources { | ||
110 | m1 = append(m1, v) | ||
111 | } | ||
112 | for _, v := range c2.Resources { | ||
113 | m2 = append(m2, v) | ||
114 | } | ||
115 | mresult = mergeSlice(m1, m2) | ||
116 | if len(mresult) > 0 { | ||
117 | c.Resources = make([]*Resource, len(mresult)) | ||
118 | for i, v := range mresult { | ||
119 | c.Resources[i] = v.(*Resource) | ||
120 | } | ||
121 | } | ||
122 | |||
123 | // Variables | ||
124 | m1 = make([]merger, 0, len(c1.Variables)) | ||
125 | m2 = make([]merger, 0, len(c2.Variables)) | ||
126 | for _, v := range c1.Variables { | ||
127 | m1 = append(m1, v) | ||
128 | } | ||
129 | for _, v := range c2.Variables { | ||
130 | m2 = append(m2, v) | ||
131 | } | ||
132 | mresult = mergeSlice(m1, m2) | ||
133 | if len(mresult) > 0 { | ||
134 | c.Variables = make([]*Variable, len(mresult)) | ||
135 | for i, v := range mresult { | ||
136 | c.Variables[i] = v.(*Variable) | ||
137 | } | ||
138 | } | ||
139 | |||
140 | return c, nil | ||
141 | } | ||
142 | |||
143 | // merger is an interface that must be implemented by types that are | ||
144 | // merge-able. This simplifies the implementation of Merge for the various | ||
145 | // components of a Config. | ||
146 | type merger interface { | ||
147 | mergerName() string | ||
148 | mergerMerge(merger) merger | ||
149 | } | ||
150 | |||
151 | // mergeSlice merges a slice of mergers. | ||
152 | func mergeSlice(m1, m2 []merger) []merger { | ||
153 | r := make([]merger, len(m1), len(m1)+len(m2)) | ||
154 | copy(r, m1) | ||
155 | |||
156 | m := map[string]struct{}{} | ||
157 | for _, v2 := range m2 { | ||
158 | // If we already saw it, just append it because its a | ||
159 | // duplicate and invalid... | ||
160 | name := v2.mergerName() | ||
161 | if _, ok := m[name]; ok { | ||
162 | r = append(r, v2) | ||
163 | continue | ||
164 | } | ||
165 | m[name] = struct{}{} | ||
166 | |||
167 | // Find an original to override | ||
168 | var original merger | ||
169 | originalIndex := -1 | ||
170 | for i, v := range m1 { | ||
171 | if v.mergerName() == name { | ||
172 | originalIndex = i | ||
173 | original = v | ||
174 | break | ||
175 | } | ||
176 | } | ||
177 | |||
178 | var v merger | ||
179 | if original == nil { | ||
180 | v = v2 | ||
181 | } else { | ||
182 | v = original.mergerMerge(v2) | ||
183 | } | ||
184 | |||
185 | if originalIndex == -1 { | ||
186 | r = append(r, v) | ||
187 | } else { | ||
188 | r[originalIndex] = v | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return r | ||
193 | } | ||