ledger

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2026 License: GPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package ledger is dstow's current-state index of the symlinks it believes exist (DESIGN.md §6 + A10; ADR 0001). It is one JSON document per machine at $XDG_STATE_HOME/dstow/ledger.json — never a journal, never a history: entries are the links dstow currently believes exist, pruned wherever disk contradicts them (disk is always the truth).

The package splits cleanly along §6.3's read/write line. Load (§6.2/§6.3) is a lock-free snapshot that never creates or writes a file. Update (§6.2/§6.3, A10) holds an exclusive flock for the whole operation, prunes contradicted entries in scope, runs the caller's mutation, and commits with one atomic temp-file+fsync+rename. Contradicted is the single owner of the disk-disagrees test so report (reads) and prune (writes) can never disagree.

The package returns data and typed errors only (A4): it never writes to stdout/stderr and renders no prose for humans beyond its error strings, which carry the §6.5 remedies. RecordedAt is the caller's to stamp — entry creation belongs to the deploy verbs — so the package itself stamps nothing.

Index

Constants

View Source
const Version = 1

Version is the schema version this dstow writes and understands (§6.5). It is bumped only on an incompatible change; v1 is the first schema.

Variables

This section is empty.

Functions

func LockPath

func LockPath(path string) string

LockPath is the sibling ledger.lock of the given ledger path (§6.2): writers take an exclusive advisory flock on it; the ledger document itself is never locked.

func Path

func Path() string

Path is the one ledger document per machine: $XDG_STATE_HOME/dstow/ledger.json (§6.1). Machine state lives in JSON in its XDG state lane, via adrg/xdg.

Types

type CorruptError

type CorruptError struct {
	Path string
	Err  error
}

CorruptError refuses an unparseable or invalid-version ledger (§6.5): corruption must never degrade into amnesia, so Load names the path and points at the remedy rather than starting empty.

func (*CorruptError) Error

func (e *CorruptError) Error() string

func (*CorruptError) Unwrap

func (e *CorruptError) Unwrap() error

type Entry

type Entry struct {
	Link        string    `json:"link"`        // target-relative, exactly how stow.Expected keys results
	Package     string    `json:"package"`     // canonical percent-encoded FQN
	Source      string    `json:"source"`      // package-relative
	Destination string    `json:"destination"` // literal symlink text as written — the damaged evidence
	RecordedAt  time.Time `json:"recorded_at"` // RFC 3339 UTC: when the entry entered the ledger
}

Entry is one ledgered link (§6.1). link is target-relative and source package-relative — exactly how stow.Expected keys and values its results — so ledger, Expected, and Owner compose directly.

func (Entry) Contradicted

func (e Entry) Contradicted(targetRoot string) (bool, string)

Contradicted reports whether disk disagrees with the entry under the given target root (CONTEXT.md "Contradicted entry"): the recorded path is gone, holds a non-link, or holds a different link text than recorded. Evidence is complete prose when contradicted, naming what disk shows against what the entry records. This is the one owner of the test — check (ops) consults it too, so report and prune can never disagree.

type Ledger

type Ledger struct {
	Version int                `json:"version"`
	Targets map[string][]Entry `json:"targets"` // absolute target root → entries; the grouping is rebuild's replace boundary
}

Ledger is the whole document (§6.1). Targets maps an absolute target root to its entries; the grouping is load-bearing — it is rebuild's replace boundary.

func Load

func Load(path string) (Ledger, error)

Load reads a lock-free snapshot of the ledger (§6.2/§6.3): it never creates or writes a file. A missing file is an empty ledger, never an error (§6.5). Unparseable JSON or a version below 1 is a *CorruptError; a version above this dstow's is a *NewerVersionError.

type LockedError

type LockedError struct {
	LockPath string
}

LockedError is fail-fast lock contention (§6.2): another dstow operation holds the ledger lock, and dstow refuses to wait (dpkg/pacman precedent).

func (*LockedError) Error

func (e *LockedError) Error() string

type NewerVersionError

type NewerVersionError struct {
	Path        string
	FileVersion int
}

NewerVersionError refuses a ledger written by a newer dstow (§6.5): never guess, never rewrite the file down — the remedy is to upgrade dstow.

func (*NewerVersionError) Error

func (e *NewerVersionError) Error() string

type Pruned

type Pruned struct {
	TargetRoot string
	Entry      Entry
	Evidence   string // complete prose: what disk shows vs what the entry records
}

Pruned records one entry removed by scoped pruning: the target root it lived under, the entry itself, and the complete evidence prose (what disk shows against what the entry recorded). The caller reports each prune loudly (§6.4).

func Update

func Update(path string, scope Scope, fn func(*Ledger) error) (pruned []Pruned, err error)

Update runs a write transaction against the ledger (§6.2/§6.3, A10). It takes an exclusive non-blocking flock on the sibling lock for the whole operation (contention → *LockedError, immediately), then under the lock: takes a fresh Load (never a stale snapshot), prunes contradicted entries the scope covers (reporting each in the returned slice — the entry is pruned, disk is never touched), runs fn on the pruned document, drops any empty target group, and commits with one atomic write. fn returning an error aborts the transaction with no write.

type Scope

type Scope struct {
	Packages []string // canonical FQNs: prune entries of these packages
	Paths    []string // absolute link paths (target root joined with entry link): prune entries at these paths
	All      bool     // the ledger-wide broom (clean §6.3)
}

Scope is a writer's pruning scope (§6.3): an entry is covered when All is set (the ledger-wide broom, clean §6.3), when its package is named, or when its absolute link path is named. Contradicted entries in scope are pruned; unrelated damage evidence survives.

Jump to

Keyboard shortcuts

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