filter

package
v0.97.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 9, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package filter provides a parser and evaluator for filter query strings used to select Terragrunt components.

Overview

The filter package implements a three-stage compiler architecture:

  1. Lexer: Tokenizes the input filter query string
  2. Parser: Builds an Abstract Syntax Tree (AST) from tokens
  3. Evaluator: Applies the filter logic to discovered Terragrunt components

This design follows the classic compiler pattern and provides a clean separation of concerns between syntax analysis and semantic evaluation.

Filter Syntax

The filter package supports the following syntax elements:

## Path Filters

Path filters match components by their file system path. They support glob patterns:

./apps/frontend         # Exact path match
./apps/*                # Single-level wildcard
./apps/**/api           # Recursive wildcard
/absolute/path          # Absolute path

## Attribute Filters

Attribute filters match components by their attributes:

name=my-app             # Match by config name (directory basename)
type=unit               # Match components of type "unit"
type=stack              # Match components of type "stack"
external=true           # Match external dependencies
external=false          # Match internal dependencies (not external)
foo                     # Shorthand for name=foo

## Negation Operator (!)

The negation operator excludes matching components:

!name=legacy            # Exclude components named "legacy"
!./apps/old             # Exclude components at path ./apps/old
!foo                    # Exclude components named "foo"
!external=true          # Exclude external dependencies

## Intersection Operator (|)

The intersection operator refines/narrows results by applying filters from left to right. Each filter in the chain further restricts the results from the previous filter. The pipe character (|) is the only delimiter between filter expressions. Whitespace is optional around operators but is NOT a delimiter itself.

./apps/* | name=web         # Components in ./apps/* AND named "web"
./apps/*|name=web           # Same as above (spaces optional)
./foo* | !./foobar*         # Components in ./foo* AND NOT in ./foobar*
type=unit | !external=true  # Internal components only

Spaces within component names and paths are preserved:

my app                  # Component named "my app" (with space)
./my path/file          # Path with spaces

## Braced Path Syntax ({})

Use braces to explicitly mark a path expression. This is useful when: - The path doesn't start with ./ or / - You want to be explicit that something is a path, not an identifier

{./apps/*}              # Explicitly a path
{my path/file}          # Path without ./ prefix
{apps}                  # Treat "apps" as a path, not a name filter

Operator Precedence

Operators are evaluated with the following precedence (highest to lowest):

  1. Prefix operators (!)
  2. Infix operators (| - intersection/refinement, left-to-right)

This means !foo | bar is evaluated as (!foo) | bar, not !(foo | bar). The intersection operator applies filters left-to-right, each filter refining/narrowing the results from the previous filter.

Usage Examples

## Basic Usage

// Parse a filter query
filter, err := filter.Parse("./apps/* | !legacy", ".")
if err != nil {
    log.Fatal(err)
}

// Apply the filter to discovered components
// (typically obtained from discovery.Discover())
components := []*component.Component{
    {Path: "./apps/app1", Kind: component.Unit},
    {Path: "./apps/legacy", Kind: component.Unit},
    {Path: "./libs/db", Kind: component.Unit},
}
result, err := filter.Evaluate(components)
if err != nil {
    log.Fatal(err)
}

## Multiple Filters (Union)

Multiple filter queries can be combined using the Filters type, which applies union (OR) semantics. This is different from using | within a single filter, which applies intersection (AND) semantics.

// Parse multiple filter queries
filters, err := filter.ParseFilterQueries([]string{
    "./apps/*",      // Select all apps
    "name=db",       // OR select db
}, ".")
if err != nil {
    log.Fatal(err)
}

result, err := filters.Evaluate(components)
// Returns: all components in ./apps/* OR components named "db"

Multiple filters are evaluated in two phases:

  1. Positive filters (non-negated) are evaluated and their results are unioned
  2. Negative filters (starting with !) are applied to remove matching components

The ExcludeByDefault() method signals whether filters operate in exclude-by-default mode. This is true if ANY filter doesn't start with a negation expression:

filters.ExcludeByDefault() // true if any filter is positive

When true, discovery should start with an empty set and add matches. When false (all filters are negated), discovery should start with all components and remove matches.

## One-Shot Usage

// Parse and evaluate in one step
result, err := filter.Apply("./apps/* | name=web", ".", components)

Implementation Details

## Lexer

The lexer (lexer.go) scans the input string and produces tokens:

  • IDENT: Identifiers (foo, name, etc.)
  • PATH: Paths (./apps/*, /absolute, etc.)
  • BANG: Negation operator (!)
  • PIPE: Intersection operator (|)
  • EQUAL: Assignment operator (=)
  • LBRACE: Left brace ({)
  • RBRACE: Right brace (})
  • EOF: End of input

## Parser

The parser (parser.go) uses recursive descent parsing with Pratt parsing for operators. It produces an AST with the following node types:

  • PathFilter: Path/glob filter
  • AttributeFilter: Key-value attribute filter
  • PrefixExpression: Negation operator
  • InfixExpression: Union operator

## Evaluator

The evaluator (evaluator.go) walks the AST and applies the filter logic:

  • PathFilter: Uses glob matching (github.com/gobwas/glob) with eager compilation and caching via sync.Once for performance
  • AttributeFilter: Matches attributes by key-value pairs:
  • name: Matches filepath.Base(component.Path)
  • type: Matches component.Kind (unit or stack)
  • external: Matches component.External (true or false)
  • PrefixExpression: Returns the complement of the right side
  • InfixExpression: Returns the intersection by applying right filter to left results

Path filters compile their glob pattern once on first evaluation and cache the compiled result for reuse in subsequent evaluations, providing significant performance improvements when filters are evaluated multiple times.

This package implements the filter syntax described in RFC #4060: https://github.com/gruntwork-io/terragrunt/issues/4060

The syntax is inspired by Turborepo's filter syntax: https://turbo.build/repo/docs/reference/run#--filter-string

Future Enhancements

Future versions will support:

  • Git-based filtering ([main...HEAD])
  • Dependency traversal (name=foo...)
  • Dependents traversal (...name=foo)
  • Read-based filtering (reads=path/to/file)

Package filter provides telemetry support for git worktree operations and filter evaluation.

Example (AttributeFilter)

Example_attributeFilter demonstrates filtering components by name attribute.

package main

import (
	"fmt"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./apps/frontend").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/backend").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./services/api").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	l := log.New()
	result, _ := filter.Apply(l, "name=api", components)

	for _, c := range result {
		fmt.Println(c.Path())
	}
}
Output:

./services/api
Example (BasicPathFilter)

Example_basicPathFilter demonstrates filtering components by path with a glob pattern.

package main

import (
	"fmt"
	"path/filepath"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./apps/app1").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/app2").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/db").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	l := log.New()
	result, _ := filter.Apply(l, "./apps/*", components)

	for _, c := range result {
		fmt.Println(filepath.Base(c.Path()))
	}
}
Output:

app1
app2
Example (ComplexQuery)

Example_complexQuery demonstrates a complex filter combining paths and negation.

package main

import (
	"fmt"
	"path/filepath"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./services/web").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./services/worker").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/db").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/api").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/cache").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	// Select all services except worker
	l := log.New()
	result, _ := filter.Apply(l, "./services/* | !worker", components)

	for _, c := range result {
		fmt.Println(filepath.Base(c.Path()))
	}
}
Output:

web
Example (ErrorHandling)

Example_errorHandling demonstrates handling parsing errors.

package main

import (
	"fmt"

	"github.com/gruntwork-io/terragrunt/internal/filter"
)

func main() {
	// Invalid syntax - missing value after =
	_, err := filter.Parse("name=")
	if err != nil {
		fmt.Println("Error occurred")
	}

	// Valid syntax
	_, err = filter.Parse("name=foo")
	if err == nil {
		fmt.Println("Successfully parsed")
	}

}
Output:

Error occurred
Successfully parsed
Example (ExclusionFilter)

Example_exclusionFilter demonstrates excluding components using the negation operator.

package main

import (
	"fmt"
	"path/filepath"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./apps/app1").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/app2").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/legacy").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	l := log.New()
	result, _ := filter.Apply(l, "!legacy", components)

	for _, c := range result {
		fmt.Println(filepath.Base(c.Path()))
	}
}
Output:

app1
app2
Example (IntersectionFilter)

Example_intersectionFilter demonstrates refining results with the intersection operator.

package main

import (
	"fmt"
	"path/filepath"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./apps/frontend").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/backend").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/db").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/api").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	// Select components in ./apps/ that are named "frontend"
	l := log.New()
	result, _ := filter.Apply(l, "./apps/* | frontend", components)

	for _, c := range result {
		fmt.Println(filepath.Base(c.Path()))
	}
}
Output:

frontend
Example (MultipleFilters)

Example_multipleFilters demonstrates using multiple filters with union semantics.

package main

import (
	"fmt"
	"path/filepath"
	"sort"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./apps/app1").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/app2").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/db").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./libs/api").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	// Parse multiple filters - results are unioned
	filters, _ := filter.ParseFilterQueries([]string{
		"./apps/*",
		"name=db",
	})

	l := log.New()
	result, _ := filters.Evaluate(l, components)

	// Sort for consistent output
	names := make([]string, len(result))
	for i, c := range result {
		names[i] = filepath.Base(c.Path())
	}

	sort.Strings(names)

	for _, name := range names {
		fmt.Println(name)
	}
}
Output:

app1
app2
db
Example (ParseAndEvaluate)

Example_parseAndEvaluate demonstrates the two-step process of parsing and evaluating.

package main

import (
	"fmt"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./apps/app1").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./apps/app2").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	// Parse the filter once
	f, err := filter.Parse("app1")
	if err != nil {
		fmt.Println("Parse error:", err)
		return
	}

	// Evaluate multiple times with different config sets
	l := log.New()
	result1, _ := f.Evaluate(l, components)
	fmt.Printf("Found %d components\n", len(result1))

	// You can also inspect the original query
	fmt.Printf("Original query: %s\n", f.String())

}
Output:

Found 1 components
Original query: app1
Example (RecursiveWildcard)

Example_recursiveWildcard demonstrates using recursive wildcards to match nested paths.

package main

import (
	"fmt"
	"path/filepath"

	"github.com/gruntwork-io/terragrunt/internal/component"
	"github.com/gruntwork-io/terragrunt/internal/filter"
	"github.com/gruntwork-io/terragrunt/pkg/log"
)

func main() {
	components := []component.Component{
		component.NewUnit("./infrastructure/networking/vpc").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./infrastructure/networking/subnets").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
		component.NewUnit("./infrastructure/compute/app-server").WithDiscoveryContext(&component.DiscoveryContext{
			WorkingDir: ".",
		}),
	}

	// Match all infrastructure components at any depth
	l := log.New()
	result, _ := filter.Apply(l, "./infrastructure/**", components)

	for _, c := range result {
		fmt.Println(filepath.Base(c.Path()))
	}
}
Output:

vpc
subnets
app-server

Index

Examples

Constants

View Source
const (
	AttributeName     = "name"
	AttributeType     = "type"
	AttributeExternal = "external"
	AttributeReading  = "reading"
	AttributeSource   = "source"

	AttributeTypeValueUnit  = string(component.UnitKind)
	AttributeTypeValueStack = string(component.StackKind)

	AttributeExternalValueTrue  = "true"
	AttributeExternalValueFalse = "false"

	// MaxTraversalDepth is the maximum depth to traverse the graph for both dependencies and dependents.
	MaxTraversalDepth = 1000000
)
View Source
const (
	LOWEST       int
	INTERSECTION // |
	PREFIX       // !
)

Operator precedence levels

View Source
const (
	// Git worktree operations
	TelemetryOpGitWorktreeCreate      = "git_worktree_create"
	TelemetryOpGitWorktreeRemove      = "git_worktree_remove"
	TelemetryOpGitWorktreesCreate     = "git_worktrees_create"
	TelemetryOpGitWorktreesCleanup    = "git_worktrees_cleanup"
	TelemetryOpGitDiff                = "git_diff"
	TelemetryOpGitWorktreeDiscovery   = "git_worktree_discovery"
	TelemetryOpGitWorktreeStackWalk   = "git_worktree_stack_walk"
	TelemetryOpGitWorktreeFilterApply = "git_worktree_filter_apply"

	// Filter evaluation operations
	TelemetryOpFilterEvaluate      = "filter_evaluate"
	TelemetryOpFilterParse         = "filter_parse"
	TelemetryOpGitFilterExpand     = "git_filter_expand"
	TelemetryOpGitFilterEvaluate   = "git_filter_evaluate"
	TelemetryOpGraphFilterTraverse = "graph_filter_traverse"
)

Telemetry operation names for git worktree and filter operations.

View Source
const (
	AttrGitRef         = "git.ref"
	AttrGitFromRef     = "git.from_ref"
	AttrGitToRef       = "git.to_ref"
	AttrGitWorktreeDir = "git.worktree_dir"
	AttrGitWorkingDir  = "git.working_dir"
	AttrGitRefCount    = "git.ref_count"
	AttrGitDiffAdded   = "git.diff.added_count"
	AttrGitDiffRemoved = "git.diff.removed_count"
	AttrGitDiffChanged = "git.diff.changed_count"

	// Repository identification attributes
	AttrGitRepoRemote = "git.repo.remote"
	AttrGitRepoBranch = "git.repo.branch"
	AttrGitRepoCommit = "git.repo.commit"

	AttrFilterQuery       = "filter.query"
	AttrFilterType        = "filter.type"
	AttrFilterCount       = "filter.count"
	AttrComponentCount    = "component.count"
	AttrResultCount       = "result.count"
	AttrWorktreePairCount = "worktree.pair_count"
)

Telemetry attribute keys for git worktree operations.

Variables

This section is empty.

Functions

func Apply

func Apply(l log.Logger, filterString string, components component.Components) (component.Components, error)

Apply is a convenience function that parses and evaluates a filter in one step. It's equivalent to calling Parse followed by Evaluate.

func Evaluate

func Evaluate(l log.Logger, expr Expression, components component.Components) (component.Components, error)

Evaluate evaluates an expression against a list of components and returns the filtered components. If logger is provided, it will be used for logging warnings during evaluation.

func NewEvaluationError

func NewEvaluationError(message string) error

NewEvaluationError creates a new EvaluationError with the given message.

func NewEvaluationErrorWithCause

func NewEvaluationErrorWithCause(message string, cause error) error

NewEvaluationErrorWithCause creates a new EvaluationError with the given message and cause.

func NewParseError

func NewParseError(message string, position int) error

NewParseError creates a new ParseError with the given message and position.

func TraceFilterEvaluate added in v0.96.1

func TraceFilterEvaluate(ctx context.Context, filterCount, componentCount int, fn func(ctx context.Context) error) error

TraceFilterEvaluate wraps filter evaluation with telemetry.

func TraceFilterParse added in v0.96.1

func TraceFilterParse(ctx context.Context, query string, fn func(ctx context.Context) error) error

TraceFilterParse wraps filter parsing with telemetry.

func TraceGitDiff added in v0.96.1

func TraceGitDiff(ctx context.Context, fromRef, toRef, repoRemote string, fn func(ctx context.Context) error) error

TraceGitDiff wraps a git diff operation with telemetry.

func TraceGitFilterEvaluate added in v0.96.1

func TraceGitFilterEvaluate(ctx context.Context, fromRef, toRef string, componentCount int, fn func(ctx context.Context) error) error

TraceGitFilterEvaluate wraps git filter evaluation with telemetry.

func TraceGitFilterExpand added in v0.96.1

func TraceGitFilterExpand(ctx context.Context, fromRef, toRef string, addedCount, removedCount, changedCount int, fn func(ctx context.Context) error) error

TraceGitFilterExpand wraps git filter expansion with telemetry.

func TraceGitWorktreeCreate added in v0.96.1

func TraceGitWorktreeCreate(ctx context.Context, ref, worktreeDir, repoRemote, repoBranch, repoCommit string, fn func(ctx context.Context) error) error

TraceGitWorktreeCreate wraps a git worktree create operation with telemetry. The underlying Telemeter.Collect handles nil/unconfigured telemetry gracefully.

func TraceGitWorktreeDiscovery added in v0.96.1

func TraceGitWorktreeDiscovery(ctx context.Context, pairCount int, fn func(ctx context.Context) error) error

TraceGitWorktreeDiscovery wraps git worktree discovery operations with telemetry.

func TraceGitWorktreeFilterApply added in v0.96.1

func TraceGitWorktreeFilterApply(ctx context.Context, filterCount, resultCount int, fn func(ctx context.Context) error) error

TraceGitWorktreeFilterApply wraps filter application to git worktrees with telemetry.

func TraceGitWorktreeRemove added in v0.96.1

func TraceGitWorktreeRemove(ctx context.Context, ref, worktreeDir string, fn func(ctx context.Context) error) error

TraceGitWorktreeRemove wraps a git worktree remove operation with telemetry.

func TraceGitWorktreeStackWalk added in v0.96.1

func TraceGitWorktreeStackWalk(ctx context.Context, fromRef, toRef string, fn func(ctx context.Context) error) error

TraceGitWorktreeStackWalk wraps git worktree stack walking operations with telemetry.

func TraceGitWorktreesCleanup added in v0.96.1

func TraceGitWorktreesCleanup(ctx context.Context, pairCount int, repoRemote string, fn func(ctx context.Context) error) error

TraceGitWorktreesCleanup wraps git worktrees cleanup with telemetry.

func TraceGitWorktreesCreate added in v0.96.1

func TraceGitWorktreesCreate(ctx context.Context, workingDir string, refCount int, repoRemote, repoBranch, repoCommit string, fn func(ctx context.Context) error) error

TraceGitWorktreesCreate wraps multiple git worktree create operations with telemetry.

func TraceGraphFilterTraverse added in v0.96.1

func TraceGraphFilterTraverse(ctx context.Context, filterType string, componentCount int, fn func(ctx context.Context) error) error

TraceGraphFilterTraverse wraps graph filter traversal with telemetry.

Types

type AttributeExpression added in v0.95.0

type AttributeExpression struct {
	Key   string
	Value string
	// contains filtered or unexported fields
}

AttributeExpression represents a key-value attribute filter (e.g., "name=my-app").

func NewAttributeExpression added in v0.95.0

func NewAttributeExpression(key string, value string) *AttributeExpression

NewAttributeExpression creates a new AttributeFilter with lazy glob compilation.

func (*AttributeExpression) CompileGlob added in v0.95.0

func (a *AttributeExpression) CompileGlob() (glob.Glob, error)

CompileGlob returns the compiled glob pattern for name and reading filters, compiling it on first call. Returns an error if called on unsupported attributes (e.g. type, external). Uses sync.Once for thread-safe lazy initialization.

func (*AttributeExpression) IsRestrictedToStacks added in v0.95.0

func (a *AttributeExpression) IsRestrictedToStacks() bool

func (*AttributeExpression) RequiresDiscovery added in v0.95.0

func (a *AttributeExpression) RequiresDiscovery() (Expression, bool)

func (*AttributeExpression) RequiresParse added in v0.95.0

func (a *AttributeExpression) RequiresParse() (Expression, bool)

func (*AttributeExpression) String added in v0.95.0

func (a *AttributeExpression) String() string

type EvaluationContext added in v0.95.0

type EvaluationContext struct {
	// GitWorktrees maps Git references to temporary worktree directory paths.
	// This is used by GitFilter expressions to access different Git references.
	GitWorktrees map[string]string
	// WorkingDir is the base working directory for resolving relative paths.
	WorkingDir string
}

EvaluationContext provides additional context for filter evaluation, such as Git worktree directories.

type EvaluationError

type EvaluationError struct {
	Cause   error
	Message string
}

EvaluationError represents an error that occurred during evaluation.

func (EvaluationError) Error

func (e EvaluationError) Error() string

type Expression

type Expression interface {

	// String returns a string representation of the expression for debugging.
	String() string
	// RequiresDiscovery returns the first expression that requires discovery of Terragrunt components if any do.
	// Additionally, it returns a secondary value of true if any do.
	RequiresDiscovery() (Expression, bool)
	// RequiresParse returns the first expression that requires parsing Terragrunt HCL configurations if any do.
	// Additionally, it returns a secondary value of true if any do.
	RequiresParse() (Expression, bool)
	// IsRestrictedToStacks returns true if the expression is restricted to stacks.
	IsRestrictedToStacks() bool
	// contains filtered or unexported methods
}

Expression is the interface that all AST nodes must implement.

type Expressions added in v0.95.0

type Expressions []Expression

Expressions is a slice of expressions.

type Filter

type Filter struct {
	// contains filtered or unexported fields
}

Filter represents a parsed filter query that can be evaluated against discovered configs.

func NewFilter added in v0.95.0

func NewFilter(expr Expression, originalQuery string) *Filter

NewFilter creates a new Filter object.

func Parse

func Parse(filterString string) (*Filter, error)

Parse parses a filter query string and returns a Filter object. Returns an error if the query cannot be parsed.

func (*Filter) Evaluate

func (f *Filter) Evaluate(l log.Logger, components component.Components) (component.Components, error)

Evaluate applies the filter to a list of components and returns the filtered result. If logger is provided, it will be used for logging warnings during evaluation.

func (*Filter) Expression

func (f *Filter) Expression() Expression

Expression returns the parsed AST expression. This is useful for debugging or advanced use cases.

func (*Filter) RequiresParse added in v0.95.0

func (f *Filter) RequiresParse() (Expression, bool)

RequiresParse returns true if the filter requires parsing of Terragrunt HCL configurations.

func (*Filter) String

func (f *Filter) String() string

String returns a string representation of the filter.

type FilterQueryRequiresDiscoveryError added in v0.93.4

type FilterQueryRequiresDiscoveryError struct {
	Query string
}

FilterQueryRequiresDiscoveryError is an error that is returned when a filter query requires discovery of Terragrunt configurations.

func (FilterQueryRequiresDiscoveryError) Error added in v0.93.4

type Filters

type Filters []*Filter

Filters represents multiple filter queries that are evaluated with union (OR) semantics. Multiple filters in Filters are always unioned (as opposed to multiple filters within one filter string separated by |, which are intersected).

func ParseFilterQueries

func ParseFilterQueries(filterStrings []string) (Filters, error)

ParseFilterQueries parses multiple filter strings and returns a Filters object. Collects all parse errors and returns them as a joined error if any occur. Returns an empty Filters if filterStrings is empty.

func (Filters) DependencyGraphExpressions added in v0.95.0

func (f Filters) DependencyGraphExpressions() []Expression

DependencyGraphExpressions returns all target expressions from graph expressions that require dependency traversal.

func (Filters) DependentGraphExpressions added in v0.95.0

func (f Filters) DependentGraphExpressions() []Expression

DependentGraphExpressions returns all target expressions from graph expressions that require dependent traversal.

func (Filters) Evaluate

func (f Filters) Evaluate(l log.Logger, components component.Components) (component.Components, error)

Evaluate applies all filters with union (OR) semantics in two phases:

  1. Positive filters (non-negated) are evaluated and their results are unioned
  2. Negative filters (starting with negation) are evaluated against the combined results and remove matching components

If logger is provided, it will be used for logging warnings during evaluation.

func (Filters) EvaluateOnFiles added in v0.92.0

func (f Filters) EvaluateOnFiles(l log.Logger, files []string, workingDir string) (component.Components, error)

EvaluateOnFiles evaluates the filters on a list of files and returns the filtered result. This is useful for the hcl format command, where we want to evaluate filters on files rather than directories, like we do with components.

func (Filters) HasPositiveFilter added in v0.91.2

func (f Filters) HasPositiveFilter() bool

HasPositiveFilter returns true if the filters have any positive filters.

func (Filters) RequiresDiscovery added in v0.93.4

func (f Filters) RequiresDiscovery() (Expression, bool)

RequiresDiscovery returns the first expression that requires discovery of Terragrunt components if any do.

func (Filters) RequiresParse added in v0.93.4

func (f Filters) RequiresParse() (Expression, bool)

RequiresParse returns the first expression that requires parsing of Terragrunt HCL configurations if any do.

func (Filters) RestrictToStacks added in v0.93.5

func (f Filters) RestrictToStacks() Filters

RestrictToStacks returns a new Filters object with only the filters that are restricted to stacks.

func (Filters) String

func (f Filters) String() string

String returns a JSON array representation of all filter strings.

func (Filters) UniqueGitFilters added in v0.95.0

func (f Filters) UniqueGitFilters() GitExpressions

UniqueGitFilters returns all unique Git filters that require worktree discovery.

type GitExpression added in v0.95.0

type GitExpression struct {
	FromRef string
	ToRef   string
}

GitExpression represents a Git-based filter expression (e.g., "[main...HEAD]" or "[main]"). It filters components based on changes between Git references.

func NewGitExpression added in v0.95.0

func NewGitExpression(fromRef, toRef string) *GitExpression

func (*GitExpression) IsRestrictedToStacks added in v0.95.0

func (g *GitExpression) IsRestrictedToStacks() bool

func (*GitExpression) RequiresDiscovery added in v0.95.0

func (g *GitExpression) RequiresDiscovery() (Expression, bool)

func (*GitExpression) RequiresParse added in v0.95.0

func (g *GitExpression) RequiresParse() (Expression, bool)

func (*GitExpression) String added in v0.95.0

func (g *GitExpression) String() string

type GitExpressions added in v0.95.0

type GitExpressions []*GitExpression

GitExpressions is a slice of Git expressions.

func (GitExpressions) UniqueGitRefs added in v0.95.0

func (e GitExpressions) UniqueGitRefs() []string

UniqueGitRefs returns all unique Git references in a slice of expressions.

type GraphExpression added in v0.93.4

type GraphExpression struct {
	Target              Expression
	IncludeDependents   bool
	IncludeDependencies bool
	ExcludeTarget       bool
}

GraphExpression represents a graph traversal expression (e.g., "...foo", "foo...", "...foo...", "^foo").

func NewGraphExpression added in v0.93.5

func NewGraphExpression(
	target Expression,
	includeDependents bool,
	includeDependencies bool,
	excludeTarget bool,
) *GraphExpression

NewGraphExpression creates a new GraphExpression.

func (*GraphExpression) IsRestrictedToStacks added in v0.93.5

func (g *GraphExpression) IsRestrictedToStacks() bool

func (*GraphExpression) RequiresDiscovery added in v0.93.4

func (g *GraphExpression) RequiresDiscovery() (Expression, bool)

func (*GraphExpression) RequiresParse added in v0.93.4

func (g *GraphExpression) RequiresParse() (Expression, bool)

func (*GraphExpression) String added in v0.93.4

func (g *GraphExpression) String() string

type InfixExpression

type InfixExpression struct {
	Left     Expression
	Right    Expression
	Operator string
}

InfixExpression represents an infix operator expression (e.g., "./apps/* | name=bar").

func NewInfixExpression added in v0.93.5

func NewInfixExpression(left Expression, operator string, right Expression) *InfixExpression

NewInfixExpression creates a new InfixExpression.

func (*InfixExpression) IsRestrictedToStacks added in v0.93.5

func (i *InfixExpression) IsRestrictedToStacks() bool

func (*InfixExpression) RequiresDiscovery added in v0.93.4

func (i *InfixExpression) RequiresDiscovery() (Expression, bool)

func (*InfixExpression) RequiresParse added in v0.93.4

func (i *InfixExpression) RequiresParse() (Expression, bool)

func (*InfixExpression) String

func (i *InfixExpression) String() string

type Lexer

type Lexer struct {
	// contains filtered or unexported fields
}

Lexer tokenizes a filter query string.

func NewLexer

func NewLexer(input string) *Lexer

NewLexer creates a new Lexer for the given input string.

func (*Lexer) NextToken

func (l *Lexer) NextToken() Token

NextToken reads and returns the next token from the input.

type ParseError

type ParseError struct {
	Message  string
	Position int
}

ParseError represents an error that occurred during parsing.

func (ParseError) Error

func (e ParseError) Error() string

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser parses a filter query string into an AST.

func NewParser

func NewParser(lexer *Lexer) *Parser

NewParser creates a new Parser for the given lexer.

func (*Parser) Errors

func (p *Parser) Errors() []error

Errors returns any parsing errors that occurred.

func (*Parser) ParseExpression

func (p *Parser) ParseExpression() (Expression, error)

ParseExpression parses and returns an expression from the input.

type PathExpression added in v0.95.0

type PathExpression struct {
	Value string
	// contains filtered or unexported fields
}

PathExpression represents a path or glob filter (e.g., "./path/**/*" or "/absolute/path").

func NewPathFilter

func NewPathFilter(value string) *PathExpression

NewPathFilter creates a new PathFilter with lazy glob compilation.

func (*PathExpression) CompileGlob added in v0.95.0

func (p *PathExpression) CompileGlob() (glob.Glob, error)

CompileGlob returns the compiled glob pattern, compiling it on first call. Subsequent calls return the cached compiled glob and any error. Uses sync.Once for thread-safe lazy initialization.

func (*PathExpression) IsRestrictedToStacks added in v0.95.0

func (p *PathExpression) IsRestrictedToStacks() bool

func (*PathExpression) RequiresDiscovery added in v0.95.0

func (p *PathExpression) RequiresDiscovery() (Expression, bool)

func (*PathExpression) RequiresParse added in v0.95.0

func (p *PathExpression) RequiresParse() (Expression, bool)

func (*PathExpression) String added in v0.95.0

func (p *PathExpression) String() string

type PrefixExpression

type PrefixExpression struct {
	Right    Expression
	Operator string
}

PrefixExpression represents a prefix operator expression (e.g., "!name=foo").

func NewPrefixExpression added in v0.93.5

func NewPrefixExpression(operator string, right Expression) *PrefixExpression

NewPrefixExpression creates a new PrefixExpression.

func (*PrefixExpression) IsRestrictedToStacks added in v0.93.5

func (p *PrefixExpression) IsRestrictedToStacks() bool

func (*PrefixExpression) RequiresDiscovery added in v0.93.4

func (p *PrefixExpression) RequiresDiscovery() (Expression, bool)

func (*PrefixExpression) RequiresParse added in v0.93.4

func (p *PrefixExpression) RequiresParse() (Expression, bool)

func (*PrefixExpression) String

func (p *PrefixExpression) String() string

type Token

type Token struct {
	Literal  string
	Type     TokenType
	Position int
}

Token represents a lexical token with its type, literal value, and position.

func NewToken

func NewToken(tokenType TokenType, literal string, position int) Token

NewToken creates a new token with the given type, literal, and position.

type TokenType

type TokenType int

TokenType represents the type of a token.

const (
	// ILLEGAL represents an unknown token
	ILLEGAL TokenType = iota

	// EOF represents the end of the input
	EOF

	// IDENT represents an identifier (e.g., "foo", "name")
	IDENT

	// PATH represents a path (starts with ./, ../, or /)
	PATH

	// Operators
	BANG  // negation operator (!)
	PIPE  // intersection operator (|)
	EQUAL // attribute assignment (=)

	// Delimiters
	LBRACE   // left brace ({)
	RBRACE   // right brace (})
	LBRACKET // left bracket ([)
	RBRACKET // right bracket (])

	// Graph operators
	ELLIPSIS // ellipsis operator (...)
	CARET    // caret operator (^)
)

func (TokenType) String

func (t TokenType) String() string

String returns a string representation of the token type for debugging.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL