mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
cc38e91612
mergeBody is a hcl.Body implementation that deals with our override file merging behavior for the portions of the configuration that are not processed until full eval time. Mimicking the behavior of our old config merge implementation from the "config" package, the rules here are: - Attributes in the override body hide attributes of the same name in the base body. - Any block in the override body hides all blocks with the same type name that appear in the base body. This is tested by a new test for the overriding of module arguments, which asserts the correct behavior of the merged body as part of its work.
122 lines
3.5 KiB
Go
122 lines
3.5 KiB
Go
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()
|
|
}
|