]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/configs/module_merge_body.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / configs / module_merge_body.go
1 package configs
2
3 import (
4 "github.com/hashicorp/hcl2/hcl"
5 )
6
7 // MergeBodies creates a new HCL body that contains a combination of the
8 // given base and override bodies. Attributes and blocks defined in the
9 // override body take precedence over those of the same name defined in
10 // the base body.
11 //
12 // If any block of a particular type appears in "override" then it will
13 // replace _all_ of the blocks of the same type in "base" in the new
14 // body.
15 func MergeBodies(base, override hcl.Body) hcl.Body {
16 return mergeBody{
17 Base: base,
18 Override: override,
19 }
20 }
21
22 // mergeBody is a hcl.Body implementation that wraps a pair of other bodies
23 // and allows attributes and blocks within the override to take precedence
24 // over those defined in the base body.
25 //
26 // This is used to deal with dynamically-processed bodies in Module.mergeFile.
27 // It uses a shallow-only merging strategy where direct attributes defined
28 // in Override will override attributes of the same name in Base, while any
29 // blocks defined in Override will hide all blocks of the same type in Base.
30 //
31 // This cannot possibly "do the right thing" in all cases, because we don't
32 // have enough information about user intent. However, this behavior is intended
33 // to be reasonable for simple overriding use-cases.
34 type mergeBody struct {
35 Base hcl.Body
36 Override hcl.Body
37 }
38
39 var _ hcl.Body = mergeBody{}
40
41 func (b mergeBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
42 var diags hcl.Diagnostics
43 baseSchema := schemaWithDynamic(schema)
44 overrideSchema := schemaWithDynamic(schemaForOverrides(schema))
45
46 baseContent, _, cDiags := b.Base.PartialContent(baseSchema)
47 diags = append(diags, cDiags...)
48 overrideContent, _, cDiags := b.Override.PartialContent(overrideSchema)
49 diags = append(diags, cDiags...)
50
51 content := b.prepareContent(baseContent, overrideContent)
52
53 return content, diags
54 }
55
56 func (b mergeBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
57 var diags hcl.Diagnostics
58 baseSchema := schemaWithDynamic(schema)
59 overrideSchema := schemaWithDynamic(schemaForOverrides(schema))
60
61 baseContent, baseRemain, cDiags := b.Base.PartialContent(baseSchema)
62 diags = append(diags, cDiags...)
63 overrideContent, overrideRemain, cDiags := b.Override.PartialContent(overrideSchema)
64 diags = append(diags, cDiags...)
65
66 content := b.prepareContent(baseContent, overrideContent)
67
68 remain := MergeBodies(baseRemain, overrideRemain)
69
70 return content, remain, diags
71 }
72
73 func (b mergeBody) prepareContent(base *hcl.BodyContent, override *hcl.BodyContent) *hcl.BodyContent {
74 content := &hcl.BodyContent{
75 Attributes: make(hcl.Attributes),
76 }
77
78 // For attributes we just assign from each map in turn and let the override
79 // map clobber any matching entries from base.
80 for k, a := range base.Attributes {
81 content.Attributes[k] = a
82 }
83 for k, a := range override.Attributes {
84 content.Attributes[k] = a
85 }
86
87 // Things are a little more interesting for blocks because they arrive
88 // as a flat list. Our merging semantics call for us to suppress blocks
89 // from base if at least one block of the same type appears in override.
90 // We explicitly do not try to correlate and deeply merge nested blocks,
91 // since we don't have enough context here to infer user intent.
92
93 overriddenBlockTypes := make(map[string]bool)
94 for _, block := range override.Blocks {
95 if block.Type == "dynamic" {
96 overriddenBlockTypes[block.Labels[0]] = true
97 continue
98 }
99 overriddenBlockTypes[block.Type] = true
100 }
101 for _, block := range base.Blocks {
102 // We skip over dynamic blocks whose type label is an overridden type
103 // but note that below we do still leave them as dynamic blocks in
104 // the result because expanding the dynamic blocks that are left is
105 // done much later during the core graph walks, where we can safely
106 // evaluate the expressions.
107 if block.Type == "dynamic" && overriddenBlockTypes[block.Labels[0]] {
108 continue
109 }
110 if overriddenBlockTypes[block.Type] {
111 continue
112 }
113 content.Blocks = append(content.Blocks, block)
114 }
115 for _, block := range override.Blocks {
116 content.Blocks = append(content.Blocks, block)
117 }
118
119 return content
120 }
121
122 func (b mergeBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
123 var diags hcl.Diagnostics
124 ret := make(hcl.Attributes)
125
126 baseAttrs, aDiags := b.Base.JustAttributes()
127 diags = append(diags, aDiags...)
128 overrideAttrs, aDiags := b.Override.JustAttributes()
129 diags = append(diags, aDiags...)
130
131 for k, a := range baseAttrs {
132 ret[k] = a
133 }
134 for k, a := range overrideAttrs {
135 ret[k] = a
136 }
137
138 return ret, diags
139 }
140
141 func (b mergeBody) MissingItemRange() hcl.Range {
142 return b.Base.MissingItemRange()
143 }