<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>cacher — S3-backed CI cache helper</title>
<style>
:root {
--fg: #1a1a1a;
--muted: #666;
--link: #0a5a9c;
--bg: #fdfdfd;
--code-bg: #f3f3f0;
--rule: #d8d8d4;
}
@media (prefers-color-scheme: dark) {
:root {
--fg: #e6e6e6;
--muted: #9a9a9a;
--link: #6bbfff;
--bg: #161616;
--code-bg: #222;
--rule: #333;
}
}
* { box-sizing: border-box; }
html, body { background: var(--bg); color: var(--fg); }
body {
max-width: 44rem;
margin: 2rem auto;
padding: 0 1.25rem 4rem;
font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
}
h1, h2, h3 { line-height: 1.25; }
h1 { font-size: 1.7rem; margin-bottom: 0.15rem; }
h2 { font-size: 1.15rem; margin-top: 2.2rem; padding-bottom: .2rem; border-bottom: 1px solid var(--rule); }
h3 { font-size: 1rem; margin-top: 1.4rem; }
p, ul, ol { margin: .7rem 0; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
code, pre, kbd { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; font-size: .92em; }
code { background: var(--code-bg); padding: 1px 4px; border-radius: 3px; }
pre { background: var(--code-bg); padding: .75rem 1rem; overflow-x: auto; border-radius: 4px; }
pre code { background: none; padding: 0; }
.tagline { color: var(--muted); margin-top: 0; }
.meta { color: var(--muted); font-size: .9em; }
.meta dt { float: left; clear: left; width: 6.5rem; }
.meta dd { margin: 0 0 .15rem 6.5rem; word-break: break-all; }
hr { border: 0; border-top: 1px solid var(--rule); margin: 2rem 0; }
footer { color: var(--muted); font-size: .85em; margin-top: 3rem; }
</style>
</head>
<body>
<h1>cacher</h1>
<p class="tagline">S3-backed CI cache helper. A single static Go binary.</p>
<h2>What it is</h2>
<p>
<code>cacher</code> is the build that the typical "check S3, fall back to
upstream, upload for next time" shell loop should have been. It downloads,
uploads, lists, and invalidates cached artifacts in any S3-compatible
bucket — single files, docker images (via streamed
<code>save | zstd | s3</code>), and whole directory trees keyed by lockfile
hash. Built for <a href="https://builds.sr.ht">builds.sr.ht</a>; works
anywhere you can run a binary and reach an S3 endpoint.
</p>
<h2>Install</h2>
<pre><code>wget https://bigbes.pages.srht.bigb.es/ci-cacher/cacher-linux-amd64 \
-O ~/.local/bin/cacher
chmod +x ~/.local/bin/cacher</code></pre>
<p>
Verify the binary against the sha256 below before using it.
</p>
<h2>The loop it replaces</h2>
<pre><code># before — install awscli, write ~/.aws/config, then in every task:
if aws s3api head-object --bucket "$B" --key "$K" >/dev/null 2>&1; then
aws s3 cp "s3://$B/$K" "$out"
else
curl -sSL "$url" -o "$out"
aws s3 cp "$out" "s3://$B/$K"
fi</code></pre>
<pre><code># after — one binary, one config, one command:
cacher download "$key" "$out" --url "$url"</code></pre>
<h2>Commands</h2>
<ul>
<li><code>init</code> / <code>doctor</code> — persist config + smoke-test creds</li>
<li><code>download</code> / <code>upload</code> — single file, with <code>--url</code> fallback and <code>--sha256</code> verify</li>
<li><code>exists</code> / <code>list</code> / <code>delete</code> / <code>key</code> — management + shell helpers</li>
<li><code>docker {exists,download,upload}</code> — streamed save/load via zstd</li>
<li><code>dir {download,upload}</code> — tar+zstd directory caching, keyed by content hash</li>
</ul>
<p>
Run <code>cacher --help</code> for the full surface. Read
<a href="https://git.srht.bigb.es/~bigbes/ci-cacher/tree/master/README.md">the
README</a> for usage patterns, Garage compatibility notes, and exit-code semantics.
</p>
<h2>Why</h2>
<p>
The shell version this replaced repeated five things in every CI task:
install AWS CLI v2 (≈50 MB per build), write a Garage-tuned
<code>~/.aws/config</code>, compute cache keys from file content with
<code>sha256sum | cut</code>, branch HIT/MISS by hand, and for
docker images pipe <code>docker save | zstd | aws s3 cp -</code> (and the
inverse). <code>cacher</code> collapses all of that into one fetched binary
plus a config file. The directory caching is the genuinely new capability —
the shell version only ever handled single files.
</p>
<h2>This build</h2>
<dl class="meta">
<dt>Version</dt> <dd>{{VERSION}}</dd>
<dt>SHA-256</dt> <dd><code>{{SHA256}}</code></dd>
<dt>Built</dt> <dd>{{BUILT}}</dd>
<dt>Source</dt> <dd><a href="https://git.srht.bigb.es/~bigbes/ci-cacher">git.srht.bigb.es/~bigbes/ci-cacher</a></dd>
<dt>License</dt> <dd>BSD-2-Clause</dd>
</dl>
<footer>
Published via <a href="https://man.sr.ht/pages.sr.ht/">pages.sr.ht</a> by
<a href="https://git.srht.bigb.es/~bigbes/ci-cacher/tree/master/.builds/publish.yml">.builds/publish.yml</a>.
</footer>
</body>
</html>