pkg/terraform/nested_block.go (140 lines of code) (raw):
package terraform
import (
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/zclconf/go-cty/cty"
"strings"
)
var _ Block = new(NestedBlock)
type NestedBlocks map[string][]*NestedBlock
type NestedBlock struct {
Type string
*hclsyntax.Block
selfWriteBlock *hclwrite.Block
WriteBlock *hclwrite.Block
ForEach *Attribute
Iterator *Attribute
Attributes map[string]*Attribute
NestedBlocks NestedBlocks
}
func (nb *NestedBlock) RemoveContent(path string) {
segs := strings.Split(path, "/")
current := segs[0]
if len(segs) > 1 {
myNbs, ok := nb.NestedBlocks[current]
if !ok {
return
}
nextPath := strings.Join(segs[1:], "/")
for _, myNb := range myNbs {
myNb.RemoveContent(nextPath)
}
return
}
_, ok := nb.Attributes[current]
if ok {
nb.WriteBody().RemoveAttribute(current)
return
}
myNbs, ok := nb.NestedBlocks[current]
if !ok {
return
}
block := nb.WriteBlock
if nb.Type == "dynamic" {
contentBlock := nb.WriteBlock.Body().Blocks()[0]
block = contentBlock
}
for _, myNb := range myNbs {
block.Body().RemoveBlock(myNb.selfWriteBlock)
}
}
func (nb *NestedBlock) SetAttributeRaw(name string, tokens hclwrite.Tokens) {
unlock := lockBlockFile(nb)
defer unlock()
nb.WriteBody().SetAttributeRaw(name, tokens)
}
func (nb *NestedBlock) AppendBlock(block *hclwrite.Block) {
unlock := lockBlockFile(nb)
defer unlock()
nb.WriteBody().AppendBlock(block)
}
func (nb *NestedBlock) WriteBody() *hclwrite.Body {
return nb.WriteBlock.Body()
}
func (nb *NestedBlock) GetAttributes() map[string]*Attribute {
return nb.Attributes
}
func (nb *NestedBlock) GetNestedBlocks() NestedBlocks {
return nb.NestedBlocks
}
func NewNestedBlock(rb *hclsyntax.Block, wb *hclwrite.Block) *NestedBlock {
if rb.Type == "dynamic" {
return dynamicNestedBlock(rb, wb)
}
return staticNestedBlock(rb, wb)
}
func (nb *NestedBlock) EvalContext() cty.Value {
v := map[string]cty.Value{}
for n, a := range nb.Attributes {
v[n] = cty.StringVal(a.String())
}
if nb.ForEach != nil {
v["for_each"] = cty.StringVal(nb.ForEach.String())
}
if nb.Iterator != nil {
v["iterator"] = cty.StringVal(nb.Iterator.String())
}
for k, nbv := range nb.NestedBlocks.Values() {
v[k] = nbv
}
v["mptf"] = nb.MptfObject()
return cty.ObjectVal(v)
}
func (nb *NestedBlock) String() string {
return string(nb.selfWriteBlock.BuildTokens(nil).Bytes())
}
func (nb *NestedBlock) MptfObject() cty.Value {
v := map[string]cty.Value{}
v["tostring"] = cty.StringVal(nb.String())
v["range"] = cty.ObjectVal(map[string]cty.Value{
"file_name": cty.StringVal(nb.Range().Filename),
"start_line": cty.NumberIntVal(int64(nb.Range().Start.Line)),
"start_column": cty.NumberIntVal(int64(nb.Range().Start.Column)),
"end_line": cty.NumberIntVal(int64(nb.Range().End.Line)),
"end_column": cty.NumberIntVal(int64(nb.Range().End.Column)),
})
return cty.ObjectVal(v)
}
func (nbs NestedBlocks) Values() map[string]cty.Value {
v := map[string]cty.Value{}
for k, blocks := range nbs {
v[k] = ListOfObject(blocks)
}
return v
}
func dynamicNestedBlock(rb *hclsyntax.Block, wb *hclwrite.Block) *NestedBlock {
nb := &NestedBlock{
Type: rb.Labels[0],
selfWriteBlock: wb,
Block: rb.Body.Blocks[0],
WriteBlock: wb.Body().Blocks()[0],
ForEach: NewAttribute("for_each", rb.Body.Attributes["for_each"], wb.Body().GetAttribute("for_each")),
Attributes: attributes(rb.Body.Blocks[0].Body, wb.Body().Blocks()[0].Body()),
NestedBlocks: nestedBlocks(rb.Body.Blocks[0].Body, wb.Body().Blocks()[0].Body()),
}
if iteratorAttr, ok := rb.Body.Attributes["iterator"]; ok {
nb.Iterator = NewAttribute("iterator", iteratorAttr, wb.Body().GetAttribute("iterator"))
}
return nb
}
func staticNestedBlock(rb *hclsyntax.Block, wb *hclwrite.Block) *NestedBlock {
return &NestedBlock{
Type: rb.Type,
Block: rb,
selfWriteBlock: wb,
WriteBlock: wb,
Attributes: attributes(rb.Body, wb.Body()),
NestedBlocks: nestedBlocks(rb.Body, wb.Body()),
}
}