cmd: add --exec fallback and --optional to the download commands --exec generalises the existing --url (file) and --pull (docker) fallbacks to anything expressible as a shell command: on a cache miss the script runs through sh -c and whatever it produced seeds the cache. That collapses the restore-or-build if/fi block CI manifests repeat around every cache into a single invocation. The destination directory is created before the script runs, so the script needs no mkdir -p of its own. The seed upload stays best-effort (the content is already on disk), but a failing script is fatal and propagates its own exit status rather than a generic 2. For docker the tag is verified with docker image inspect afterwards — with a best-effort upload, a script exiting 0 without building the image would otherwise pass silently and fail a later task. --optional turns a cache miss into exit 0 for download and dir download, so set -e manifests drop the trailing || echo "cache miss".
Add end-to-end test suite against real Garage via testcontainers * internal/testutil/garage: spins up dxflrs/garage:v2.3.0 with --single-node --default-bucket so the bucket + access key are auto-created from env vars at startup, no CLI bootstrap dance. Each Start() call yields a fresh container with random creds and registers t.Cleanup teardown. * e2e_test.go gated by build tag e2e exercises the compiled cacher binary against the container — covers init/doctor parity (the regression guard for the HeadBucket+signature bugs we hit on the real bucket), single-file round-trip, exit codes (1/2/3), URL fallback + cache fill, --hash-from parity with sha256sum, directory tar+zstd round-trip, and delimited list output. * just test-e2e recipe; requires Docker on the host. Total runtime ~30s after first image pull (~1.5s/container).