execution

package
v0.1.0-dev.20260212221939 Latest Latest
Warning

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

Go to latest
Published: Feb 12, 2026 License: MIT Imports: 16 Imported by: 0

Documentation ¶

Overview ¶

Package execution provides the core execution graph primitives and executor shared by writ (configuration deployment) and lore (package management).

Core Types ¶

  • Graph: A directed graph of nodes and edges representing work to be done
  • Node: A single unit of work with operations to execute
  • Edge: A dependency relationship between nodes

Execution Model ¶

  • GraphBuilder: Interface for building graphs (implementations in tools)
  • GraphExecutor: Runs graphs by executing operations on nodes
  • OperationRegistry: Maps operation names to implementations

Operation Categories ¶

  • Transform: Read content, produce transformed content (decrypt, expand)
  • Writer: Read content, write to filesystem (copy)
  • Direct: Manage own I/O, no content flow (link, mkdir, install)

Graph Lifecycle ¶

The Graph represents both plans (before execution) and receipts (after execution):

  • Before Run(): State is "pending", nodes describe what will happen
  • After Run(): State is "executed", nodes describe what happened
  • Serialized before execution: "dry-run" or "purchase order"
  • Serialized after execution: "receipt"

Index ¶

Constants ¶

This section is empty.

Variables ¶

This section is empty.

Functions ¶

func ChecksumBytes ¶

func ChecksumBytes(content []byte) string

ChecksumBytes computes SHA256 of content and returns "sha256:<hex>".

func ChecksumFile ¶

func ChecksumFile(path string) string

ChecksumFile computes SHA256 of a file and returns "sha256:<hex>". Returns empty string if the file cannot be read.

func ExpandDelegates ¶

func ExpandDelegates(ctx context.Context, graph *Graph, builder SubgraphBuilder, 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 to each root node of the subgraph.

The original delegate node is removed from the graph after expansion.

func GitStyleChecksum ¶

func GitStyleChecksum(objectType, basename string, content []byte) string

GitStyleChecksum computes a git-style checksum. Format: SHA256("<type> <basename> <len>\0<content>") Returns format "sha256:<hex>".

Types ¶

type BackupOp ¶

type BackupOp struct{}

BackupOp moves the existing file at node's "path" slot to a timestamped backup. The backup path is stored in node.Annotations["backup_path"] after execution.

func (*BackupOp) Category ¶

func (o *BackupOp) Category() OpCategory

func (*BackupOp) Execute ¶

func (o *BackupOp) Execute(ctx *Context, node Executable) error

func (*BackupOp) Name ¶

func (o *BackupOp) Name() string

type BuildOptions ¶

type BuildOptions struct {
	// DryRun prevents the builder from making filesystem queries with 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 subgraph building behavior.

type Collision ¶

type Collision struct {
	Target            string `json:"target" yaml:"target"`
	Winner            string `json:"winner" yaml:"winner"`
	WinnerLayer       string `json:"winner_layer,omitempty" yaml:"winner_layer,omitempty"`
	WinnerSpecificity int    `json:"winner_specificity,omitempty" yaml:"winner_specificity,omitempty"`
	Loser             string `json:"loser" yaml:"loser"`
	LoserLayer        string `json:"loser_layer,omitempty" yaml:"loser_layer,omitempty"`
	LoserSpecificity  int    `json:"loser_specificity,omitempty" yaml:"loser_specificity,omitempty"`
}

Collision records a source conflict resolved during tree building (writ-specific).

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 during execution.

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 GraphExecutor.Run().
	Data map[string]any
}

Context provides execution context to operations.

type CopyOp ¶

type CopyOp struct{}

CopyOp writes content to node's "path" slot and returns the target checksum.

func (*CopyOp) Category ¶

func (o *CopyOp) Category() OpCategory

func (*CopyOp) Name ¶

func (o *CopyOp) Name() string

func (*CopyOp) Write ¶

func (o *CopyOp) Write(ctx *Context, node Executable, content []byte) (string, error)

type DecryptOp ¶

type DecryptOp struct{}

DecryptOp decrypts content using the SOPS API. The decryption configuration is expected in ctx.Data. Returns the decrypted content.

func (*DecryptOp) Category ¶

func (o *DecryptOp) Category() OpCategory

func (*DecryptOp) Name ¶

func (o *DecryptOp) Name() string

func (*DecryptOp) Transform ¶

func (o *DecryptOp) Transform(ctx *Context, node Executable, content []byte) ([]byte, error)

type DependencyView ¶

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

DependencyView provides dependency analysis for a single execution graph. It indexes the graph's edges to enable efficient dependency queries.

func NewDependencyView ¶

func NewDependencyView(g *Graph) *DependencyView

NewDependencyView creates a DependencyView for the given graph.

func (*DependencyView) AllDependencies ¶

func (v *DependencyView) AllDependencies(nodeID string) []string

AllDependencies returns the transitive closure of dependencies for a node. This includes all nodes that must complete before this node can start.

func (*DependencyView) AllDependents ¶

func (v *DependencyView) AllDependents(nodeID string) []string

AllDependents returns the transitive closure of dependents for a node. This includes all nodes that directly or indirectly depend on this node.

func (*DependencyView) CriticalPath ¶

func (v *DependencyView) CriticalPath() []string

CriticalPath returns the longest dependency chain in the graph. This represents the minimum sequential execution path.

func (*DependencyView) Dependents ¶

func (v *DependencyView) Dependents(nodeID string) []string

Dependents returns the direct dependents of a node (nodes that wait for this one).

func (*DependencyView) DependsOn ¶

func (v *DependencyView) DependsOn(nodeID string) []string

DependsOn returns the direct dependencies of a node (nodes that must complete first).

func (*DependencyView) EdgeCount ¶

func (v *DependencyView) EdgeCount() int

EdgeCount returns the number of edges in the graph.

func (*DependencyView) Graph ¶

func (v *DependencyView) Graph() *Graph

Graph returns the underlying graph.

func (*DependencyView) HasCycle ¶

func (v *DependencyView) HasCycle() bool

HasCycle returns true if the graph contains a cycle.

func (*DependencyView) IndependentSets ¶

func (v *DependencyView) IndependentSets() [][]string

IndependentSets returns groups of nodes that have no dependencies between them. Each set can be executed fully in parallel with other sets.

func (*DependencyView) Leaves ¶

func (v *DependencyView) Leaves() []string

Leaves returns nodes with no dependents (final nodes in the graph).

func (*DependencyView) Node ¶

func (v *DependencyView) Node(id string) *Node

Node returns the node with the given ID, or nil if not found.

func (*DependencyView) NodeCount ¶

func (v *DependencyView) NodeCount() int

NodeCount returns the number of nodes in the graph.

func (*DependencyView) ParallelLevels ¶

func (v *DependencyView) ParallelLevels() [][]string

ParallelLevels returns nodes grouped by execution level. Level 0 contains roots (can execute immediately). Level N contains nodes whose dependencies are all in levels < N. Within each level, nodes can execute in parallel.

func (*DependencyView) PathBetween ¶

func (v *DependencyView) PathBetween(source, target string) []string

PathBetween returns the shortest path from source to target, or nil if none exists.

func (*DependencyView) Roots ¶

func (v *DependencyView) Roots() []string

Roots returns nodes with no dependencies (can execute immediately).

func (*DependencyView) Subgraph ¶

func (v *DependencyView) Subgraph(nodeIDs []string) *DependencyView

Subgraph returns a new DependencyView containing only the specified nodes and the edges between them.

func (*DependencyView) TopologicalOrder ¶

func (v *DependencyView) TopologicalOrder() []string

TopologicalOrder returns nodes in a valid execution order. Nodes appear after all their dependencies. Returns nil if the graph has a cycle.

type Direct ¶

type Direct interface {
	Operation
	Execute(ctx *Context, node Executable) error
}

Direct operations manage their own I/O with no content flow. Used for: link, mkdir, backup, unlink, remove, validate, rename, install.

type Edge ¶

type Edge struct {
	From string `json:"from" yaml:"from"`
	To   string `json:"to" yaml:"to"`
}

Edge represents a dependency relationship between two nodes. From must complete before To can begin execution.

type Encoder ¶

type Encoder interface {
	Encode(v any) error
}

Encoder is the interface for graph serialization. Both *json.Encoder and *yaml.Encoder satisfy this interface.

type EntryType ¶

type EntryType string

EntryType distinguishes between package and file entries.

const (
	// EntryPackage represents a lore package lifecycle entry.
	EntryPackage EntryType = "package"
	// EntryFile represents a project file entry (link/copy/expand/decrypt).
	EntryFile EntryType = "file"
)

type Executable ¶

type Executable interface {
	GetID() string
	GetOperations() []string
	GetSlot(name string) string
	GetProject() string
	GetMode() os.FileMode
}

Executable represents a unit of work that can be executed. This interface is implemented by Node.

type ExecutorOptions ¶

type ExecutorOptions 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
}

ExecutorOptions configures GraphExecutor behavior.

type FileEntry ¶

type FileEntry struct {
	// Target is the relative target path (e.g., ".bashrc").
	Target string `json:"target" yaml:"target"`

	// Source is the absolute source path.
	Source string `json:"source" yaml:"source"`

	// Project this file belongs to.
	Project string `json:"project" yaml:"project"`

	// Layer is the repository layer (base, team, personal).
	Layer string `json:"layer,omitempty" yaml:"layer,omitempty"`

	// History of deployment operations, ordered by time.
	History []HistoryRecord `json:"history" yaml:"history"`
}

FileEntry represents a project file's deployment history.

func (*FileEntry) IsCopied ¶

func (e *FileEntry) IsCopied() bool

IsCopied returns true if the latest operation was a copy (not symlink).

func (*FileEntry) IsLinked ¶

func (e *FileEntry) IsLinked() bool

IsLinked returns true if the latest operation was a symlink.

func (*FileEntry) LastOperation ¶

func (e *FileEntry) LastOperation() *HistoryRecord

LastOperation returns the most recent operation, or nil if no history.

func (*FileEntry) Operations ¶

func (e *FileEntry) Operations() []string

Operations returns the operations from the latest deployment.

func (*FileEntry) SourceChecksum ¶

func (e *FileEntry) SourceChecksum() string

SourceChecksum returns the source checksum from the latest operation.

func (*FileEntry) TargetChecksum ¶

func (e *FileEntry) TargetChecksum() string

TargetChecksum returns the target checksum from the latest operation.

type FileTree ¶

type FileTree struct {
	// Root is the target root path (e.g., $HOME).
	Root string `json:"root" yaml:"root"`

	// Entries provides flat lookup by relative target path.
	Entries map[string]*FileEntry `json:"entries" yaml:"entries"`

	// Tree is the hierarchical view.
	Tree *FileTreeNode `json:"tree" yaml:"tree"`
}

FileTree provides both flat and hierarchical access to files.

func (*FileTree) CopiedFiles ¶

func (t *FileTree) CopiedFiles() map[string]*FileEntry

CopiedFiles returns all entries that were copied (not symlinked).

func (*FileTree) ForProject ¶

func (t *FileTree) ForProject(project string) map[string]*FileEntry

ForProject returns all file entries for a specific project.

func (*FileTree) LinkedFiles ¶

func (t *FileTree) LinkedFiles() map[string]*FileEntry

LinkedFiles returns all entries that are symlinks.

func (*FileTree) Projects ¶

func (t *FileTree) Projects() []string

Projects returns a list of all projects with files in the tree.

type FileTreeNode ¶

type FileTreeNode struct {
	// Name is the filename or directory name.
	Name string `json:"name" yaml:"name"`

	// IsDir is true if this is a directory.
	IsDir bool `json:"is_dir" yaml:"is_dir"`

	// Entry is the file entry (nil for directories).
	Entry *FileEntry `json:"entry,omitempty" yaml:"entry,omitempty"`

	// Children are the child nodes (nil for files).
	Children map[string]*FileTreeNode `json:"children,omitempty" yaml:"children,omitempty"`
}

FileTreeNode represents a node in the target filesystem tree.

type Graph ¶

type Graph struct {
	// Version is the graph format version.
	Version string `json:"version" yaml:"version"`

	// Tool identifies which tool created this graph ("writ" or "lore").
	Tool string `json:"tool" yaml:"tool"`

	// Timestamp is when the graph was created/executed.
	Timestamp time.Time `json:"timestamp" yaml:"timestamp"`

	// State is the execution state (pending, executed, failed).
	State GraphState `json:"state" yaml:"state"`

	// Platform records the OS and architecture.
	Platform Platform `json:"platform" yaml:"platform"`

	// Context contains tool-specific metadata.
	Context GraphContext `json:"context" yaml:"context"`

	// Nodes are the operations to perform/performed.
	Nodes []*Node `json:"nodes" yaml:"nodes"`

	// Edges are the dependencies between nodes.
	Edges []Edge `json:"edges,omitempty" yaml:"edges,omitempty"`

	// Collisions records source conflicts resolved during tree building (writ-specific).
	Collisions []Collision `json:"collisions,omitempty" yaml:"collisions,omitempty"`

	// Summary contains execution statistics (populated after Run).
	Summary Summary `json:"summary,omitempty" yaml:"summary,omitempty"`

	// Checksum is the git-style integrity hash.
	Checksum string `json:"checksum,omitempty" yaml:"checksum,omitempty"`

	// Signature contains the cryptographic signature (optional).
	Signature *Signature `json:"signature,omitempty" yaml:"signature,omitempty"`
}

Graph represents an execution graph containing nodes and edges. This is THE graph used by both writ and lore - they differ only in content.

Before Run(): State is "pending", represents the plan After Run(): State is "executed", represents the receipt

func (*Graph) ApplyResults ¶

func (g *Graph) ApplyResults(results []*Result)

ApplyResults updates node states from execution results.

func (*Graph) CanonicalContent ¶

func (g *Graph) CanonicalContent() ([]byte, error)

CanonicalContent returns the graph serialized as YAML without checksum and signature. This is used for computing checksums and verifying signatures.

func (*Graph) ComputeSummary ¶

func (g *Graph) ComputeSummary()

ComputeSummary calculates summary statistics from nodes.

func (*Graph) Filename ¶

func (g *Graph) Filename() string

Filename returns the standard filename for this graph. Format: "<tool>-<timestamp>.yaml"

func (*Graph) Serialize ¶

func (g *Graph) Serialize(enc Encoder) error

Serialize writes the graph to the given encoder. The checksum is computed before encoding.

Usage:

enc := yaml.NewEncoder(file)
enc.SetIndent(2)
defer enc.Close()
g.Serialize(enc)

type GraphBuilder ¶

type GraphBuilder interface {
	// Build creates an execution graph.
	// Implementations hold their configuration internally (set at construction).
	Build(ctx context.Context) (*Graph, error)
}

GraphBuilder is the interface for building execution graphs. Implementations are provided by tools (writ, lore) and create graphs from their respective inputs (file trees, package manifests, etc.).

type GraphContext ¶

type GraphContext struct {
	// SourceRoot is the source directory (writ: repo path, lore: registry cache).
	SourceRoot string `json:"source_root,omitempty" yaml:"source_root,omitempty"`

	// TargetRoot is the target directory (typically $HOME).
	TargetRoot string `json:"target_root,omitempty" yaml:"target_root,omitempty"`

	// Projects lists the projects included (writ-specific).
	Projects []string `json:"projects,omitempty" yaml:"projects,omitempty"`

	// Packages lists the packages included (lore-specific).
	Packages []string `json:"packages,omitempty" yaml:"packages,omitempty"`

	// Segments contains platform segment values (writ-specific).
	Segments map[string]string `json:"segments,omitempty" yaml:"segments,omitempty"`

	// Layers lists repository layers used (writ-specific).
	Layers []string `json:"layers,omitempty" yaml:"layers,omitempty"`

	// Platform is the target platform string (lore-specific, e.g., "Darwin", "Linux.Debian").
	TargetPlatform string `json:"target_platform,omitempty" yaml:"target_platform,omitempty"`

	// Features enabled for package installation (lore-specific).
	Features []string `json:"features,omitempty" yaml:"features,omitempty"`

	// Settings for package installation (lore-specific).
	Settings map[string]string `json:"settings,omitempty" yaml:"settings,omitempty"`
}

GraphContext contains tool-specific metadata stored in the graph. Both writ and lore populate this with their relevant context.

type GraphExecutor ¶

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

GraphExecutor executes operation graphs.

func NewGraphExecutor ¶

func NewGraphExecutor(registry *OperationRegistry, opts ExecutorOptions) *GraphExecutor

NewGraphExecutor creates an executor with the given registry and options.

func (*GraphExecutor) Run ¶

func (e *GraphExecutor) Run(ctx context.Context, g *Graph) error

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.

func (*GraphExecutor) RunNodes ¶

func (e *GraphExecutor) RunNodes(ctx context.Context, nodes []Executable, edges []Edge) ([]*Result, error)

RunNodes executes a slice of executables with the given edges. This is a lower-level API for callers that don't have a full Graph.

type GraphState ¶

type GraphState string

GraphState represents the execution state of the graph.

const (
	StatePending  GraphState = "pending"
	StateExecuted GraphState = "executed"
	StateFailed   GraphState = "failed"
)

type HistoryRecord ¶

type HistoryRecord struct {
	// Timestamp is when this operation occurred.
	Timestamp time.Time `json:"timestamp" yaml:"timestamp"`

	// Receipt is the filename of the receipt that recorded this.
	Receipt string `json:"receipt" yaml:"receipt"`

	// Tool is which tool created this record ("lore" or "writ").
	Tool string `json:"tool" yaml:"tool"`

	// Operations performed: link, expand, decrypt, install, verify, etc.
	Operations []string `json:"operations" yaml:"operations"`

	// Status of this operation: completed, skipped, failed.
	Status NodeStatus `json:"status" yaml:"status"`

	// SourceChecksum is the SHA256 of the source at operation time.
	SourceChecksum string `json:"source_checksum,omitempty" yaml:"source_checksum,omitempty"`

	// TargetChecksum is the SHA256 of the target after operation.
	TargetChecksum string `json:"target_checksum,omitempty" yaml:"target_checksum,omitempty"`
}

HistoryRecord represents a single operation on an entry from a receipt.

type LaunchdDisableOp ¶

type LaunchdDisableOp struct{}

LaunchdDisableOp disables a launchd service at boot (macOS).

func (*LaunchdDisableOp) Category ¶

func (o *LaunchdDisableOp) Category() OpCategory

func (*LaunchdDisableOp) Execute ¶

func (o *LaunchdDisableOp) Execute(ctx *Context, node Executable) error

func (*LaunchdDisableOp) Name ¶

func (o *LaunchdDisableOp) Name() string

type LaunchdEnableOp ¶

type LaunchdEnableOp struct{}

LaunchdEnableOp enables a launchd service at boot (macOS).

func (*LaunchdEnableOp) Category ¶

func (o *LaunchdEnableOp) Category() OpCategory

func (*LaunchdEnableOp) Execute ¶

func (o *LaunchdEnableOp) Execute(ctx *Context, node Executable) error

func (*LaunchdEnableOp) Name ¶

func (o *LaunchdEnableOp) Name() string

type LaunchdRestartOp ¶

type LaunchdRestartOp struct{}

LaunchdRestartOp restarts a launchd service (macOS).

func (*LaunchdRestartOp) Category ¶

func (o *LaunchdRestartOp) Category() OpCategory

func (*LaunchdRestartOp) Execute ¶

func (o *LaunchdRestartOp) Execute(ctx *Context, node Executable) error

func (*LaunchdRestartOp) Name ¶

func (o *LaunchdRestartOp) Name() string

type LaunchdStartOp ¶

type LaunchdStartOp struct{}

LaunchdStartOp starts a launchd service (macOS).

func (*LaunchdStartOp) Category ¶

func (o *LaunchdStartOp) Category() OpCategory

func (*LaunchdStartOp) Execute ¶

func (o *LaunchdStartOp) Execute(ctx *Context, node Executable) error

func (*LaunchdStartOp) Name ¶

func (o *LaunchdStartOp) Name() string

type LaunchdStopOp ¶

type LaunchdStopOp struct{}

LaunchdStopOp stops a launchd service (macOS).

func (*LaunchdStopOp) Category ¶

func (o *LaunchdStopOp) Category() OpCategory

func (*LaunchdStopOp) Execute ¶

func (o *LaunchdStopOp) Execute(ctx *Context, node Executable) error

func (*LaunchdStopOp) Name ¶

func (o *LaunchdStopOp) Name() string

type LinkOp ¶

type LinkOp struct{}

LinkOp creates a symlink from node's "path" slot pointing to "source" slot.

func (*LinkOp) Category ¶

func (o *LinkOp) Category() OpCategory

func (*LinkOp) Execute ¶

func (o *LinkOp) Execute(ctx *Context, node Executable) error

func (*LinkOp) Name ¶

func (o *LinkOp) Name() string

type MoveOp ¶

type MoveOp struct{}

MoveOp moves a file or directory from node's "source" slot to "path" slot using git mv when inside a git repository, falling back to os.Rename otherwise.

func (*MoveOp) Category ¶

func (o *MoveOp) Category() OpCategory

func (*MoveOp) Execute ¶

func (o *MoveOp) Execute(ctx *Context, node Executable) error

func (*MoveOp) Name ¶

func (o *MoveOp) Name() string

type Node ¶

type Node struct {
	// ID is the unique identifier (typically relative target path or package name).
	ID string `json:"id" yaml:"id"`

	// Operations to perform: link, copy, expand, decrypt, install, etc.
	Operations []string `json:"operations" yaml:"operations"`

	// Status of this node: pending, completed, skipped, failed.
	Status NodeStatus `json:"status" yaml:"status"`

	// Timestamp is when this operation completed.
	Timestamp string `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`

	// Slots holds input values for this node. Each slot can be:
	// - Immediate: value known at analysis time
	// - Promise: reference to another node's output (creates edge)
	Slots map[string]SlotValue `json:"slots,omitempty" yaml:"slots,omitempty"`

	// Project this node belongs to.
	Project string `json:"project,omitempty" yaml:"project,omitempty"`

	// Layer is the repository layer (base, team, personal).
	Layer string `json:"layer,omitempty" yaml:"layer,omitempty"`

	// Mode is the file permissions to set.
	Mode os.FileMode `json:"-" yaml:"-"`

	// SourceChecksum is the SHA256 of the source file at deploy time.
	SourceChecksum string `json:"source_checksum,omitempty" yaml:"source_checksum,omitempty"`

	// TargetChecksum is the SHA256 of the target file after deployment.
	TargetChecksum string `json:"target_checksum,omitempty" yaml:"target_checksum,omitempty"`

	// Error message if status is failed.
	Error string `json:"error,omitempty" yaml:"error,omitempty"`

	// Annotations holds extensible metadata (serialized to receipts).
	Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
}

Node represents a single unit of work in an execution graph.

func (*Node) GetID ¶

func (n *Node) GetID() string

GetID returns the node's unique identifier.

func (*Node) GetMode ¶

func (n *Node) GetMode() os.FileMode

GetMode returns the file mode.

func (*Node) GetOperations ¶

func (n *Node) GetOperations() []string

GetOperations returns the list of operations to perform.

func (*Node) GetProject ¶

func (n *Node) GetProject() string

GetProject returns the project name.

func (*Node) GetSlot ¶

func (n *Node) GetSlot(name string) string

GetSlot returns the resolved value of a slot. If the slot is a promise, returns empty string (must be resolved by executor).

func (*Node) SetSlotImmediate ¶

func (n *Node) SetSlotImmediate(name, value string)

SetSlotImmediate sets a slot to an immediate value.

func (*Node) SetSlotPromise ¶

func (n *Node) SetSlotPromise(name, nodeRef, slot string)

SetSlotPromise sets a slot to a promise (reference to another node).

type NodeStatus ¶

type NodeStatus string

NodeStatus represents the execution status of a node.

const (
	StatusPending   NodeStatus = "pending"
	StatusCompleted NodeStatus = "completed"
	StatusSkipped   NodeStatus = "skipped"
	StatusFailed    NodeStatus = "failed"
)

type OpCategory ¶

type OpCategory int

OpCategory classifies operations by their data flow behavior.

const (
	// OpTransform reads content, produces transformed content.
	OpTransform OpCategory = iota

	// OpWriter reads content, writes to filesystem, produces checksum.
	OpWriter

	// OpDirect manages its own I/O, no content flow.
	OpDirect
)

type Operation ¶

type Operation interface {
	// Name returns the operation identifier (e.g., "link", "decrypt").
	Name() string

	// Category returns the operation category for pipeline validation.
	Category() OpCategory
}

Operation is the base interface for all executable actions.

func AllOps ¶

func AllOps() []Operation

AllOps returns all operations (file + package) for registration. Both writ and lore should use this to ensure the same operations are available.

func FileOps ¶

func FileOps() []Operation

FileOps returns all built-in file operations for registration.

Transform operations (content in → content out):

  • decrypt: decrypts encrypted content via ctx.Data["decryptor"]
  • render: renders Go text/template content with ctx.Data

Writer operations (content in → checksum out):

  • copy: writes content to node's "path" slot

Direct operations (no content flow):

  • link: creates symlink from "path" → "source" slots
  • write: writes "content" slot to "path" slot
  • backup: moves "path" slot to timestamped backup
  • unlink: removes symlink at "path" slot
  • remove: deletes file at "path" slot
  • validate: checks precondition from ctx.Data["validators"]
  • move: moves "source" → "path" slots (git mv when possible)

NOTE: Package operations (package-install, package-upgrade, package-remove, package-update) are provided by ops_package.go.

func PackageOps ¶

func PackageOps() []Operation

PackageOps returns all package manager operations for registration.

func ServiceOps ¶

func ServiceOps() []Operation

ServiceOps returns all service manager operations for registration.

type OperationRegistry ¶

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

OperationRegistry maps operation names to their implementations. Each tool registers its operations before calling GraphExecutor.Run().

func NewOperationRegistry ¶

func NewOperationRegistry() *OperationRegistry

NewOperationRegistry creates an empty operation registry.

func (*OperationRegistry) Get ¶

func (r *OperationRegistry) Get(name string) (Operation, bool)

Get returns the operation registered under the given name.

func (*OperationRegistry) Names ¶

func (r *OperationRegistry) Names() []string

Names returns all registered operation names.

func (*OperationRegistry) Register ¶

func (r *OperationRegistry) Register(op Operation)

Register adds an operation to the registry. If an operation with the same name already exists, it is replaced.

type PackageEntry ¶

type PackageEntry struct {
	// Name is the package name (e.g., "docker").
	Name string `json:"name" yaml:"name"`

	// History of lifecycle operations, ordered by time.
	History []HistoryRecord `json:"history" yaml:"history"`
}

PackageEntry represents a lore package's lifecycle history.

func (*PackageEntry) LastOperation ¶

func (e *PackageEntry) LastOperation() *HistoryRecord

LastOperation returns the most recent operation, or nil if no history.

type PackageInstallOp ¶

type PackageInstallOp struct{}

PackageInstallOp installs packages using the platform's package manager.

func (*PackageInstallOp) Category ¶

func (o *PackageInstallOp) Category() OpCategory

func (*PackageInstallOp) Execute ¶

func (o *PackageInstallOp) Execute(ctx *Context, node Executable) error

func (*PackageInstallOp) Name ¶

func (o *PackageInstallOp) Name() string

type PackageRemoveOp ¶

type PackageRemoveOp struct{}

PackageRemoveOp removes packages using the platform's package manager.

func (*PackageRemoveOp) Category ¶

func (o *PackageRemoveOp) Category() OpCategory

func (*PackageRemoveOp) Execute ¶

func (o *PackageRemoveOp) Execute(ctx *Context, node Executable) error

func (*PackageRemoveOp) Name ¶

func (o *PackageRemoveOp) Name() string

type PackageUpdateOp ¶

type PackageUpdateOp struct{}

PackageUpdateOp refreshes the package manager index.

func (*PackageUpdateOp) Category ¶

func (o *PackageUpdateOp) Category() OpCategory

func (*PackageUpdateOp) Execute ¶

func (o *PackageUpdateOp) Execute(ctx *Context, node Executable) error

func (*PackageUpdateOp) Name ¶

func (o *PackageUpdateOp) Name() string

type PackageUpgradeOp ¶

type PackageUpgradeOp struct{}

PackageUpgradeOp upgrades packages using the platform's package manager.

func (*PackageUpgradeOp) Category ¶

func (o *PackageUpgradeOp) Category() OpCategory

func (*PackageUpgradeOp) Execute ¶

func (o *PackageUpgradeOp) Execute(ctx *Context, node Executable) error

func (*PackageUpgradeOp) Name ¶

func (o *PackageUpgradeOp) Name() string

type Plan ¶

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

Plan provides binding functions for building an execution graph. Graph producers (writ tree builder, lore pipeline executor, LLM graph builder) use Plan to add operations to the graph. Each method returns the created node for edge construction.

In Starlark scripts, the plan object is passed to each phase function:

def install(system, package, plan):
    plan.mkdir("/usr/local/bin")
    plan.link("/usr/local/bin/foo", source="/path/to/foo")

func NewPlan ¶

func NewPlan(project string) *Plan

NewPlan creates a new plan for building an execution graph.

func (*Plan) Backup ¶

func (p *Plan) Backup(path string) *Node

Backup adds a backup operation for an existing file.

func (*Plan) Copy ¶

func (p *Plan) Copy(source, path string, transforms ...string) *Node

Copy adds a file copy operation. Transforms (decrypt, expand) can be prepended to the pipeline.

func (*Plan) CopyWithMode ¶

func (p *Plan) CopyWithMode(source, path string, mode os.FileMode, transforms ...string) *Node

CopyWithMode adds a file copy operation with explicit permissions.

func (*Plan) DependsOn ¶

func (p *Plan) DependsOn(from, to *Node)

DependsOn adds an ordering edge: from must complete before to begins.

func (*Plan) Graph ¶

func (p *Plan) Graph() *Graph

Graph returns the built execution graph.

func (p *Plan) Link(source, path string) *Node

Link adds a symlink creation operation.

func (*Plan) Mkdir ¶

func (p *Plan) Mkdir(path string) *Node

Mkdir adds a directory creation operation.

func (*Plan) Orders ¶

func (p *Plan) Orders(from, to *Node)

Orders adds an ordering constraint between nodes.

func (*Plan) Remove ¶

func (p *Plan) Remove(path string) *Node

Remove adds a file/directory removal operation.

func (*Plan) Rename ¶

func (p *Plan) Rename(source, path string) *Node

Rename adds a file/directory move operation (git mv when possible).

func (p *Plan) Unlink(path string) *Node

Unlink adds a symlink removal operation.

func (*Plan) Validate ¶

func (p *Plan) Validate(check, message string) *Node

Validate adds a precondition check operation.

type Platform ¶

type Platform struct {
	OS   string `json:"os" yaml:"os"`
	Arch string `json:"arch" yaml:"arch"`
}

Platform records the OS and architecture.

type PowerShellOp ¶

type PowerShellOp struct{}

PowerShellOp executes a PowerShell command from node's "command" slot (Windows).

func (*PowerShellOp) Category ¶

func (o *PowerShellOp) Category() OpCategory

func (*PowerShellOp) Execute ¶

func (o *PowerShellOp) Execute(ctx *Context, node Executable) error

func (*PowerShellOp) Name ¶

func (o *PowerShellOp) Name() string

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 Preflight ¶

func Preflight(graph *Graph) *PreflightResult

Preflight performs pre-flight conflict detection without modifying anything. Only applies to nodes with file operations (link, copy).

func (*PreflightResult) HasConflicts ¶

func (p *PreflightResult) HasConflicts() bool

HasConflicts returns true if any conflicts were detected.

type RemoveOp ¶

type RemoveOp struct{}

RemoveOp deletes the file at node.GetSlot("path"). If ctx.Data["prune_empty_dirs"] is true and ctx.Data["prune_boundary"] is set, empty parent directories are removed up to the boundary.

func (*RemoveOp) Category ¶

func (o *RemoveOp) Category() OpCategory

func (*RemoveOp) Execute ¶

func (o *RemoveOp) Execute(ctx *Context, node Executable) error

func (*RemoveOp) Name ¶

func (o *RemoveOp) Name() string

type RenderOp ¶

type RenderOp struct{}

RenderOp processes content as a Go text/template with ctx.Data as the template data. Returns the rendered content.

func (*RenderOp) Category ¶

func (o *RenderOp) Category() OpCategory

func (*RenderOp) Name ¶

func (o *RenderOp) Name() string

func (*RenderOp) Transform ¶

func (o *RenderOp) Transform(ctx *Context, node Executable, content []byte) ([]byte, error)

type Result ¶

type Result struct {
	NodeID         string
	Status         ResultStatus
	Error          error
	Message        string
	SourceChecksum string
	TargetChecksum string
}

Result represents the outcome of executing a single node.

type ResultStatus ¶

type ResultStatus int

ResultStatus represents the execution status of a node.

const (
	// ResultPending means the node has not been processed yet.
	ResultPending ResultStatus = iota
	// ResultRunning means the node is currently executing.
	ResultRunning
	// ResultCompleted means the node executed successfully.
	ResultCompleted
	// ResultFailed means the node encountered an error.
	ResultFailed
	// ResultSkipped means the node was skipped (conflict, already deployed, etc.).
	ResultSkipped
)

func (ResultStatus) String ¶

func (s ResultStatus) String() string

String returns a human-readable status label.

type ShellOp ¶

type ShellOp struct{}

ShellOp executes a shell command from node's "command" slot.

func (*ShellOp) Category ¶

func (o *ShellOp) Category() OpCategory

func (*ShellOp) Execute ¶

func (o *ShellOp) Execute(ctx *Context, node Executable) error

func (*ShellOp) Name ¶

func (o *ShellOp) Name() string

type Signature ¶

type Signature struct {
	// Method is the signing method used (gpg, aws_kms, gcp_kms, azure_kv).
	Method string `json:"method" yaml:"method"`

	// Value is the signature data (base64-encoded).
	Value string `json:"value" yaml:"value"`

	// KeyID identifies the key used for signing.
	// For GPG: fingerprint, for KMS: key ARN/ID/URL.
	KeyID string `json:"key_id" yaml:"key_id"`
}

Signature contains the cryptographic signature of a graph.

type SlotValue ¶

type SlotValue struct {
	// Immediate is the direct value (string, used when known at analysis time).
	Immediate string `json:"immediate,omitempty" yaml:"immediate,omitempty"`

	// NodeRef is the ID of the node that produces this value (promise).
	NodeRef string `json:"node_ref,omitempty" yaml:"node_ref,omitempty"`

	// Slot is which output slot of the referenced node (empty = default output).
	Slot string `json:"slot,omitempty" yaml:"slot,omitempty"`
}

SlotValue represents a value that fills a slot in a node. Either Immediate is set (direct value) or NodeRef is set (promise from upstream node).

func (SlotValue) IsImmediate ¶

func (s SlotValue) IsImmediate() bool

IsImmediate returns true if this slot value is an immediate value.

func (SlotValue) IsPromise ¶

func (s SlotValue) IsPromise() bool

IsPromise returns true if this slot value is a promise (reference to another node).

type StateView ¶

type StateView struct {
	// Since is the start of the time window (inclusive).
	Since time.Time `json:"since" yaml:"since"`

	// Until is the end of the time window (inclusive).
	Until time.Time `json:"until" yaml:"until"`

	// ReceiptCount is the number of receipts included in this view.
	ReceiptCount int `json:"receipt_count" yaml:"receipt_count"`

	// Packages maps package names to their lifecycle history.
	Packages map[string]*PackageEntry `json:"packages" yaml:"packages"`

	// Files provides file entry access (flat and tree).
	Files *FileTree `json:"files" yaml:"files"`
}

StateView is a read-only view over multiple execution graphs. It represents "what we believe happened" over a time interval.

func (*StateView) Summary ¶

func (v *StateView) Summary() (packages, links, copied int)

Summary returns counts of packages, linked files, and copied files.

type StateViewBuilder ¶

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

StateViewBuilder creates StateViews from receipts.

func NewStateViewBuilder ¶

func NewStateViewBuilder(opts ViewOptions) *StateViewBuilder

NewStateViewBuilder creates a new builder with the given options.

func (*StateViewBuilder) Build ¶

func (b *StateViewBuilder) Build(receiptsDir string) (*StateView, error)

Build loads all receipts from the directory and builds a StateView.

func (*StateViewBuilder) BuildFrom ¶

func (b *StateViewBuilder) BuildFrom(graphs []*Graph) *StateView

BuildFrom creates a StateView from the given graphs.

type SubgraphBuilder ¶

type SubgraphBuilder interface {
	// BuildSubgraph creates a graph from a manifest file path.
	BuildSubgraph(ctx context.Context, manifestPath string, opts BuildOptions) (*Graph, error)
}

SubgraphBuilder builds subgraphs from manifest files during delegate expansion. This is used when a node with operation "delegate" is encountered, causing the referenced manifest to be expanded into a subgraph.

type Summary ¶

type Summary struct {
	TotalFiles int `json:"total_files,omitempty" yaml:"total_files,omitempty"`
	Links      int `json:"links,omitempty" yaml:"links,omitempty"`
	Copies     int `json:"copies,omitempty" yaml:"copies,omitempty"`
	Templates  int `json:"templates,omitempty" yaml:"templates,omitempty"`
	Secrets    int `json:"secrets,omitempty" yaml:"secrets,omitempty"`
	Packages   int `json:"packages,omitempty" yaml:"packages,omitempty"`
	Skipped    int `json:"skipped,omitempty" yaml:"skipped,omitempty"`
	Failed     int `json:"failed,omitempty" yaml:"failed,omitempty"`
	BackedUp   int `json:"backed_up,omitempty" yaml:"backed_up,omitempty"`
}

Summary contains execution statistics.

func (Summary) String ¶

func (s Summary) String() string

String returns a human-readable summary.

type SystemdDisableOp ¶

type SystemdDisableOp struct{}

SystemdDisableOp disables a systemd service at boot (Linux).

func (*SystemdDisableOp) Category ¶

func (o *SystemdDisableOp) Category() OpCategory

func (*SystemdDisableOp) Execute ¶

func (o *SystemdDisableOp) Execute(ctx *Context, node Executable) error

func (*SystemdDisableOp) Name ¶

func (o *SystemdDisableOp) Name() string

type SystemdEnableOp ¶

type SystemdEnableOp struct{}

SystemdEnableOp enables a systemd service at boot (Linux).

func (*SystemdEnableOp) Category ¶

func (o *SystemdEnableOp) Category() OpCategory

func (*SystemdEnableOp) Execute ¶

func (o *SystemdEnableOp) Execute(ctx *Context, node Executable) error

func (*SystemdEnableOp) Name ¶

func (o *SystemdEnableOp) Name() string

type SystemdRestartOp ¶

type SystemdRestartOp struct{}

SystemdRestartOp restarts a systemd service (Linux).

func (*SystemdRestartOp) Category ¶

func (o *SystemdRestartOp) Category() OpCategory

func (*SystemdRestartOp) Execute ¶

func (o *SystemdRestartOp) Execute(ctx *Context, node Executable) error

func (*SystemdRestartOp) Name ¶

func (o *SystemdRestartOp) Name() string

type SystemdStartOp ¶

type SystemdStartOp struct{}

SystemdStartOp starts a systemd service (Linux).

func (*SystemdStartOp) Category ¶

func (o *SystemdStartOp) Category() OpCategory

func (*SystemdStartOp) Execute ¶

func (o *SystemdStartOp) Execute(ctx *Context, node Executable) error

func (*SystemdStartOp) Name ¶

func (o *SystemdStartOp) Name() string

type SystemdStopOp ¶

type SystemdStopOp struct{}

SystemdStopOp stops a systemd service (Linux).

func (*SystemdStopOp) Category ¶

func (o *SystemdStopOp) Category() OpCategory

func (*SystemdStopOp) Execute ¶

func (o *SystemdStopOp) Execute(ctx *Context, node Executable) error

func (*SystemdStopOp) Name ¶

func (o *SystemdStopOp) Name() string

type Transform ¶

type Transform interface {
	Operation
	Transform(ctx *Context, node Executable, content []byte) ([]byte, error)
}

Transform operations read content and produce transformed content. Used for: decrypt, expand.

type UnlinkOp ¶

type UnlinkOp struct{}

UnlinkOp removes a symlink at node's "path" slot. If ctx.Data["prune_empty_dirs"] is true and ctx.Data["prune_boundary"] is set, empty parent directories are removed up to the boundary.

func (*UnlinkOp) Category ¶

func (o *UnlinkOp) Category() OpCategory

func (*UnlinkOp) Execute ¶

func (o *UnlinkOp) Execute(ctx *Context, node Executable) error

func (*UnlinkOp) Name ¶

func (o *UnlinkOp) Name() string

type ValidateOp ¶

type ValidateOp struct{}

ValidateOp checks a precondition and fails with a message if unmet. The check function is retrieved from ctx.Data["validators"][node.GetSlot("check")].

func (*ValidateOp) Category ¶

func (o *ValidateOp) Category() OpCategory

func (*ValidateOp) Execute ¶

func (o *ValidateOp) Execute(ctx *Context, node Executable) error

func (*ValidateOp) Name ¶

func (o *ValidateOp) Name() string

type ViewOptions ¶

type ViewOptions struct {
	// Since filters to receipts after this time (zero = no lower bound).
	Since time.Time

	// Until filters to receipts before this time (zero = no upper bound).
	Until time.Time

	// Tools filters to specific tools (empty = all tools).
	Tools []string
}

ViewOptions configures how the view is built.

type WinServiceDisableOp ¶

type WinServiceDisableOp struct{}

WinServiceDisableOp configures a Windows service to be disabled.

func (*WinServiceDisableOp) Category ¶

func (o *WinServiceDisableOp) Category() OpCategory

func (*WinServiceDisableOp) Execute ¶

func (o *WinServiceDisableOp) Execute(ctx *Context, node Executable) error

func (*WinServiceDisableOp) Name ¶

func (o *WinServiceDisableOp) Name() string

type WinServiceEnableOp ¶

type WinServiceEnableOp struct{}

WinServiceEnableOp configures a Windows service to start automatically.

func (*WinServiceEnableOp) Category ¶

func (o *WinServiceEnableOp) Category() OpCategory

func (*WinServiceEnableOp) Execute ¶

func (o *WinServiceEnableOp) Execute(ctx *Context, node Executable) error

func (*WinServiceEnableOp) Name ¶

func (o *WinServiceEnableOp) Name() string

type WinServiceRestartOp ¶

type WinServiceRestartOp struct{}

WinServiceRestartOp restarts a Windows service (stop + start).

func (*WinServiceRestartOp) Category ¶

func (o *WinServiceRestartOp) Category() OpCategory

func (*WinServiceRestartOp) Execute ¶

func (o *WinServiceRestartOp) Execute(ctx *Context, node Executable) error

func (*WinServiceRestartOp) Name ¶

func (o *WinServiceRestartOp) Name() string

type WinServiceStartOp ¶

type WinServiceStartOp struct{}

WinServiceStartOp starts a Windows service.

func (*WinServiceStartOp) Category ¶

func (o *WinServiceStartOp) Category() OpCategory

func (*WinServiceStartOp) Execute ¶

func (o *WinServiceStartOp) Execute(ctx *Context, node Executable) error

func (*WinServiceStartOp) Name ¶

func (o *WinServiceStartOp) Name() string

type WinServiceStopOp ¶

type WinServiceStopOp struct{}

WinServiceStopOp stops a Windows service.

func (*WinServiceStopOp) Category ¶

func (o *WinServiceStopOp) Category() OpCategory

func (*WinServiceStopOp) Execute ¶

func (o *WinServiceStopOp) Execute(ctx *Context, node Executable) error

func (*WinServiceStopOp) Name ¶

func (o *WinServiceStopOp) Name() string

type WriteOp ¶

type WriteOp struct{}

WriteOp writes content from node's "content" slot to node's "path" slot. Used by plan.file.write() for writing inline content directly.

func (*WriteOp) Category ¶

func (o *WriteOp) Category() OpCategory

func (*WriteOp) Execute ¶

func (o *WriteOp) Execute(ctx *Context, node Executable) error

func (*WriteOp) Name ¶

func (o *WriteOp) Name() string

type Writer ¶

type Writer interface {
	Operation
	Write(ctx *Context, node Executable, content []byte) (targetChecksum string, err error)
}

Writer operations read content and write to the filesystem. Used for: copy.

Jump to

Keyboard shortcuts

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