pkg/terraform/root_block.go (182 lines of code) (raw):

package terraform import ( "sort" "strings" "github.com/Azure/golden" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/hashicorp/hcl/v2/hclwrite" "github.com/zclconf/go-cty/cty" ) var _ Block = new(RootBlock) var RootBlockReflectionInformation = func(v map[string]cty.Value, b *RootBlock) { var moduleObj = cty.ObjectVal(map[string]cty.Value{ "key": cty.StringVal(""), "version": cty.StringVal(""), "source": cty.StringVal(""), "dir": cty.StringVal(""), "abs_dir": cty.StringVal(""), "git_hash": cty.StringVal(""), }) if b.module != nil { moduleObj = cty.ObjectVal(map[string]cty.Value{ "key": cty.StringVal(b.module.Key), "version": cty.StringVal(b.module.Version), "source": cty.StringVal(b.module.Source), "dir": cty.StringVal(b.module.Dir), "abs_dir": cty.StringVal(b.module.AbsDir), "git_hash": cty.StringVal(b.module.GitHash), }) } labels := golden.ToCtyValue(b.Labels) v["mptf"] = cty.ObjectVal(map[string]cty.Value{ "block_address": cty.StringVal(b.Address), "terraform_address": cty.StringVal(blockAddressToRef(b.Address)), "block_type": cty.StringVal(b.Type), "block_labels": labels, "module": moduleObj, "range": cty.ObjectVal(map[string]cty.Value{ "file_name": cty.StringVal(b.Range().Filename), "start_line": cty.NumberIntVal(int64(b.Range().Start.Line)), "start_column": cty.NumberIntVal(int64(b.Range().Start.Column)), "end_line": cty.NumberIntVal(int64(b.Range().End.Line)), "end_column": cty.NumberIntVal(int64(b.Range().End.Column)), }), }) } func blockAddressToRef(address string) string { if strings.HasPrefix(address, "resource.") { return strings.TrimPrefix(address, "resource.") } return address } type RootBlock struct { *hclsyntax.Block module *Module WriteBlock *hclwrite.Block Count *Attribute ForEach *Attribute Attributes map[string]*Attribute NestedBlocks NestedBlocks Type string Labels []string Address string } func (b *RootBlock) RemoveContent(path string) { unlock := lockBlockFile(b) defer unlock() b.removeContent(b.WriteBlock, path) } func (b *RootBlock) removeContent(wb *hclwrite.Block, path string) { segs := strings.Split(path, ".") var nbs []*hclwrite.Block if wb.Type() == "dynamic" { nbs = wb.Body().Blocks() } for _, nb := range nbs { if nb.Type() != "content" { continue } wb = nb break } _, ok := wb.Body().Attributes()[segs[0]] if ok { wb.Body().RemoveAttribute(segs[0]) return } nbs = make([]*hclwrite.Block, 0) for _, nb := range wb.Body().Blocks() { if nb.Type() == segs[0] || (nb.Type() == "dynamic" && nb.Labels()[0] == segs[0]) { nbs = append(nbs, nb) } } if len(nbs) == 0 { return } if len(segs) == 1 { for _, nb := range nbs { wb.Body().RemoveBlock(nb) } return } for _, nb := range nbs { b.removeContent(nb, strings.Join(segs[1:], ".")) } } func (b *RootBlock) SetAttributeRaw(name string, tokens hclwrite.Tokens) { unlock := lockBlockFile(b) defer unlock() b.WriteBody().SetAttributeRaw(name, tokens) } func (b *RootBlock) AppendBlock(block *hclwrite.Block) { unlock := lockBlockFile(b) defer unlock() b.WriteBody().AppendBlock(block) } func (b *RootBlock) WriteBody() *hclwrite.Body { return b.WriteBlock.Body() } func (b *RootBlock) GetAttributes() map[string]*Attribute { return b.Attributes } func (b *RootBlock) GetNestedBlocks() NestedBlocks { return b.NestedBlocks } func NewBlock(m *Module, rb *hclsyntax.Block, wb *hclwrite.Block) *RootBlock { b := &RootBlock{ Type: rb.Type, Labels: rb.Labels, Address: strings.Join(append([]string{rb.Type}, rb.Labels...), "."), Block: rb, WriteBlock: wb, module: m, } if countAttr, ok := rb.Body.Attributes["count"]; ok { b.Count = NewAttribute("count", countAttr, wb.Body().GetAttribute("count")) } if forEachAttr, ok := rb.Body.Attributes["for_each"]; ok { b.ForEach = NewAttribute("for_each", forEachAttr, wb.Body().GetAttribute("for_each")) } b.Attributes = attributes(rb.Body, wb.Body()) b.NestedBlocks = nestedBlocks(rb.Body, wb.Body()) return b } func (b *RootBlock) EvalContext() cty.Value { v := map[string]cty.Value{} RootBlockReflectionInformation(v, b) for n, a := range b.Attributes { v[n] = cty.StringVal(a.String()) } if b.Count != nil { v["count"] = cty.StringVal(b.Count.String()) } if b.ForEach != nil { v["for_each"] = cty.StringVal(b.ForEach.String()) } for k, values := range b.NestedBlocks.Values() { v[k] = values } return cty.ObjectVal(v) } func attributes(rb *hclsyntax.Body, wb *hclwrite.Body) map[string]*Attribute { attributes := rb.Attributes r := make(map[string]*Attribute, len(attributes)) for name, attribute := range attributes { r[name] = NewAttribute(name, attribute, wb.GetAttribute(name)) } return r } func nestedBlocks(rb *hclsyntax.Body, wb *hclwrite.Body) NestedBlocks { blocks := rb.Blocks r := make(map[string][]*NestedBlock) for i, block := range blocks { nb := NewNestedBlock(block, wb.Blocks()[i]) r[nb.Type] = append(r[nb.Type], nb) } for _, v := range r { sort.Slice(v, func(i, j int) bool { return v[i].Range().Start.Line < v[j].Range().Start.Line }) } return r }