The dependency-cache layer in Dockerfile has been a no-op since the workspace grew past four crates, so every image build compiles the full dependency graph from scratch.
What is wrong
Dockerfile:12-24 copies four crate manifests before priming the dependency cache:
COPY Cargo.toml Cargo.lock ./
COPY crates/gitlawb-core/Cargo.toml crates/gitlawb-core/
COPY crates/gitlawb-node/Cargo.toml crates/gitlawb-node/
COPY crates/gl/Cargo.toml crates/gl/
COPY crates/git-remote-gitlawb/Cargo.toml crates/git-remote-gitlawb/
The workspace has six members. Cargo.toml also lists crates/gitlawb-attest and crates/icaptcha-client, and crates/gl/Cargo.toml:15 takes a path dependency on the latter:
icaptcha-client = { path = "../icaptcha-client" }
So cargo fails while loading the workspace, before it ever resolves dependencies or reads Cargo.lock. The || true at the end of the layer swallows the error and the build proceeds as if the cache had been primed.
Reproduction
Built the first 24 lines of Dockerfile unchanged (docker 29.1.3), with a diagnostic step appended:
--- target/release/deps rlib count ---
0
--- registry cache size ---
no registry cache
--- rerun the layer command without || true ---
error: failed to load manifest for workspace member `/build/crates/gl`
referenced by workspace at `/build/Cargo.toml`
Caused by:
failed to load manifest for dependency `icaptcha-client`
Caused by:
failed to read `/build/crates/icaptcha-client/Cargo.toml`
Caused by:
No such file or directory (os error 2)
exit=101
Zero compiled rlibs and no registry cache: the layer downloads nothing and builds nothing.
Impact
Every build of the main image is a cold build of the whole dependency graph, including the docker-build smoke test in pr-checks.yml (30-minute timeout) and the docker job that pushes to ghcr on release. The real build at Dockerfile:37 still produces a correct image, so this is wasted CI time rather than a correctness bug. It also silently defeats the layer-caching intent stated in the comment at line 18, so a reader would reasonably assume dependencies are cached when they are not.
Fix
Copy all six member manifests (and create the matching dummy src entries) so the layer can resolve, and consider dropping the || true that hid this. A trailing || true on a cache-priming step means the next crate added to the workspace breaks it silently again; if the layer is expected to succeed, letting it fail loudly is what would have surfaced this at the time.
Noticed while adding --locked to the shipping builds in #243. Filing separately rather than widening that PR.
The fix above is verified, not just proposed
Built the same layer with all six manifests copied, matching dummy src entries added, and the || true dropped:
--- rlib count after the fixed cache layer ---
619
--- registry cache ---
508M /usr/local/cargo/registry
619 compiled rlibs and a 508 MB registry cache, against 0 and none today. The layer also succeeds without || true, so the guard is not load-bearing once the manifest list is complete.
The dependency-cache layer in
Dockerfilehas been a no-op since the workspace grew past four crates, so every image build compiles the full dependency graph from scratch.What is wrong
Dockerfile:12-24copies four crate manifests before priming the dependency cache:The workspace has six members.
Cargo.tomlalso listscrates/gitlawb-attestandcrates/icaptcha-client, andcrates/gl/Cargo.toml:15takes a path dependency on the latter:So cargo fails while loading the workspace, before it ever resolves dependencies or reads
Cargo.lock. The|| trueat the end of the layer swallows the error and the build proceeds as if the cache had been primed.Reproduction
Built the first 24 lines of
Dockerfileunchanged (docker 29.1.3), with a diagnostic step appended:Zero compiled rlibs and no registry cache: the layer downloads nothing and builds nothing.
Impact
Every build of the main image is a cold build of the whole dependency graph, including the
docker-buildsmoke test inpr-checks.yml(30-minute timeout) and thedockerjob that pushes to ghcr on release. The real build atDockerfile:37still produces a correct image, so this is wasted CI time rather than a correctness bug. It also silently defeats the layer-caching intent stated in the comment at line 18, so a reader would reasonably assume dependencies are cached when they are not.Fix
Copy all six member manifests (and create the matching dummy
srcentries) so the layer can resolve, and consider dropping the|| truethat hid this. A trailing|| trueon a cache-priming step means the next crate added to the workspace breaks it silently again; if the layer is expected to succeed, letting it fail loudly is what would have surfaced this at the time.Noticed while adding
--lockedto the shipping builds in #243. Filing separately rather than widening that PR.The fix above is verified, not just proposed
Built the same layer with all six manifests copied, matching dummy
srcentries added, and the|| truedropped:619 compiled rlibs and a 508 MB registry cache, against 0 and none today. The layer also succeeds without
|| true, so the guard is not load-bearing once the manifest list is complete.