3 // Merge merges two configurations into a single configuration.
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) {
12 unknowns := make(map[string]struct{})
13 for _, k := range c1.unknownKeys {
14 _, present := unknowns[k]
16 unknowns[k] = struct{}{}
17 c.unknownKeys = append(c.unknownKeys, k)
20 for _, k := range c2.unknownKeys {
21 _, present := unknowns[k]
23 unknowns[k] = struct{}{}
24 c.unknownKeys = append(c.unknownKeys, k)
28 // Merge Atlas configuration. This is a dumb one overrides the other
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)
42 c.Terraform = c2.Terraform
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.
53 var m1, m2, mresult []merger
56 m1 = make([]merger, 0, len(c1.Modules))
57 m2 = make([]merger, 0, len(c2.Modules))
58 for _, v := range c1.Modules {
61 for _, v := range c2.Modules {
64 mresult = mergeSlice(m1, m2)
66 c.Modules = make([]*Module, len(mresult))
67 for i, v := range mresult {
68 c.Modules[i] = v.(*Module)
73 m1 = make([]merger, 0, len(c1.Outputs))
74 m2 = make([]merger, 0, len(c2.Outputs))
75 for _, v := range c1.Outputs {
78 for _, v := range c2.Outputs {
81 mresult = mergeSlice(m1, m2)
83 c.Outputs = make([]*Output, len(mresult))
84 for i, v := range mresult {
85 c.Outputs[i] = v.(*Output)
90 m1 = make([]merger, 0, len(c1.ProviderConfigs))
91 m2 = make([]merger, 0, len(c2.ProviderConfigs))
92 for _, v := range c1.ProviderConfigs {
95 for _, v := range c2.ProviderConfigs {
98 mresult = mergeSlice(m1, m2)
100 c.ProviderConfigs = make([]*ProviderConfig, len(mresult))
101 for i, v := range mresult {
102 c.ProviderConfigs[i] = v.(*ProviderConfig)
107 m1 = make([]merger, 0, len(c1.Resources))
108 m2 = make([]merger, 0, len(c2.Resources))
109 for _, v := range c1.Resources {
112 for _, v := range c2.Resources {
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)
124 m1 = make([]merger, 0, len(c1.Variables))
125 m2 = make([]merger, 0, len(c2.Variables))
126 for _, v := range c1.Variables {
129 for _, v := range c2.Variables {
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)
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 {
148 mergerMerge(merger) merger
151 // mergeSlice merges a slice of mergers.
152 func mergeSlice(m1, m2 []merger) []merger {
153 r := make([]merger, len(m1), len(m1)+len(m2))
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 {
167 // Find an original to override
170 for i, v := range m1 {
171 if v.mergerName() == name {
182 v = original.mergerMerge(v2)
185 if originalIndex == -1 {