forked from hashicorp/terraform
-
Notifications
You must be signed in to change notification settings - Fork 2
/
module_merge_body.go
121 lines (98 loc) · 3.55 KB
/
module_merge_body.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package configs
import (
"github.com/hashicorp/hcl2/hcl"
)
func mergeBodies(base, override hcl.Body) hcl.Body {
return mergeBody{
Base: base,
Override: override,
}
}
// mergeBody is a hcl.Body implementation that wraps a pair of other bodies
// and allows attributes and blocks within the override to take precedence
// over those defined in the base body.
//
// This is used to deal with dynamically-processed bodies in Module.mergeFile.
// It uses a shallow-only merging strategy where direct attributes defined
// in Override will override attributes of the same name in Base, while any
// blocks defined in Override will hide all blocks of the same type in Base.
//
// This cannot possibly "do the right thing" in all cases, because we don't
// have enough information about user intent. However, this behavior is intended
// to be reasonable for simple overriding use-cases.
type mergeBody struct {
Base hcl.Body
Override hcl.Body
}
var _ hcl.Body = mergeBody{}
func (b mergeBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
var diags hcl.Diagnostics
oSchema := schemaForOverrides(schema)
baseContent, cDiags := b.Base.Content(schema)
diags = append(diags, cDiags...)
overrideContent, cDiags := b.Override.Content(oSchema)
diags = append(diags, cDiags...)
content := b.prepareContent(baseContent, overrideContent)
return content, diags
}
func (b mergeBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
var diags hcl.Diagnostics
oSchema := schemaForOverrides(schema)
baseContent, baseRemain, cDiags := b.Base.PartialContent(schema)
diags = append(diags, cDiags...)
overrideContent, overrideRemain, cDiags := b.Override.PartialContent(oSchema)
diags = append(diags, cDiags...)
content := b.prepareContent(baseContent, overrideContent)
remain := mergeBodies(baseRemain, overrideRemain)
return content, remain, diags
}
func (b mergeBody) prepareContent(base *hcl.BodyContent, override *hcl.BodyContent) *hcl.BodyContent {
content := &hcl.BodyContent{
Attributes: make(hcl.Attributes),
}
// For attributes we just assign from each map in turn and let the override
// map clobber any matching entries from base.
for k, a := range base.Attributes {
content.Attributes[k] = a
}
for k, a := range override.Attributes {
content.Attributes[k] = a
}
// Things are a little more interesting for blocks because they arrive
// as a flat list. Our merging semantics call for us to suppress blocks
// from base if at least one block of the same type appears in override.
// We explicitly do not try to correlate and deeply merge nested blocks,
// since we don't have enough context here to infer user intent.
overriddenBlockTypes := make(map[string]bool)
for _, block := range override.Blocks {
overriddenBlockTypes[block.Type] = true
}
for _, block := range base.Blocks {
if overriddenBlockTypes[block.Type] {
continue
}
content.Blocks = append(content.Blocks, block)
}
for _, block := range override.Blocks {
content.Blocks = append(content.Blocks, block)
}
return content
}
func (b mergeBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
var diags hcl.Diagnostics
ret := make(hcl.Attributes)
baseAttrs, aDiags := b.Base.JustAttributes()
diags = append(diags, aDiags...)
overrideAttrs, aDiags := b.Override.JustAttributes()
diags = append(diags, aDiags...)
for k, a := range baseAttrs {
ret[k] = a
}
for k, a := range overrideAttrs {
ret[k] = a
}
return ret, diags
}
func (b mergeBody) MissingItemRange() hcl.Range {
return b.Base.MissingItemRange()
}