cai2hcl/common/hcl_write.go (63 lines of code) (raw):
package common
import (
"fmt"
"github.com/hashicorp/hcl/hcl/printer"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/zclconf/go-cty/cty"
)
// HclWriteBlocks prints HCLResourceBlock objects as string.
func HclWriteBlocks(blocks []*HCLResourceBlock) ([]byte, error) {
f := hclwrite.NewFile()
rootBody := f.Body()
for _, resourceBlock := range blocks {
hclBlock := rootBody.AppendNewBlock("resource", resourceBlock.Labels)
if err := hclWriteBlock(resourceBlock.Value, hclBlock.Body()); err != nil {
return nil, err
}
}
return printer.Format(f.Bytes())
}
func hclWriteBlock(val cty.Value, body *hclwrite.Body) error {
if val.IsNull() {
return nil
}
if !val.Type().IsObjectType() {
return fmt.Errorf("expect object type only, but type = %s", val.Type().FriendlyName())
}
it := val.ElementIterator()
for it.Next() {
objKey, objVal := it.Element()
if objVal.IsNull() {
continue
}
objValType := objVal.Type()
switch {
case objValType.IsObjectType():
newBlock := body.AppendNewBlock(objKey.AsString(), nil)
if err := hclWriteBlock(objVal, newBlock.Body()); err != nil {
return err
}
case objValType.IsCollectionType():
if objVal.LengthInt() == 0 {
continue
}
// Presumes map should not contain object type.
if !objValType.IsMapType() && objValType.ElementType().IsObjectType() {
listIterator := objVal.ElementIterator()
for listIterator.Next() {
_, listVal := listIterator.Element()
subBlock := body.AppendNewBlock(objKey.AsString(), nil)
if err := hclWriteBlock(listVal, subBlock.Body()); err != nil {
return err
}
}
continue
}
fallthrough
default:
if objValType.FriendlyName() == "string" && objVal.AsString() == "" {
continue
}
body.SetAttributeValue(objKey.AsString(), objVal)
}
}
return nil
}