Documentation
¶
Overview ¶
Package planner provides pure planning logic for computing operations.
Index ¶
- func ComputeDesiredState(packages []domain.Package, target domain.TargetPath, packageNameMapping bool) domain.Result[DesiredState]
- func ComputeOperationsFromDesiredState(desired DesiredState) []domain.Operation
- func DotOperationalPaths() []string
- func ValidateNoSelfManagement(packageName string, desired DesiredState) error
- type Conflict
- type ConflictType
- type CurrentState
- type DependencyGraph
- func (g *DependencyGraph) Dependencies(op domain.Operation) []domain.Operation
- func (g *DependencyGraph) FindCycle() []domain.Operation
- func (g *DependencyGraph) HasOperation(op domain.Operation) bool
- func (g *DependencyGraph) Operations() []domain.Operation
- func (g *DependencyGraph) ParallelizationPlan() [][]domain.Operation
- func (g *DependencyGraph) Size() int
- func (g *DependencyGraph) TopologicalSort() ([]domain.Operation, error)
- type DesiredState
- type DirSpec
- type FileInfo
- type LinkSpec
- type LinkTarget
- type PlanResult
- type ResolutionOutcome
- type ResolutionPolicies
- type ResolutionPolicy
- type ResolutionStatus
- type ResolveResult
- type Suggestion
- type Warning
- type WarningSeverity
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComputeDesiredState ¶
func ComputeDesiredState(packages []domain.Package, target domain.TargetPath, packageNameMapping bool) domain.Result[DesiredState]
ComputeDesiredState computes desired state from packages. This is a pure function that determines what links and directories should exist based on the package contents.
For each file in each package: 1. Compute relative path from package root 2. Apply dotfile translation (dot-vimrc -> .vimrc) 3. If packageNameMapping enabled, prepend translated package name 4. Join with target to get target path 5. Create LinkSpec (source -> target) 6. Create DirSpec for parent directories
func ComputeOperationsFromDesiredState ¶
func ComputeOperationsFromDesiredState(desired DesiredState) []domain.Operation
ComputeOperationsFromDesiredState converts desired state into operations
func DotOperationalPaths ¶
func DotOperationalPaths() []string
DotOperationalPaths returns the paths that dot uses for its own operation. Packages cannot create symlinks into these directories.
func ValidateNoSelfManagement ¶
func ValidateNoSelfManagement(packageName string, desired DesiredState) error
ValidateNoSelfManagement validates that a package does not attempt to manage dot's own operational directories.
Returns an error if: - Any link would be created inside dot's config directory (~/.config/dot/) - Any link would be created inside dot's data directory (~/.local/share/dot/) - Any link would override dot's operational directories
Types ¶
type Conflict ¶
type Conflict struct {
Type ConflictType
Path domain.FilePath
Details string
Context map[string]string // Additional context
Suggestions []Suggestion
}
Conflict represents a detected conflict during planning
func NewConflict ¶
func NewConflict(ct ConflictType, path domain.FilePath, details string) Conflict
NewConflict creates a new Conflict with the given type, path, and details
func (Conflict) WithContext ¶
WithContext adds a context key-value pair to the conflict
func (Conflict) WithSuggestion ¶
func (c Conflict) WithSuggestion(s Suggestion) Conflict
WithSuggestion adds a suggestion to the conflict
type ConflictType ¶
type ConflictType int
ConflictType categorizes conflicts by their nature
const ( // ConflictFileExists indicates a file exists at the link target location ConflictFileExists ConflictType = iota // ConflictWrongLink indicates a symlink points to the wrong source ConflictWrongLink // ConflictPermission indicates permission denied for operation ConflictPermission // ConflictCircular indicates a circular symlink dependency ConflictCircular // ConflictDirExpected indicates a directory was expected but file found ConflictDirExpected // ConflictFileExpected indicates a file was expected but directory found ConflictFileExpected )
func (ConflictType) String ¶
func (ct ConflictType) String() string
String returns the string representation of ConflictType
type CurrentState ¶
type CurrentState struct {
Files map[string]FileInfo // Regular files at target paths
Links map[string]LinkTarget // Existing symlinks
Dirs map[string]struct{} // Existing directories (set)
}
CurrentState represents the current filesystem state
type DependencyGraph ¶
type DependencyGraph struct {
// contains filtered or unexported fields
}
DependencyGraph represents operation dependencies for topological sorting. It maintains a directed graph where nodes are operations and edges represent dependencies (an edge from A to B means A depends on B).
func BuildGraph ¶
func BuildGraph(ops []domain.Operation) *DependencyGraph
BuildGraph constructs a dependency graph from a list of operations. It analyzes the Dependencies() of each operation to build the graph edges. Additionally, it computes implicit dependencies for DirCreate operations, ensuring parent directories are created before child directories.
Time complexity: O(n + e) where n is the number of operations and e is the total number of dependencies across all operations.
func (*DependencyGraph) Dependencies ¶
func (g *DependencyGraph) Dependencies(op domain.Operation) []domain.Operation
Dependencies returns the list of operations that the given operation depends on. Returns an empty slice if the operation has no dependencies or is not in the graph.
func (*DependencyGraph) FindCycle ¶
func (g *DependencyGraph) FindCycle() []domain.Operation
FindCycle detects circular dependencies using depth-first search. Returns a slice of operations forming a cycle, or nil if no cycle exists.
The returned cycle starts and ends with the same operation, showing the circular path: [A, B, C, A] indicates A depends on B, B depends on C, and C depends on A.
Time complexity: O(n + e) where n is the number of operations and e is the number of dependency edges.
func (*DependencyGraph) HasOperation ¶
func (g *DependencyGraph) HasOperation(op domain.Operation) bool
HasOperation returns true if the operation exists in the graph.
func (*DependencyGraph) Operations ¶
func (g *DependencyGraph) Operations() []domain.Operation
Operations returns all operations in the graph. The returned slice is a copy to prevent external modification.
func (*DependencyGraph) ParallelizationPlan ¶
func (g *DependencyGraph) ParallelizationPlan() [][]domain.Operation
ParallelizationPlan computes batches of operations that can execute concurrently. Returns a slice of batches where operations within each batch have no dependencies on each other and can run in parallel. Batches must execute sequentially - batch N must complete before batch N+1 begins.
The algorithm uses level-based grouping: operations with no dependencies are at level 0, operations depending only on level 0 are at level 1, etc. Operations at the same level can execute in parallel.
Time complexity: O(n + e) where n is the number of operations and e is the number of dependency edges.
func (*DependencyGraph) Size ¶
func (g *DependencyGraph) Size() int
Size returns the number of operations in the graph.
func (*DependencyGraph) TopologicalSort ¶
func (g *DependencyGraph) TopologicalSort() ([]domain.Operation, error)
TopologicalSort returns operations in dependency order using depth-first search. Operations with no dependencies come first, and each operation appears after all its dependencies.
Returns an error if the graph contains cycles, as cyclic dependencies cannot be topologically sorted.
Time complexity: O(n + e) where n is the number of operations and e is the number of dependency edges.
type DesiredState ¶
type DesiredState struct {
Links map[string]LinkSpec // Key: target path
Dirs map[string]DirSpec // Key: directory path
}
DesiredState represents the desired filesystem state.
type LinkSpec ¶
type LinkSpec struct {
Source domain.FilePath // Source file in package
Target domain.TargetPath // Target location
}
LinkSpec specifies a desired symbolic link.
type PlanResult ¶
type PlanResult struct {
Desired DesiredState
Resolved *ResolveResult // Optional resolution results
}
PlanResult contains planning results with optional conflict resolution
func (PlanResult) HasConflicts ¶
func (pr PlanResult) HasConflicts() bool
HasConflicts returns true if there are unresolved conflicts
type ResolutionOutcome ¶
type ResolutionOutcome struct {
Status ResolutionStatus
Operations []domain.Operation // Modified operations after resolution
Conflict *Conflict // If status is ResolveConflict
Warning *Warning // If status is ResolveWarning
}
ResolutionOutcome captures the result of resolving a single operation
type ResolutionPolicies ¶
type ResolutionPolicies struct {
OnFileExists ResolutionPolicy
OnWrongLink ResolutionPolicy
OnPermissionErr ResolutionPolicy
OnCircular ResolutionPolicy
OnTypeMismatch ResolutionPolicy
}
ResolutionPolicies configures conflict resolution behavior per conflict type
func DefaultPolicies ¶
func DefaultPolicies() ResolutionPolicies
DefaultPolicies returns safe default policies (all fail)
type ResolutionPolicy ¶
type ResolutionPolicy int
ResolutionPolicy defines how to handle conflicts
const ( // PolicyFail stops and reports conflict (default, safest) PolicyFail ResolutionPolicy = iota // PolicyBackup backs up conflicting file before linking PolicyBackup // PolicyOverwrite replaces conflicting file with link PolicyOverwrite // PolicySkip skips conflicting operation PolicySkip )
func (ResolutionPolicy) String ¶
func (rp ResolutionPolicy) String() string
String returns the string representation of ResolutionPolicy
type ResolutionStatus ¶
type ResolutionStatus int
ResolutionStatus indicates the outcome of conflict resolution
const ( // ResolveOK indicates no conflict, proceed with operation ResolveOK ResolutionStatus = iota // ResolveConflict indicates unresolved conflict, operation fails ResolveConflict // ResolveWarning indicates resolved with warning ResolveWarning // ResolveSkip indicates operation was skipped ResolveSkip )
func (ResolutionStatus) String ¶
func (rs ResolutionStatus) String() string
String returns the string representation of ResolutionStatus
type ResolveResult ¶
ResolveResult contains all resolved operations, conflicts, and warnings
func NewResolveResult ¶
func NewResolveResult(ops []domain.Operation) ResolveResult
NewResolveResult creates a new ResolveResult with the given operations
func Resolve ¶
func Resolve( operations []domain.Operation, current CurrentState, policies ResolutionPolicies, backupDir string, ) ResolveResult
Resolve applies conflict resolution to a list of operations
func (ResolveResult) ConflictCount ¶
func (r ResolveResult) ConflictCount() int
ConflictCount returns the number of conflicts
func (ResolveResult) HasConflicts ¶
func (r ResolveResult) HasConflicts() bool
HasConflicts returns true if there are any conflicts
func (ResolveResult) WarningCount ¶
func (r ResolveResult) WarningCount() int
WarningCount returns the number of warnings
func (ResolveResult) WithConflict ¶
func (r ResolveResult) WithConflict(c Conflict) ResolveResult
WithConflict adds a conflict to the result
func (ResolveResult) WithWarning ¶
func (r ResolveResult) WithWarning(w Warning) ResolveResult
WithWarning adds a warning to the result
type Suggestion ¶
type Suggestion struct {
Action string // What to do
Explanation string // Why this helps
Example string // Example command (optional)
}
Suggestion provides actionable resolution guidance
type Warning ¶
type Warning struct {
Message string
Severity WarningSeverity
Context map[string]string
}
Warning represents a non-fatal issue
type WarningSeverity ¶
type WarningSeverity int
WarningSeverity indicates the severity level of a warning
const ( // WarnInfo is informational only WarnInfo WarningSeverity = iota // WarnCaution requires attention WarnCaution // WarnDanger indicates potentially destructive operation WarnDanger )
func (WarningSeverity) String ¶
func (ws WarningSeverity) String() string
String returns the string representation of WarningSeverity