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