Documentation
¶
Overview ¶
Package engine provides a common execution engine for graph-based operations. Both writ and lore build execution graphs and hand them to this engine for processing. The engine dispatches operations to registered handlers, threads content through transform pipelines, and produces receipts.
Index ¶
- func ExpandDelegates(ctx context.Context, graph *Graph, builder GraphBuilder, opts BuildOptions) error
- type BackupOp
- type BuildOptions
- type Conflict
- type ConflictResolution
- type ConflictType
- type Context
- type CopyOp
- type DecryptOp
- type DelegateOp
- type Edge
- type Engine
- type ExpandOp
- type Graph
- type GraphBuilder
- type LinkOp
- type Node
- type Operation
- type Options
- type PipelineState
- type PreflightResult
- type Registry
- type RemoveOp
- type Result
- type Status
- type UnlinkOp
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExpandDelegates ¶
func ExpandDelegates(ctx context.Context, graph *Graph, builder GraphBuilder, opts BuildOptions) error
ExpandDelegates replaces delegate nodes in the graph with subgraphs produced by the given builder. Delegate nodes are identified by having "delegate" as their sole operation.
The expanded subgraph's nodes and edges are appended to the parent graph. An ordering edge is added from the delegate node's predecessor (if any) to each root node of the subgraph.
The original delegate node is removed from the graph after expansion.
Types ¶
type BackupOp ¶
type BackupOp struct{}
BackupOp moves the existing file at node.Target to a timestamped backup.
type BuildOptions ¶
type BuildOptions struct {
// DryRun prevents the builder from making any filesystem queries
// that have side effects.
DryRun bool
// Features lists enabled features (e.g., "rootless", "compose").
Features []string
// Data holds tool context: platform info, environment, segments.
Data map[string]any
}
BuildOptions configures graph building behavior.
type Conflict ¶
type Conflict struct {
Node *Node
Type ConflictType
ExistingPath string // For symlinks, where it points
Message string
}
Conflict represents a pre-flight detected conflict.
type ConflictResolution ¶
type ConflictResolution int
ConflictResolution specifies how to handle conflicts.
const ( // ResolutionStop aborts execution on first conflict. ResolutionStop ConflictResolution = iota // ResolutionBackup moves conflicting files to timestamped backups. ResolutionBackup // ResolutionOverwrite removes conflicting files without backup. ResolutionOverwrite // ResolutionSkip skips conflicting files and continues. ResolutionSkip )
type ConflictType ¶
type ConflictType int
ConflictType describes the kind of conflict at a target path.
const ( // ConflictNone indicates no conflict exists. ConflictNone ConflictType = iota // ConflictRegularFile indicates a regular file exists at target. ConflictRegularFile // ConflictDirectory indicates a directory exists at target. ConflictDirectory // ConflictForeignSymlink indicates a symlink pointing elsewhere exists. ConflictForeignSymlink // ConflictOurSymlink indicates our symlink already exists (no action needed). ConflictOurSymlink )
type Context ¶
type Context struct {
context.Context
// DryRun prevents filesystem modifications when true.
DryRun bool
// Logger receives operation output messages.
Logger io.Writer
// Data holds tool-provided context: template variables, SOPS config,
// identities, segment maps, etc. Each tool populates this before
// calling Engine.Run().
Data map[string]any
}
Context provides execution context to operations.
type CopyOp ¶
type CopyOp struct{}
CopyOp writes state.Content to node.Target and sets state.TargetChecksum.
type DecryptOp ¶
type DecryptOp struct{}
DecryptOp decrypts state.Content using the SOPS API. The decryption configuration is expected in ctx.Data. The decrypted result replaces state.Content.
type DelegateOp ¶
type DelegateOp struct{}
DelegateOp is a no-op that marks a node for cross-tool handoff.
func (*DelegateOp) Execute ¶
func (o *DelegateOp) Execute(_ *Context, node *Node, state *PipelineState) error
func (*DelegateOp) Name ¶
func (o *DelegateOp) Name() string
type Edge ¶
type Edge struct {
From string // Source node ID
To string // Target node ID
Relation string // "depends_on", "delegates", "orders"
}
Edge defines an ordering constraint between nodes.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine executes operation graphs.
func (*Engine) Preflight ¶
func (e *Engine) Preflight(graph *Graph) *PreflightResult
Preflight performs pre-flight conflict detection without modifying anything. Only applies to nodes with file operations (link, copy).
func (*Engine) Run ¶
Run executes all nodes in the graph, respecting ordering constraints. Nodes are processed in topological order when edges define dependencies. Returns results for each node.
TODO: Add graph optimization pass before execution. Native PM operations (e.g., multiple "install" nodes with the same package manager) should be batched into a single operation to reduce PM invocations. See docs/plans/uniform-pipeline-interface.md for design details.
type ExpandOp ¶
type ExpandOp struct{}
ExpandOp processes state.Content as a Go text/template with ctx.Data as the template data. The expanded result replaces state.Content.
type Graph ¶
Graph represents an execution graph: nodes with operations and edges defining ordering constraints.
type GraphBuilder ¶
type GraphBuilder interface {
BuildGraph(ctx context.Context, manifestPath string, opts BuildOptions) (*Graph, error)
}
GraphBuilder builds an execution graph from a manifest file. Tools implement this interface to translate their manifest format into an execution graph that the engine can process.
When writ encounters a delegate node, it calls BuildGraph with the manifest path to get a subgraph. That subgraph is then executed by the same engine — no separate tool invocation needed.
type LinkOp ¶
type LinkOp struct{}
LinkOp creates a symlink from node.Target pointing to node.Source.
type Node ¶
type Node struct {
// ID uniquely identifies this node (e.g., relative target path for writ,
// package name for lore).
ID string
// Operations is the pipeline of operations to execute on this node.
// Examples: ["link"], ["decrypt", "expand", "copy"], ["install"].
Operations []string
// Source is the source path (for file operations).
Source string
// Target is the target path (for file operations).
Target string
// Project is the grouping key (writ: project name, lore: package name).
Project string
// Mode is the target file permissions (0 means use default 0644).
Mode os.FileMode
// DelegateTo names the tool to delegate to (for delegate operations).
DelegateTo string
// Metadata holds tool-specific extensions.
Metadata map[string]string
}
Node represents a unit of work in the execution graph.
type Operation ¶
type Operation interface {
// Execute performs the operation on the given node with pipeline state.
// Transforms modify state.Content in place. Writers consume state.Content
// and produce filesystem output. Direct operations ignore state.Content.
Execute(ctx *Context, node *Node, state *PipelineState) error
// Name returns the operation identifier (e.g., "link", "decrypt").
Name() string
}
Operation defines an executable action. Implementations fall into three categories: transforms (modify state.Content), writers (produce filesystem side effects from state.Content), and direct operations (manage their own I/O).
type Options ¶
type Options struct {
// DryRun prevents filesystem modifications.
DryRun bool
// Logger receives operation output.
Logger io.Writer
// Data holds tool-provided context (template vars, SOPS config, etc.).
Data map[string]any
// ConflictResolution specifies how to handle conflicts detected during preflight.
ConflictResolution ConflictResolution
// BackupSuffix is appended to backup filenames (default: ".writ-backup").
BackupSuffix string
}
Options configures engine behavior.
type PipelineState ¶
type PipelineState struct {
// Content is the current file content. Transforms modify this in place;
// writers consume it to produce output files.
Content []byte
// SourceChecksum is computed from the original source file content
// before any transforms are applied. Format: "sha256:<hex>".
SourceChecksum string
// TargetChecksum is set by writer operations after writing content
// to the target path. Format: "sha256:<hex>".
TargetChecksum string
// Metadata holds per-node extensible state that operations can read/write.
Metadata map[string]string
}
PipelineState holds mutable state threaded through a node's operation pipeline. The engine pre-reads source content into Content when the pipeline begins with a transform or writer operation.
type PreflightResult ¶
type PreflightResult struct {
Conflicts []Conflict
AlreadyDone []Conflict // Symlinks that already point correctly
Ready []*Node // Nodes ready to deploy (no conflict)
}
PreflightResult contains the results of pre-flight conflict detection.
func (*PreflightResult) HasConflicts ¶
func (p *PreflightResult) HasConflicts() bool
HasConflicts returns true if any conflicts were detected.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps operation names to implementations. Each tool registers its operations before calling Engine.Run().
type RemoveOp ¶
type RemoveOp struct{}
RemoveOp deletes the file at node.Target. If ctx.Data["prune_empty_dirs"] is true and ctx.Data["prune_boundary"] is set, empty parent directories are removed up to the boundary.
type Result ¶
type Result struct {
NodeID string
Status Status
Error error
Message string
SourceChecksum string
TargetChecksum string
}
Result represents the outcome of executing a single node.
type Status ¶
type Status int
Status represents the execution status of a node.
const ( // StatusPending means the node has not been processed yet. StatusPending Status = iota // StatusRunning means the node is currently executing. StatusRunning // StatusCompleted means the node executed successfully. StatusCompleted // StatusFailed means the node encountered an error. StatusFailed // StatusSkipped means the node was skipped (conflict, already deployed, etc.). StatusSkipped )
type UnlinkOp ¶
type UnlinkOp struct{}
UnlinkOp removes a symlink at node.Target. If ctx.Data["prune_empty_dirs"] is true and ctx.Data["prune_boundary"] is set, empty parent directories are removed up to the boundary.