]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
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 | } |