Documentation ¶
Overview ¶
Package hclwrite deals with the problem of generating HCL configuration and of making specific surgical changes to existing HCL configurations.
It operates at a different level of abstraction than the main HCL parser and AST, since details such as the placement of comments and newlines are preserved when unchanged.
The hclwrite API follows a similar principle to XML/HTML DOM, allowing nodes to be read out, created and inserted, etc. Nodes represent syntax constructs rather than semantic concepts.
Example (GenerateFromScratch) ¶
package main import ( "fmt" "github.com/hashicorp/hcl2/hcl" "github.com/hashicorp/hcl2/hclwrite" "github.com/zclconf/go-cty/cty" ) func main() { f := hclwrite.NewEmptyFile() rootBody := f.Body() rootBody.SetAttributeValue("string", cty.StringVal("bar")) // this is overwritten later rootBody.AppendNewline() rootBody.SetAttributeValue("object", cty.ObjectVal(map[string]cty.Value{ "foo": cty.StringVal("foo"), "bar": cty.NumberIntVal(5), "baz": cty.True, })) rootBody.SetAttributeValue("string", cty.StringVal("foo")) rootBody.SetAttributeValue("bool", cty.False) rootBody.SetAttributeTraversal("path", hcl.Traversal{ hcl.TraverseRoot{ Name: "env", }, hcl.TraverseAttr{ Name: "PATH", }, }) rootBody.AppendNewline() fooBlock := rootBody.AppendNewBlock("foo", nil) fooBody := fooBlock.Body() rootBody.AppendNewBlock("empty", nil) rootBody.AppendNewline() barBlock := rootBody.AppendNewBlock("bar", []string{"a", "b"}) barBody := barBlock.Body() fooBody.SetAttributeValue("hello", cty.StringVal("world")) bazBlock := barBody.AppendNewBlock("baz", nil) bazBody := bazBlock.Body() bazBody.SetAttributeValue("foo", cty.NumberIntVal(10)) bazBody.SetAttributeValue("beep", cty.StringVal("boop")) bazBody.SetAttributeValue("baz", cty.ListValEmpty(cty.String)) fmt.Printf("%s", f.Bytes()) }
Output: string = "foo" object = { bar = 5, baz = true, foo = "foo" } bool = false path = env.PATH foo { hello = "world" } empty { } bar "a" "b" { baz { foo = 10 beep = "boop" baz = [] } }
Index ¶
- func Format(src []byte) []byte
- type Attribute
- type Block
- type Body
- func (b *Body) AppendBlock(block *Block) *Block
- func (b *Body) AppendNewBlock(typeName string, labels []string) *Block
- func (b *Body) AppendNewline()
- func (b *Body) AppendUnstructuredTokens(ts Tokens)
- func (b *Body) Attributes() map[string]*Attribute
- func (b *Body) Blocks() []*Block
- func (it *Body) BuildTokens(to Tokens) Tokens
- func (b *Body) Clear()
- func (b *Body) GetAttribute(name string) *Attribute
- func (b *Body) SetAttributeTraversal(name string, traversal hcl.Traversal) *Attribute
- func (b *Body) SetAttributeValue(name string, val cty.Value) *Attribute
- type Expression
- type File
- type Token
- type Tokens
- type Traversal
- type TraverseIndex
- type TraverseName
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Format ¶
Format takes source code and performs simple whitespace changes to transform it to a canonical layout style.
Format skips constructing an AST and works directly with tokens, so it is less expensive than formatting via the AST for situations where no other changes will be made. It also ignores syntax errors and can thus be applied to partial source code, although the result in that case may not be desirable.
Types ¶
type Attribute ¶
type Attribute struct {
// contains filtered or unexported fields
}
func (*Attribute) BuildTokens ¶
func (*Attribute) Expr ¶
func (a *Attribute) Expr() *Expression
type Block ¶
type Block struct {
// contains filtered or unexported fields
}
func (*Block) Body ¶
Body returns the body that represents the content of the receiving block.
Appending to or otherwise modifying this body will make changes to the tokens that are generated between the blocks open and close braces.
func (*Block) BuildTokens ¶
type Body ¶
type Body struct {
// contains filtered or unexported fields
}
func (*Body) AppendBlock ¶
AppendBlock appends an existing block (which must not be already attached to a body) to the end of the receiving body.
func (*Body) AppendNewBlock ¶
AppendNewBlock appends a new nested block to the end of the receiving body with the given type name and labels.
func (*Body) AppendNewline ¶
func (b *Body) AppendNewline()
AppendNewline appends a newline token to th end of the receiving body, which generally serves as a separator between different sets of body contents.
func (*Body) AppendUnstructuredTokens ¶
func (*Body) Attributes ¶
Attributes returns a new map of all of the attributes in the body, with the attribute names as the keys.
func (*Body) BuildTokens ¶
func (*Body) Clear ¶
func (b *Body) Clear()
Clear removes all of the items from the body, making it empty.
func (*Body) GetAttribute ¶
GetAttribute returns the attribute from the body that has the given name, or returns nil if there is currently no matching attribute.
func (*Body) SetAttributeTraversal ¶
SetAttributeTraversal either replaces the expression of an existing attribute of the given name or adds a new attribute definition to the end of the body.
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 (*Body) SetAttributeValue ¶
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.
type Expression ¶
type Expression struct {
// contains filtered or unexported fields
}
func NewExpressionAbsTraversal ¶
func NewExpressionAbsTraversal(traversal hcl.Traversal) *Expression
NewExpressionAbsTraversal constructs an expression that represents the given traversal, which must be absolute or this function will panic.
func NewExpressionLiteral ¶
func NewExpressionLiteral(val cty.Value) *Expression
NewExpressionLiteral constructs an an expression that represents the given literal value.
Since an unknown value cannot be represented in source code, this function will panic if the given value is unknown or contains a nested unknown value. Use val.IsWhollyKnown before calling to be sure.
HCL native syntax does not directly represent lists, maps, and sets, and instead relies on the automatic conversions to those collection types from either list or tuple constructor syntax. Therefore converting collection values to source code and re-reading them will lose type information, and the reader must provide a suitable type at decode time to recover the original value.
func (*Expression) BuildTokens ¶
func (*Expression) RenameVariablePrefix ¶
func (e *Expression) RenameVariablePrefix(search, replacement []string)
RenameVariablePrefix examines each of the absolute traversals in the receiving expression to see if they have the given sequence of names as a prefix prefix. If so, they are updated in place to have the given replacement names instead of that prefix.
This can be used to implement symbol renaming. The calling application can visit all relevant expressions in its input and apply the same renaming to implement a global symbol rename.
The search and replacement traversals must be the same length, or this method will panic. Only attribute access operations can be matched and replaced. Index steps never match the prefix.
Example ¶
package main import ( "fmt" "github.com/hashicorp/hcl2/hcl" "github.com/hashicorp/hcl2/hclwrite" ) func main() { src := []byte( "foo = a.x + a.y * b.c\n" + "bar = max(a.z, b.c)\n", ) f, diags := hclwrite.ParseConfig(src, "", hcl.Pos{Line: 1, Column: 1}) if diags.HasErrors() { fmt.Printf("errors: %s", diags) return } // Rename references of variable "a" to "z" for _, attr := range f.Body().Attributes() { attr.Expr().RenameVariablePrefix( []string{"a"}, []string{"z"}, ) } fmt.Printf("%s", f.Bytes()) }
Output: foo = z.x + z.y * b.c bar = max(z.z, b.c)
func (*Expression) Variables ¶
func (e *Expression) Variables() []*Traversal
Variables returns the absolute traversals that exist within the receiving expression.
type File ¶
type File struct {
// contains filtered or unexported fields
}
func NewEmptyFile ¶
func NewEmptyFile() *File
NewEmptyFile constructs a new file with no content, ready to be mutated by other calls that append to its body.
func NewFile ¶
func NewFile() *File
NewFile creates a new file object that is empty and ready to have constructs added t it.
func ParseConfig ¶
ParseConfig interprets the given source bytes into a *hclwrite.File. The resulting AST can be used to perform surgical edits on the source code before turning it back into bytes again.
func (*File) Body ¶
Body returns the root body of the file, which contains the top-level attributes and blocks.
func (*File) BuildTokens ¶
type Token ¶
type Token struct { Type hclsyntax.TokenType Bytes []byte // We record the number of spaces before each token so that we can // reproduce the exact layout of the original file when we're making // surgical changes in-place. When _new_ code is created it will always // be in the canonical style, but we preserve layout of existing code. SpacesBefore int }
Token is a single sequence of bytes annotated with a type. It is similar in purpose to hclsyntax.Token, but discards the source position information since that is not useful in code generation.
type Tokens ¶
type Tokens []*Token
Tokens is a flat list of tokens.
func TokensForTraversal ¶
TokensForTraversal returns a sequence of tokens that represents the given traversal.
If the traversal is absolute then the result is a self-contained, valid reference expression. If the traversal is relative then the returned tokens could be appended to some other expression tokens to traverse into the represented expression.
func TokensForValue ¶
TokensForValue returns a sequence of tokens that represents the given constant value.
This function only supports types that are used by HCL. In particular, it does not support capsule types and will panic if given one.
It is not possible to express an unknown value in source code, so this function will panic if the given value is unknown or contains any unknown values. A caller can call the value's IsWhollyKnown method to verify that no unknown values are present before calling TokensForValue.
func (Tokens) BuildTokens ¶
type Traversal ¶
type Traversal struct {
// contains filtered or unexported fields
}
Traversal represents a sequence of variable, attribute, and/or index operations.
func (*Traversal) BuildTokens ¶
type TraverseIndex ¶
type TraverseIndex struct {
// contains filtered or unexported fields
}
func (*TraverseIndex) BuildTokens ¶
type TraverseName ¶
type TraverseName struct {
// contains filtered or unexported fields
}