Documentation
¶
Overview ¶
Package hclparse provides two-phase HCL parsing for stack files with support for autoinclude blocks and deferred evaluation.
Index ¶
- Constants
- func AutoIncludeDependencyPaths(fs vfs.FS, unitDir string) ([]string, error)
- func AutoIncludeFileNameForKind(kind AutoIncludeKind) string
- func AutoIncludeKey(kind AutoIncludeKind, name string) string
- func BuildAutoIncludeEvalContext(unitRefs, stackRefs []ComponentRef) *hcl.EvalContext
- func BuildComponentRefMap(refs []ComponentRef) cty.Value
- func CommentTokens(text string) hclwrite.Tokens
- func FindBlock(body *hclsyntax.Body, blockType, label string) *hclsyntax.Block
- func GenerateAutoIncludeFile(fs vfs.FS, resolved *AutoIncludeResolved, targetDir string, srcBytes []byte, ...) error
- func HCLStringContent(s string) []byte
- func IsPure(expr hclsyntax.Expression, deferred map[string]bool) bool
- func PartialEval(expr hclsyntax.Expression, args *EvalArgs) []byte
- func RangeBytes(src []byte, r hcl.Range) []byte
- func RawTokens(b []byte) hclwrite.Tokens
- func SortedAttributes(attrs hclsyntax.Attributes) []*hclsyntax.Attribute
- func UnitPathsFromStackDir(fs vfs.FS, stackDir string) ([]string, error)
- func ValueToHCLBytes(val cty.Value) []byte
- type AutoIncludeDependency
- type AutoIncludeHCL
- type AutoIncludeKind
- type AutoIncludeResolved
- type ComponentRef
- type Copier
- type DirCreateError
- type DuplicateStackNameError
- type DuplicateUnitNameError
- type EmptyArgError
- type EvalArgs
- type FileDecodeError
- type FileParseError
- type FileReadError
- type FileWriteError
- type IncludeValidationError
- type LocalEvalError
- type LocalsCycleError
- type LocalsHCL
- type LocalsMaxIterError
- type MalformedDependencyError
- type ParseResult
- type ParseStackFileInput
- type StackBlockHCL
- type StackFileHCL
- type StackIncludeHCL
- type UnexpectedBodyTypeError
- type UnitBlockHCL
Constants ¶
const ( // AutoIncludeFile is the filename for generated unit-level autoinclude files. AutoIncludeFile = "terragrunt.autoinclude.hcl" // AutoIncludeStackFile is the filename for generated stack-level autoinclude files; the .stack.hcl suffix mirrors terragrunt.stack.hcl so tooling (LSP, read_terragrunt_config) can distinguish unit vs stack autoincludes by name. AutoIncludeStackFile = "terragrunt.autoinclude.stack.hcl" )
const (
// StackDir is the directory name where generated stack components are placed.
StackDir = ".terragrunt-stack"
)
Variables ¶
This section is empty.
Functions ¶
func AutoIncludeDependencyPaths ¶
AutoIncludeDependencyPaths reads the autoinclude file in unitDir and returns resolved dependency config_path values. Returns EmptyArgError when unitDir is empty so callers can distinguish bad input from a missing file.
func AutoIncludeFileNameForKind ¶ added in v1.0.4
func AutoIncludeFileNameForKind(kind AutoIncludeKind) string
AutoIncludeFileNameForKind returns the autoinclude filename to generate for the given kind. Panics on unknown kinds (programmer error) so a misspelled or missing kind cannot silently produce the wrong filename.
func AutoIncludeKey ¶
func AutoIncludeKey(kind AutoIncludeKind, name string) string
AutoIncludeKey returns the map key for an autoinclude entry, namespaced by component kind to prevent collisions between same-name units and stacks.
func BuildAutoIncludeEvalContext ¶
func BuildAutoIncludeEvalContext(unitRefs, stackRefs []ComponentRef) *hcl.EvalContext
BuildAutoIncludeEvalContext creates an HCL evaluation context with unit and stack path references for resolving autoinclude blocks.
The context provides:
- unit.<name>.path - resolved path of each unit in the stack
- unit.<name>.name - name label of each unit
- stack.<name>.path - resolved path of each stack in the stack
- stack.<name>.name - name label of each stack
Additional variables (locals, values) can be merged into the returned context by the caller.
func BuildComponentRefMap ¶
func BuildComponentRefMap(refs []ComponentRef) cty.Value
BuildComponentRefMap creates a cty.Value map from a slice of ComponentRef. The resulting value is an object like:
{
"unit_name": { "path": "../relative/path", "name": "unit_name" }
}
For stack refs with children, it also includes nested unit refs:
{
"stack_name": {
"path": "/abs/path",
"name": "stack_name",
"unit_name": { "path": "/abs/path/to/unit", "name": "unit_name" }
}
}
This is injected into the HCL eval context as the `unit` or `stack` variable.
func CommentTokens ¶
CommentTokens creates a comment token for hclwrite.
func FindBlock ¶
FindBlock finds a block by type and first label in the AST body. Exported for reuse by callers that need to locate specific blocks in parsed HCL bodies.
func GenerateAutoIncludeFile ¶
func GenerateAutoIncludeFile(fs vfs.FS, resolved *AutoIncludeResolved, targetDir string, srcBytes []byte, evalCtx *hcl.EvalContext) error
GenerateAutoIncludeFile writes a terragrunt.autoinclude.hcl file in the given directory from a resolved autoinclude.
The generated file contains:
- dependency blocks with resolved config_path and all other attributes (mock_outputs, mock_outputs_allowed_terraform_commands, etc.) copied from the original AST source bytes.
- All non-dependency content (inputs, retry blocks, etc.) copied verbatim from the original AST source bytes: dependency.*.outputs.* references are preserved without evaluation.
Requires non-nil fs and non-empty targetDir (panics otherwise). resolved may be nil (no-op). srcBytes must be the bytes of the file resolved.RawBody was parsed from; for includes pass resolved.SourceBytes. evalCtx may be nil.
func HCLStringContent ¶
HCLStringContent returns the inner content of an HCL-escaped string (without surrounding quotes). Uses hclwrite.TokensForValue for correct escaping of all HCL special characters.
func IsPure ¶
func IsPure(expr hclsyntax.Expression, deferred map[string]bool) bool
IsPure returns true if the expression has no references to deferred root names.
func PartialEval ¶
func PartialEval(expr hclsyntax.Expression, args *EvalArgs) []byte
PartialEval walks an hclsyntax.Expression tree and returns HCL source text. Pure expressions (no deferred refs) are fully evaluated to literals. Mixed expressions get per-child treatment: evaluable parts become literals, deferred parts keep their original source text.
func RangeBytes ¶
RangeBytes extracts the source bytes for the given range.
func RawTokens ¶
RawTokens wraps raw bytes as a single hclwrite token. hclwrite.Format will handle the final formatting of the output.
func SortedAttributes ¶
func SortedAttributes(attrs hclsyntax.Attributes) []*hclsyntax.Attribute
SortedAttributes returns attributes in a deterministic order by source position.
func UnitPathsFromStackDir ¶
UnitPathsFromStackDir parses the stack file in stackDir and returns paths to each unit's generated directory. Returns (nil, err) on parse errors so callers can distinguish "not a stack dir" from "malformed stack file".
func ValueToHCLBytes ¶
ValueToHCLBytes converts a cty.Value to HCL source text bytes.
Types ¶
type AutoIncludeDependency ¶
type AutoIncludeDependency struct {
// Block is the original HCL block, preserved for serialization.
Block *hcl.Block
Name string
ConfigPath string
}
AutoIncludeDependency represents a resolved dependency block from autoinclude. config_path has been evaluated (e.g. unit.vpc.path -> "/abs/path/to/.terragrunt-stack/vpc"). The original HCL block is preserved for writing all attributes (mock_outputs, etc.) into the generated file.
type AutoIncludeHCL ¶
AutoIncludeHCL represents the first-phase parse of an autoinclude block. The entire body is captured as remain because it may contain references to unit.*.path / stack.*.path variables that are only available after the first parsing pass extracts all unit/stack names and paths.
Example HCL:
autoinclude {
dependency "vpc" {
config_path = unit.vpc.path
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
}
}
func (*AutoIncludeHCL) Resolve ¶
func (a *AutoIncludeHCL) Resolve(evalCtx *hcl.EvalContext) (*AutoIncludeResolved, hcl.Diagnostics)
Resolve evaluates the autoinclude body using the provided eval context, which must contain unit.* and stack.* variables for path resolution.
Callers that need to record the originating file's bytes on the returned AutoIncludeResolved (so generation can slice expressions from the correct source after include merging) should set SourceBytes on the result.
The resolution follows three levels:
- First parse: autoinclude body captured as Remain (unit.*.path not yet available)
- This method (second parse): dependency.config_path evaluated using unit/stack context. All other dependency attributes (mock_outputs, etc.) are preserved as raw HCL.
- inputs and other non-dependency content: NOT evaluated here. They contain dependency.*.outputs.* which is runtime-only. The RawBody is preserved so the generator can copy these from the AST.
type AutoIncludeKind ¶ added in v1.0.4
type AutoIncludeKind string
AutoIncludeKind identifies whether a generated autoinclude file is unit-level or stack-level. The values intentionally match internal/component.{UnitKind,StackKind} but are defined here because internal/component -> pkg/config -> internal/hclparse is the established import direction; reusing the component constants would create a cycle.
const ( // KindUnit selects the unit-level filename (terragrunt.autoinclude.hcl). Value matches component.UnitKind. KindUnit AutoIncludeKind = "unit" // KindStack selects the stack-level filename (terragrunt.autoinclude.stack.hcl). Value matches component.StackKind. KindStack AutoIncludeKind = "stack" )
type AutoIncludeResolved ¶
type AutoIncludeResolved struct {
// EvalCtx is the HCL evaluation context used during resolution,
// preserved so the generator can evaluate non-deferred expressions.
EvalCtx *hcl.EvalContext
// RawBody is the original autoinclude HCL body, preserved so
// the generator can write non-dependency content (inputs, etc.)
// directly from the AST without evaluating dependency.* references.
RawBody hcl.Body
// SourceBytes are the bytes of the file RawBody was parsed from. Generation slices expressions by HCL byte ranges and must use these bytes, not the root stack file's bytes, when the autoinclude originated in an included file.
SourceBytes []byte
// Kind is KindUnit or KindStack and drives the generated filename (terragrunt.autoinclude.hcl vs terragrunt.autoinclude.stack.hcl).
Kind AutoIncludeKind
Dependencies []AutoIncludeDependency
}
AutoIncludeResolved represents the second-phase resolved autoinclude content.
After the first parse extracts unit/stack names and paths, the autoinclude body is partially evaluated:
- dependency.config_path is resolved (references unit.*.path)
- dependency remain (mock_outputs etc) is preserved for generation
- inputs and other blocks are partially evaluated (local.* resolved, dependency.* preserved)
The RawBody is preserved for serializing the generated terragrunt.autoinclude.hcl file.
type ComponentRef ¶
type ComponentRef struct {
Name string
Path string
// ChildRefs holds nested unit refs for stack components.
// When a stack block references a source with a terragrunt.stack.hcl,
// the child units within that stack are parsed and stored here.
// This enables stack.stack_name.unit_name.path references.
ChildRefs []ComponentRef
}
ComponentRef holds the path and name metadata for a unit or stack block, used to build the evaluation context for the second parsing phase.
func DiscoverStackChildUnits ¶
func DiscoverStackChildUnits(fs vfs.FS, stackSourceDir, stackGenDir string) []ComponentRef
DiscoverStackChildUnits parses a stack's source dir for stack.<name>.<unit>.path resolution. Best-effort: nested parse failures yield empty refs, never an error.
func ExtractStackRefs ¶
func ExtractStackRefs(stacks []*StackBlockHCL) []ComponentRef
ExtractStackRefs extracts ComponentRef values from parsed StackBlockHCL slices.
func ExtractUnitRefs ¶
func ExtractUnitRefs(units []*UnitBlockHCL) []ComponentRef
ExtractUnitRefs extracts ComponentRef values from parsed UnitBlockHCL slices.
type Copier ¶
type Copier struct {
// contains filtered or unexported fields
}
Copier copies HCL blocks from AST source to hclwrite output. When an eval context is set, attributes are partially evaluated (local.* resolved, dependency.* preserved). Without it, attributes are copied verbatim from source bytes.
func (*Copier) WithEvalCtx ¶
func (c *Copier) WithEvalCtx(evalCtx *hcl.EvalContext) *Copier
WithEvalCtx returns the Copier with partial evaluation enabled.
type DirCreateError ¶
DirCreateError indicates a failure to create a directory.
func (DirCreateError) Error ¶
func (e DirCreateError) Error() string
func (DirCreateError) Unwrap ¶
func (e DirCreateError) Unwrap() error
type DuplicateStackNameError ¶
type DuplicateStackNameError struct {
Name string
}
DuplicateStackNameError indicates that multiple stacks with the same name were found after merging include blocks.
func (DuplicateStackNameError) Error ¶
func (e DuplicateStackNameError) Error() string
type DuplicateUnitNameError ¶
type DuplicateUnitNameError struct {
Name string
}
DuplicateUnitNameError indicates that multiple units with the same name were found after merging include blocks.
func (DuplicateUnitNameError) Error ¶
func (e DuplicateUnitNameError) Error() string
type EmptyArgError ¶ added in v1.0.4
EmptyArgError indicates that a required string argument was empty.
func (EmptyArgError) Error ¶ added in v1.0.4
func (e EmptyArgError) Error() string
type EvalArgs ¶
type EvalArgs struct {
EvalCtx *hcl.EvalContext
Deferred map[string]bool
SrcBytes []byte
}
EvalArgs bundles the shared arguments for partial evaluation functions.
type FileDecodeError ¶
FileDecodeError indicates a failure to decode an HCL file into a struct.
func (FileDecodeError) Error ¶
func (e FileDecodeError) Error() string
type FileParseError ¶
FileParseError indicates a failure to parse an HCL file.
func (FileParseError) Error ¶
func (e FileParseError) Error() string
type FileReadError ¶
FileReadError indicates a failure to read a file from the filesystem.
func (FileReadError) Error ¶
func (e FileReadError) Error() string
func (FileReadError) Unwrap ¶
func (e FileReadError) Unwrap() error
type FileWriteError ¶
FileWriteError indicates a failure to write a file to the filesystem.
func (FileWriteError) Error ¶
func (e FileWriteError) Error() string
func (FileWriteError) Unwrap ¶
func (e FileWriteError) Unwrap() error
type IncludeValidationError ¶
IncludeValidationError indicates that an included stack file violates constraints (e.g. defines locals or nested includes).
func (IncludeValidationError) Error ¶
func (e IncludeValidationError) Error() string
type LocalEvalError ¶
LocalEvalError indicates a failure to evaluate a local variable.
func (LocalEvalError) Error ¶
func (e LocalEvalError) Error() string
type LocalsCycleError ¶
type LocalsCycleError struct {
Names []string
}
LocalsCycleError indicates that locals have circular dependencies.
func (LocalsCycleError) Error ¶
func (e LocalsCycleError) Error() string
type LocalsMaxIterError ¶
LocalsMaxIterError indicates that locals evaluation exceeded the maximum iterations.
func (LocalsMaxIterError) Error ¶
func (e LocalsMaxIterError) Error() string
type MalformedDependencyError ¶ added in v1.0.4
MalformedDependencyError indicates a dependency block in an autoinclude file is malformed. Err optionally carries the original HCL diagnostics so callers can extract position info via errors.As/Is.
func (MalformedDependencyError) Error ¶ added in v1.0.4
func (e MalformedDependencyError) Error() string
func (MalformedDependencyError) Unwrap ¶ added in v1.0.4
func (e MalformedDependencyError) Unwrap() error
type ParseResult ¶
type ParseResult struct {
// AutoIncludes maps component name -> resolved autoinclude (only for units/stacks
// that had an autoinclude block). Dependencies have config_path resolved.
AutoIncludes map[string]*AutoIncludeResolved
// Units from the first-pass parse (name, source, path, values decoded).
Units []*UnitBlockHCL
// Stacks from the first-pass parse.
Stacks []*StackBlockHCL
}
ParseResult holds the output of a two-pass parse of a terragrunt.stack.hcl file.
func ParseStackFile ¶
func ParseStackFile(fs vfs.FS, input *ParseStackFileInput) (*ParseResult, error)
ParseStackFile performs a two-pass parse of a terragrunt.stack.hcl file.
Pass 1: Parse unit/stack blocks to extract names, sources, and paths. The autoinclude body is captured as hcl.Body via remain (not evaluated).
Between passes: Build eval context with unit.<name>.path and stack.<name>.path variables. Paths are resolved to absolute paths under .terragrunt-stack/.
Pass 2: For each unit/stack with an autoinclude block, resolve the autoinclude body using the eval context. dependency.config_path is evaluated (references unit.*.path), while inputs are left unevaluated (contain dependency.*.outputs.*).
func ParseStackFileFromPath ¶
func ParseStackFileFromPath(fs vfs.FS, stackDir string) (*ParseResult, error)
ParseStackFileFromPath reads stackDir/terragrunt.stack.hcl from disk and performs a two-pass parse. Returns (nil, nil) only when the stack file does not exist. Callers that may pass non-directory paths must filter those before calling.
type ParseStackFileInput ¶
ParseStackFileInput holds the input for ParseStackFile.
type StackBlockHCL ¶
type StackBlockHCL struct {
AutoInclude *AutoIncludeHCL `hcl:"autoinclude,block"`
NoStack *bool `hcl:"no_dot_terragrunt_stack,attr"`
NoValidation *bool `hcl:"no_validation,attr"`
Values *cty.Value `hcl:"values,attr"`
Name string `hcl:",label"`
Source string `hcl:"source,attr"`
Path string `hcl:"path,attr"`
}
StackBlockHCL represents the first-phase parse of a stack block. Same remain pattern as UnitBlockHCL.
type StackFileHCL ¶
type StackFileHCL struct {
Locals *LocalsHCL `hcl:"locals,block"`
Includes []*StackIncludeHCL `hcl:"include,block"`
Stacks []*StackBlockHCL `hcl:"stack,block"`
Units []*UnitBlockHCL `hcl:"unit,block"`
}
StackFileHCL represents the first-phase parse of a terragrunt.stack.hcl file. The autoinclude body inside each unit/stack block is captured as hcl.Body via remain, allowing deferred evaluation once unit/stack path variables are available.
type StackIncludeHCL ¶
StackIncludeHCL represents an include block in a terragrunt.stack.hcl file. The path is evaluated immediately during the first parse pass.
type UnexpectedBodyTypeError ¶
type UnexpectedBodyTypeError struct {
FilePath string
}
UnexpectedBodyTypeError indicates that an HCL file body was not the expected *hclsyntax.Body type. This typically occurs with JSON-format HCL files.
func (UnexpectedBodyTypeError) Error ¶
func (e UnexpectedBodyTypeError) Error() string
type UnitBlockHCL ¶
type UnitBlockHCL struct {
AutoInclude *AutoIncludeHCL `hcl:"autoinclude,block"`
NoStack *bool `hcl:"no_dot_terragrunt_stack,attr"`
NoValidation *bool `hcl:"no_validation,attr"`
Values *cty.Value `hcl:"values,attr"`
Name string `hcl:",label"`
Source string `hcl:"source,attr"`
Path string `hcl:"path,attr"`
}
UnitBlockHCL represents the first-phase parse of a unit block. Known attributes are decoded directly. The autoinclude block body is captured in Remain for second-phase evaluation.