Fix #117: Support bootstrap on read-only installations (e.g., Nix store)#193
Fix #117: Support bootstrap on read-only installations (e.g., Nix store)#193KaoruBB wants to merge 2 commits intogcv:masterfrom
Conversation
Refactor macro to handle unwritable envs and Activation fallback
Ensure dir and action are properly escaped to avoid hygiene issues in macro expansion.
There was a problem hiding this comment.
Pull request overview
This PR updates JuliaSnail’s bootstrap/environment handling to work when the installation directory is read-only (e.g., Nix store) by creating a writable cached environment under DEPOT_PATH and activating it during bootstrap.
Changes:
- Added
pkg_env_for_bootstrap(dir)to redirect bootstrapping to a writable cached environment whendiris not writable. - Updated
@with_pkg_envto activate the selected environment, retry the action after instantiating/precompiling when bootstrap is required, and restore the previously active project afterward. - Added
bootstrap_required(err)to broaden bootstrap detection to include certainLoadErrorcases.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| env_name = "julia-snail-" * string(hash(abspath(dir)), base=16) | ||
| cache = joinpath(first(Base.DEPOT_PATH), "environments", env_name) |
There was a problem hiding this comment.
env_name is derived from hash(abspath(dir)), but hash is intentionally not stable across Julia sessions (seeded), so the cache directory name may change between runs. That defeats the purpose of a persistent bootstrap cache and can create a new environment on every startup. Consider using a deterministic digest of abspath(dir) (e.g., SHA-1/SHA-256 via the SHA stdlib) or another stable encoding instead.
| function pkg_env_for_bootstrap(dir) | ||
| if iswritable(dir) | ||
| return dir | ||
| end | ||
| env_name = "julia-snail-" * string(hash(abspath(dir)), base=16) | ||
| cache = joinpath(first(Base.DEPOT_PATH), "environments", env_name) |
There was a problem hiding this comment.
The cache location uses first(Base.DEPOT_PATH). If the first depot is not writable (or DEPOT_PATH is empty/misconfigured), mkpath(cache) / cp(...) will fail, which undermines the read-only-installation support this PR adds. Consider selecting the first writable depot in Base.DEPOT_PATH (or falling back to tempdir() with a clear error if none are writable).
| function pkg_env_for_bootstrap(dir) | |
| if iswritable(dir) | |
| return dir | |
| end | |
| env_name = "julia-snail-" * string(hash(abspath(dir)), base=16) | |
| cache = joinpath(first(Base.DEPOT_PATH), "environments", env_name) | |
| function first_writable_depot_or_tempdir() | |
| # Try to find a writable depot in Base.DEPOT_PATH | |
| for depot in Base.DEPOT_PATH | |
| if iswritable(depot) | |
| return depot | |
| end | |
| end | |
| # Fall back to a writable temporary directory | |
| tmp = tempdir() | |
| if iswritable(tmp) | |
| return tmp | |
| end | |
| error("JuliaSnail: no writable depot in Base.DEPOT_PATH and tempdir() is not writable; cannot create cache environment.") | |
| end | |
| function pkg_env_for_bootstrap(dir) | |
| if iswritable(dir) | |
| return dir | |
| end | |
| env_name = "julia-snail-" * string(hash(abspath(dir)), base=16) | |
| cache_root = first_writable_depot_or_tempdir() | |
| cache = joinpath(cache_root, "environments", env_name) |
This PR fixes #117 by adding a writable environment fallback for the bootstrap process. It uses a hashed environment cache in
DEPOT_PATHif the installation directory is read-only.Fixes #117