planner

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Nov 24, 2025 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package planner provides pure planning logic for computing operations.

Index

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

func (c Conflict) WithContext(key, value string) Conflict

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]bool       // Existing directories
}

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 DirSpec

type DirSpec struct {
	Path domain.FilePath
}

DirSpec specifies a desired directory.

type FileInfo

type FileInfo struct {
	Size int64
	Mode uint32
}

FileInfo represents basic file information

type LinkSpec

type LinkSpec struct {
	Source domain.FilePath   // Source file in package
	Target domain.TargetPath // Target location
}

LinkSpec specifies a desired symbolic link.

type LinkTarget

type LinkTarget struct {
	Target string
}

LinkTarget represents a symlink target

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

type ResolveResult struct {
	Operations []domain.Operation
	Conflicts  []Conflict
	Warnings   []Warning
}

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

Jump to

Keyboard shortcuts

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