Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

dotling is structured as a layered Rust application with a command pattern. Each CLI subcommand maps to a module in src/commands/, and core logic is organized into four top-level modules.

Module hierarchy

dotling
├── core/                  Foundational utilities
│   ├── error              Error enum and Result type alias
│   ├── fs                 Filesystem helpers (walk, copy, symlink, atomic write)
│   ├── path               Path mapping, tilde expansion, category rules
│   ├── platform           OS detection, platform matching
│   └── store              Global state at ~/.dotling/
│
├── config/                Data model and rendering
│   ├── mod.rs             Config, Entry, Settings, Hooks, TOML parser/serializer
│   ├── template           Template engine: {{ var.x }}, {{ dotling.x }}, {{ env.X }}
│   └── vars               Machine-local variable store
│
├── crypto/                Encryption
│   ├── mod.rs             ChaCha20-Poly1305 encryption, Argon2id key derivation
│   └── vault              Vault management: init, unlock, export, import
│
├── sync/                  Sync and deployment
│   ├── mod.rs             Sync orchestration
│   ├── deploy             Entry deployment: symlink/copy, state checking
│   ├── fingerprint        Blake2s-256 content hashing for change detection
│   ├── hooks              Lifecycle hooks with trust verification
│   └── merge              Line-level three-way merge using LCS diff
│
├── cli.rs                 clap derive definitions for all CLI args/subcommands
├── commands/              Command handlers (one module per subcommand)
│   ├── init, add, remove, sync, status, edit
│   ├── encrypt, vault, doctor, vars, completions
│
├── ui.rs                  Terminal UI: colors, prompts, diff display
└── main.rs                Entry point: parse CLI, dispatch, handle errors

Data flow

CLI input (clap)
  → main.rs (parse args, dispatch)
    → commands/<subcommand>::run()
      → core/store (load repo root from ~/.dotling/state.toml)
      → config/mod (load dotling.toml)
      → sync engine
        → sync/deploy (create/fix symlinks, copy files)
        → sync/fingerprint (record/check content hashes)
        → sync/hooks (execute lifecycle hooks)
        → sync/merge (three-way merge for conflicts)
        → crypto (encrypt/decrypt as needed)
        → config/template (render templates)
      → ui (display results)

Data model

Config (dotling.toml)

The central configuration file at the repo root. Contains:

  • Settings — global defaults (deployment method)
  • Vec<Entry> — all tracked files/directories
  • Hooks — global lifecycle hooks
  • Vec<(String, String)> — shared variable defaults

The TOML parser and serializer are hand-rolled (no serde dependency).

Entry

Each tracked file or directory:

FieldTypeDescription
sourceStringRepo-relative path
targetStringDeploy target path with ~
methodOption<DeployMethod>Symlink or Copy override
encryptedboolWhether the entry is encrypted
directoryboolWhether the entry is a directory
templateboolWhether the entry is a template
osOption<String>Platform restriction
permissionsOption<u32>Octal permissions
beforeOption<String>Pre-sync hook
afterOption<String>Post-sync hook

FingerprintStore (~/.dotling/fingerprints.toml)

Maps source paths to EntryFingerprint records with three Blake2s-256 hashes: enc_hash (ciphertext), target_hash (deployed file), source_hash (repo source).

VarStore (~/.dotling/vars.toml)

Ordered list of (key, value) pairs for machine-local template variables.

Dependencies

CratePurpose
clapCLI argument parsing with derive macros
clap_completeShell completion generation
chacha20poly1305AEAD encryption
argon2Password-based key derivation
blake2Content hashing (fingerprints, hook trust)
randCryptographic random number generation
base64Binary-to-text encoding for encrypted files

No serde. No async runtime. Minimal by design.

Testing

Tests are inline #[cfg(test)] mod tests blocks across 15 files (94 tests total). Uses tempfile for temporary directories. Tests that mutate environment variables use a shared Mutex guard pattern to prevent interference.