c8c208e083
For now, this is the only way to set an attribute, and so attributes can only be set to literal values. Later this will be generalized so that this is just a helper wrapper around a "SetAttribute" method that just uses a given expression, which then helps by constructing the expression from the value first.
138 lines
3.2 KiB
Go
138 lines
3.2 KiB
Go
package hclwrite
|
|
|
|
import (
|
|
"github.com/hashicorp/hcl2/hcl"
|
|
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
type Body struct {
|
|
inTree
|
|
|
|
items nodeSet
|
|
|
|
// indentLevel is the number of spaces that should appear at the start
|
|
// of lines added within this body.
|
|
indentLevel int
|
|
}
|
|
|
|
func (b *Body) appendItem(c nodeContent) *node {
|
|
nn := b.children.Append(c)
|
|
b.items.Add(nn)
|
|
return nn
|
|
}
|
|
|
|
func (b *Body) appendItemNode(nn *node) *node {
|
|
nn.assertUnattached()
|
|
b.children.AppendNode(nn)
|
|
b.items.Add(nn)
|
|
return nn
|
|
}
|
|
|
|
func (b *Body) AppendUnstructuredTokens(ts Tokens) {
|
|
b.inTree.children.Append(ts)
|
|
}
|
|
|
|
// GetAttribute returns the attribute from the body that has the given name,
|
|
// or returns nil if there is currently no matching attribute.
|
|
func (b *Body) GetAttribute(name string) *Attribute {
|
|
for n := range b.items {
|
|
if attr, isAttr := n.content.(*Attribute); isAttr {
|
|
nameObj := attr.name.content.(*identifier)
|
|
if nameObj.hasName(name) {
|
|
// We've found it!
|
|
return attr
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetAttributeValue either replaces the expression of an existing attribute
|
|
// of the given name or adds a new attribute definition to the end of the block.
|
|
//
|
|
// The value is given as a cty.Value, and must therefore be a literal. To set
|
|
// a variable reference or other traversal, use SetAttributeTraversal.
|
|
//
|
|
// The return value is the attribute that was either modified in-place or
|
|
// created.
|
|
func (b *Body) SetAttributeValue(name string, val cty.Value) *Attribute {
|
|
attr := b.GetAttribute(name)
|
|
expr := NewExpressionLiteral(val)
|
|
if attr != nil {
|
|
attr.expr = attr.expr.ReplaceWith(expr)
|
|
} else {
|
|
attr := newAttribute()
|
|
attr.init(name, expr)
|
|
b.appendItem(attr)
|
|
}
|
|
return attr
|
|
}
|
|
|
|
// SetAttributeTraversal either replaces the expression of an existing attribute
|
|
// of the given name or adds a new attribute definition to the end of the block.
|
|
//
|
|
// The new expression is given as a hcl.Traversal, which must be an absolute
|
|
// traversal. To set a literal value, use SetAttributeValue.
|
|
//
|
|
// The return value is the attribute that was either modified in-place or
|
|
// created.
|
|
func (b *Body) SetAttributeTraversal(name string, traversal hcl.Traversal) *Attribute {
|
|
panic("Body.SetAttributeTraversal not yet implemented")
|
|
}
|
|
|
|
type Attribute struct {
|
|
inTree
|
|
|
|
leadComments *node
|
|
name *node
|
|
expr *node
|
|
lineComments *node
|
|
}
|
|
|
|
func newAttribute() *Attribute {
|
|
return &Attribute{
|
|
inTree: newInTree(),
|
|
}
|
|
}
|
|
|
|
func (a *Attribute) init(name string, expr *Expression) {
|
|
expr.assertUnattached()
|
|
|
|
nameTok := newIdentToken(name)
|
|
nameObj := newIdentifier(nameTok)
|
|
a.leadComments = a.children.Append(newComments(nil))
|
|
a.name = a.children.Append(nameObj)
|
|
a.children.AppendUnstructuredTokens(Tokens{
|
|
{
|
|
Type: hclsyntax.TokenEqual,
|
|
Bytes: []byte{'='},
|
|
},
|
|
})
|
|
a.expr = a.children.Append(expr)
|
|
a.expr.list = a.children
|
|
a.lineComments = a.children.Append(newComments(nil))
|
|
a.children.AppendUnstructuredTokens(Tokens{
|
|
{
|
|
Type: hclsyntax.TokenNewline,
|
|
Bytes: []byte{'\n'},
|
|
},
|
|
})
|
|
}
|
|
|
|
func (a *Attribute) Expr() *Expression {
|
|
return a.expr.content.(*Expression)
|
|
}
|
|
|
|
type Block struct {
|
|
inTree
|
|
|
|
leadComments *node
|
|
typeName *node
|
|
labels nodeSet
|
|
open *node
|
|
body *node
|
|
close *node
|
|
}
|