ferrule v0.6.2

A content-addressed cache for build artifacts.

Ferrule stores build outputs by the hash of their inputs, so repeated builds resolve from disk instead of running again. Single static binary, no daemon, no configuration file required.

$ curl -fsSL https://tech.mahaon.xyz/install.sh | sh

Overview

Deterministic keys

Cache keys are derived from the command line, environment allowlist, and a digest of every declared input file. Identical inputs always resolve to the same entry.

No background process

Everything happens in the calling process. There is no daemon to supervise, no socket to clean up, and nothing left running after the build exits.

Bounded on disk

The store is pruned by least-recent-use against a size ceiling. Eviction runs inline and is safe to interrupt at any point.

Portable stores

A store is an ordinary directory. Copy it, mount it read-only, or share it over NFS between machines of the same architecture.

Usage

Wrap any command that produces files. Declare the inputs it reads and the outputs it writes:

# first run executes the compiler
ferrule run \
  --in src/*.c --in include/ \
  --out build/libwidget.a \
  -- cc -c -O2 src/*.c -o build/libwidget.a

# second run restores from the store in ~40ms
ferrule run --in src/*.c --in include/ \
  --out build/libwidget.a -- cc -c -O2 src/*.c -o build/libwidget.a
→ hit 3f9c1a2e (restored 1 file, 2.1 MiB)

Inspect what is stored and reclaim space:

ferrule stat            # entries, total size, hit ratio
ferrule prune --max 4G  # evict until under the ceiling
ferrule verify          # re-hash every entry, drop corrupt ones

Options

--store <path>
Location of the cache directory. Defaults to $XDG_CACHE_HOME/ferrule, falling back to ~/.cache/ferrule.
--env <name>
Include an environment variable in the cache key. Repeatable. Variables not listed are excluded, which keeps unrelated shell state out of the hash.
--max <size>
Size ceiling for the store, accepting K, M, and G suffixes. Default is 8G.
--no-write
Read from the store but never add to it. Useful on CI runners with a read-only shared cache mount.
--json
Emit machine-readable results on stdout. The command's own output is passed through on stderr unchanged.

Changes