Skip to content

Commit

Permalink
When setting JULIA_DEPOT_PATH to /path:, omit the default user de…
Browse files Browse the repository at this point in the history
…pot (#51448)

This commit slightly changes how the `DEPOT_PATH` works when overriden using
the env var `JULIA_DEPOT_PATH`, now omitting the default user depot when
specifying a path.

Before:

```
❯ JULIA_DEPOT_PATH=/foo: \
  julia-1.10 -e 'display(DEPOT_PATH)'
4-element Vector{String}:
 "/foo"
 "/home/tim/.julia"
 "/path/to/julia/local/share/julia"
 "/path/to/julia/share/julia"
```

After:

```
❯ JULIA_DEPOT_PATH=/foo: \
  julia-pr -e 'display(DEPOT_PATH)'
3-element Vector{String}:
 "/foo"
 "/path/to/julia/local/share/julia"
 "/path/to/julia/share/julia"
```

This makes it possibly to create a new isolated depot by simply
setting `JULIA_DEPOT_PATH` to `/path:`, while still being able
to load resources that are bundled with Julia.

For a full discussion, see the PR.
  • Loading branch information
maleadt committed Dec 22, 2023
1 parent 878b0c0 commit 9443c76
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 26 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Language changes
pkgimage caches for all other packages than the package being tested, likely meaning faster test
execution. ([#52123])

* Specifying a path in `JULIA_DEPOT_PATH` now results in the expansion of empty strings to
omit the default user depot ([#51448]).

Compiler/Runtime improvements
-----------------------------
* Updated GC heuristics to count allocated pages instead of individual objects ([#50144]).
Expand Down
22 changes: 17 additions & 5 deletions base/initdefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@ See also [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH), and
"""
const DEPOT_PATH = String[]

function append_default_depot_path!(DEPOT_PATH)
path = joinpath(homedir(), ".julia")
path in DEPOT_PATH || push!(DEPOT_PATH, path)
function append_bundled_depot_path!(DEPOT_PATH)
path = abspath(Sys.BINDIR, "..", "local", "share", "julia")
path in DEPOT_PATH || push!(DEPOT_PATH, path)
path = abspath(Sys.BINDIR, "..", "share", "julia")
Expand All @@ -108,17 +106,31 @@ function init_depot_path()
empty!(DEPOT_PATH)
if haskey(ENV, "JULIA_DEPOT_PATH")
str = ENV["JULIA_DEPOT_PATH"]

# explicitly setting JULIA_DEPOT_PATH to the empty string means using no depot
isempty(str) && return

# otherwise, populate the depot path with the entries in JULIA_DEPOT_PATH,
# expanding empty strings to the bundled depot
populated = false
for path in eachsplit(str, Sys.iswindows() ? ';' : ':')
if isempty(path)
append_default_depot_path!(DEPOT_PATH)
append_bundled_depot_path!(DEPOT_PATH)
else
path = expanduser(path)
path in DEPOT_PATH || push!(DEPOT_PATH, path)
populated = true
end
end

# backwards compatibility: if JULIA_DEPOT_PATH only contains empty entries
# (e.g., JULIA_DEPOT_PATH=':'), make sure to use the default depot
if !populated
pushfirst!(DEPOT_PATH, joinpath(homedir(), ".julia"))
end
else
append_default_depot_path!(DEPOT_PATH)
push!(DEPOT_PATH, joinpath(homedir(), ".julia"))
append_bundled_depot_path!(DEPOT_PATH)
end
nothing
end
Expand Down
37 changes: 22 additions & 15 deletions doc/src/manual/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,30 @@ as Julia's code loading mechanisms, look for package registries, installed
packages, named environments, repo clones, cached compiled package images,
configuration files, and the default location of the REPL's history file.

Unlike the shell `PATH` variable but similar to [`JULIA_LOAD_PATH`](@ref JULIA_LOAD_PATH), empty entries in
[`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) are expanded to the default value of `DEPOT_PATH`. This allows
easy appending, prepending, etc. of the depot path value in shell scripts regardless
of whether [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) is already set or not. For example, to prepend the
directory `/foo/bar` to `DEPOT_PATH` just do
Unlike the shell `PATH` variable but similar to [`JULIA_LOAD_PATH`](@ref JULIA_LOAD_PATH),
empty entries in [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) are expanded to the default
value of `DEPOT_PATH`, excluding the user depot. This allows easy overriding of the user
depot, while still retaining access to resources that are bundled with Julia, like cache
files, artifacts, etc. For example, to switch the user depot to `/foo/bar` just do
```sh
export JULIA_DEPOT_PATH="/foo/bar:$JULIA_DEPOT_PATH"
export JULIA_DEPOT_PATH="/foo/bar:"
```
If the [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) environment variable is already set, its old value will be
prepended with `/foo/bar`. On the other hand, if [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) is not set, then
it will be set to `/foo/bar:` which will have the effect of prepending `/foo/bar` to
the default depot path. If [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) is set to the empty string, it expands
to an empty `DEPOT_PATH` array. In other words, the empty string is interpreted as a
zero-element array, not a one-element array of the empty string. This behavior was
chosen so that it would be possible to set an empty depot path via the environment
variable. If you want the default depot path, either unset the environment variable
or if it must have a value, set it to the string `:`.
All package operations, like cloning registrise or installing packages, will now write to
`/foo/bar`, but since the empty entry is expanded to the default system depot, any bundled
resources will still be available. If you really only want to use the depot at `/foo/bar`,
and not load any bundled resources, simply set the environment variable to `/foo/bar`
without the trailing colon.

There are two exceptions to the above rule. First, if [`JULIA_DEPOT_PATH`](@ref
JULIA_DEPOT_PATH) is set to the empty string, it expands to an empty `DEPOT_PATH` array. In
other words, the empty string is interpreted as a zero-element array, not a one-element
array of the empty string. This behavior was chosen so that it would be possible to set an
empty depot path via the environment variable.

Second, if no user depot is specified in [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH), then
the empty entry is expanded to the default depot *including* the user depot. This makes
it possible to use the default depot, as if the environment variable was unset, by setting
it to the string `:`.

!!! note

Expand Down
13 changes: 7 additions & 6 deletions test/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -721,16 +721,17 @@ end
@testset "expansion of JULIA_DEPOT_PATH" begin
s = Sys.iswindows() ? ';' : ':'
tmp = "/this/does/not/exist"
DEFAULT = Base.append_default_depot_path!(String[])
default = joinpath(homedir(), ".julia")
bundled = Base.append_bundled_depot_path!(String[])
cases = Dict{Any,Vector{String}}(
nothing => DEFAULT,
nothing => [default; bundled],
"" => [],
"$s" => DEFAULT,
"$tmp$s" => [tmp; DEFAULT],
"$s$tmp" => [DEFAULT; tmp],
"$s" => [default; bundled],
"$tmp$s" => [tmp; bundled],
"$s$tmp" => [bundled; tmp],
)
for (env, result) in pairs(cases)
script = "DEPOT_PATH == $(repr(result)) || error()"
script = "DEPOT_PATH == $(repr(result)) || error(\"actual depot \" * join(DEPOT_PATH,':') * \" does not match expected depot \" * join($(repr(result)), ':'))"
cmd = `$(Base.julia_cmd()) --startup-file=no -e $script`
cmd = addenv(cmd, "JULIA_DEPOT_PATH" => env)
cmd = pipeline(cmd; stdout, stderr)
Expand Down

0 comments on commit 9443c76

Please sign in to comment.