github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/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  }