Repository navigation
Minor release. The image cache is now keyed on the image recipe, which stops stale base images from being reused. The CLI and config are backward compatible. The library's public Rust API has breaking changes, listed below, which is why this is 0.10.0 rather than 0.9.15.
Image cache keyed on the image recipe (#263)
A cached base image is now identified by its checkpoint commit plus the recipe it was built from, compared for exact equality. The old key was the checkpoint commit plus the config file path, which was wrong in both directions:
- Stale image reuse. Editing
sandbox_init_cmdorprovider.dockerfilewithout touching abuild_inputsfile reused the old image, and nothing was logged. Any recipe change is now a cache miss. - Duplicate builds. Configs that differed only in
[framework],[report]orsandbox_project_rooteach built their own base image. Configs with the same recipe now share one base image. - Working-tree leak. In a checkpoint build,
include_cwd, relativecopy_dirsand.dockerignorewere read from the live working tree. They now come from the exported checkpoint tree, and the live-tree inputs that remain are digested into the recipe.
The recipe holds:
- The builder inputs. On Modal these are
dockerfile, theinclude_cwddirectory and the bundledmodal_sandbox.py. On the default provider they areprepare_commandandworking_dir. copy_dirsand--copy-dir, in order.sandbox_init_cmd.- Digests of everything the build reads from outside the checkpoint tree: copy sources outside the repository, the gitignored files the export copies in, and tracked symlinks whose targets are outside the repository or missing. The digests include file mode bits.
Changing post_patch_cmd, [framework], [groups], [report], sandbox_project_root, env, cpu_cores or memory_gb does not rebuild the base image. The full design is in plans/image-cache-key.spec.md.
Fixed in the same change:
- The default provider resolves relative
copy_dirsand--copy-dirsources against itsworking_dirwhen one is set, because that is whereprepare_commandruns. - Absolute symlinks that point into the repository are rewritten to point at the exported checkpoint tree's copy of their target, not the live tree.
- The recipe's file walk no longer follows symlinked directories. Before, a link cycle such as
loop -> .madeoffload run,offload buildandoffload checkpoint-statusfail.
New command: offload checkpoint-status
Prints HEAD, the checkpoint commit and its distance from HEAD, the cached image, the mode the next run would use, and the current recipe name. It then prints one line per note entry, saying whether the entry matches, which recipe fields differ, or that it is a legacy entry from an older Offload. --remote NAME sets the remote to fetch notes from (default origin).
Upgrading
- No config changes are needed, and every existing TOML file keeps its meaning.
- Cache entries written by older versions are ignored, so the first run after upgrading rebuilds the base image once per recipe for each active checkpoint.
- Older versions keep reading and writing their own entries in
refs/notes/offload-images. When an older version writes a note on a commit, it strips the new fields from that commit's entries, so the next 0.10.0 run rebuilds that image once.
Breaking library API changes
These affect only code that uses offload as a Rust library:
image_cache::CheckpointInfoandimage_cache::LatestCommitInfoare removed.image_cache::resolve_latest_commitandimage_cache::resolve_checkpointreturn only the base commit SHA, and no longer takeconfig_pathorno_cache.image_cache::resolve_basetakescopy_dirsinstead of the config path.image_cache::write_note_for_committakes theRecipe.image_cache::ResolvedBasehas a new public field,recipe.git::ImageEntryhas four new public fields:recipe,config_path,offload_versionandbuilt_at.- New public items: the
image_cache::recipemodule andgit::path_within_repo.
Dependencies
- New:
sha20.10 for recipe digests, andhumantime2 for note timestamps. async-traitgoes from 0.1.89 to 0.1.92 so clippy 1.99 passes.
Full changelog: v0.9.14...v0.10.0