]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/configs/module_merge_body.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / configs / module_merge_body.go
CommitLineData
107c1cdb
ND
1package configs
2
3import (
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.
15func 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.
34type mergeBody struct {
35 Base hcl.Body
36 Override hcl.Body
37}
38
39var _ hcl.Body = mergeBody{}
40
41func (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
56func (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
73func (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
122func (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
141func (b mergeBody) MissingItemRange() hcl.Range {
142 return b.Base.MissingItemRange()
143}