Documentation
¶
Overview ¶
Package drift compares a resolved plan against the live system. All checks are read-only probes; nothing is installed, written, or ensured.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ColorDiff ¶ added in v0.16.0
ColorDiff adds ANSI colors to unified diff output. When color is false the input is returned unchanged. + lines (not +++) get green, - lines (not ---) get red, @@ hunk headers get cyan.
func Render ¶
func Render(w io.Writer, findings []Finding, renderOptions ...RenderOption)
Render writes the drift report. Sections appear in fixed order and only when they have ≥1 finding. Non-OK findings print as ` <module>: <item> - <detail>`; the owning module replaces the status prefix (drift is implied for listed items; unknown items get a (?) suffix). A section whose findings are all OK prints ` ok: all N checks passed`. The orphans section groups its findings under layer-root headings (` base:` / ` hosts/<hostname>:` / ` users/<username>:`), one ` <module>: <file> - <detail>` line each. On a TTY, finding lines are colored by issue type: orange (missing/version drift), red (not-a-symlink/unknown), yellow (content differs), and magenta (orphans). The final line is `no drift` when nothing drifted, otherwise `drift: N item(s)` with `, K unknown` appended when there are unknowns.
func UnifiedDiff ¶ added in v0.16.0
UnifiedDiff computes a unified diff between current (live) and desired (profile) file content. Returns empty string when content is identical. targetName/sourceName label the --- and +++ header lines.
Types ¶
type CheckOptions ¶
type CheckOptions struct {
// Jobs bounds concurrent probe workers; <= 0 uses runtime.NumCPU().
Jobs int
// Verbose, when non-nil, receives one "checking <section>: <item>" line
// per probe as it starts. Writes are serialized internally.
Verbose io.Writer
}
CheckOptions controls how Check runs its probes.
type Finding ¶
type Finding struct {
Section string // "packages" | "tools" | "dotfiles" | "mounts" | "smb" | "orphans"
Item string // package name, tool name, target path, unit name, share name
Status Status
Detail string
Module string // owning module ID (empty if unknown)
// Group is the orphans-only layer-root heading the finding renders
// under: "base", "hosts/<hostname>", or "users/<username>". Empty for
// every other section (they render flat).
Group string
}
Finding is one checked item. Detail is empty for OK.
func Check ¶
func Check(ctx context.Context, plan *resolve.Plan, profileRoot string, pr Probes, opts CheckOptions) []Finding
Check runs every read-only probe for the plan concurrently (bounded by opts.Jobs; <= 0 → runtime.NumCPU) and returns findings in fixed section order (packages → tools → dotfiles → mounts → smb). Each worker writes only its own indexed result slot, so output order is deterministic regardless of completion order. opts.Verbose, when non-nil, receives one "checking <section>: <item>" line per probe as it starts. A nil plan returns nil.
func CheckOrphans ¶ added in v0.24.0
func CheckOrphans(plan *resolve.Plan, layers []ModuleLayer) []Finding
CheckOrphans reports files inside the given module layer directories that no [dotfiles] entry of that module references — neither explicitly (source = "...") nor implicitly (the source subtree of a symlink-each entry, attributed to the layer whose module.toml DECLARES the entry). Findings land in the "orphans" section grouped by layer root (Group = "base" / "hosts/<hostname>" / "users/<username>", Module = the bare module dir), so stale content is visible per host/user/module. module.toml is the manifest itself and never an orphan.
type ModuleLayer ¶ added in v0.24.0
type ModuleLayer struct {
Dir string // module directory name (dotfile-entry Module key)
Layer string // "base" | "host" | "user"
Owner string // hostname (host layer) or username (user layer); empty for base
Path string // absolute layer module directory
}
ModuleLayer names one layer directory of one module: the module's directory name (the layer-merge key), the layer it lives in, and the absolute path. For host/user layers Owner names the layer's hostname or username so orphan group headings read "hosts/<hostname>" / "users/<username>". Callers derive these from the profile layout (modules/<dir>, hosts/<hostname>/modules/<dir>, users/<username>/modules/<dir>).
type Probes ¶
type Probes struct {
IsInstalled func(ctx context.Context, pkg string) (bool, error)
ToolCurrent func(ctx context.Context, tool string) (string, error) // err or "" → Unknown
Run func(ctx context.Context, name string, args ...string) (string, error)
HomeDir string
Readlink func(path string) (string, error)
ReadFile func(path string) ([]byte, error)
StatDir func(path string) (bool, error) // exists and is a directory
Stat func(path string) (bool, error) // exists (file or dir) — source validity
ListDir func(path string) ([]string, error) // direct child names — stale symlink-each scan
}
Probes are the side-effect seams. DefaultProbes fills OS-backed defaults; tests override individual fields. IsInstalled and ToolCurrent have no generic OS default (they need a package backend / mise) and must be set by the caller before Check.
func DefaultProbes ¶
func DefaultProbes() Probes
DefaultProbes returns OS-backed probes for Run, Readlink, ReadFile, StatDir, Stat, ListDir, and HomeDir. IsInstalled and ToolCurrent are left nil — wire them to a package backend and mise before calling Check.
type RenderOption ¶ added in v0.24.0
type RenderOption func(*renderOpts)
RenderOption configures one Render call.
func WithPalette ¶ added in v0.24.0
func WithPalette(p *palette.Palette) RenderOption
WithPalette selects the color palette for the report (per-role overrides from dotdrift.toml [colors]); nil falls back to the default.