diff --git a/NEWS.md b/NEWS.md index bab64a2d195ac..0af3ff45d5c9a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,9 @@ New language features Language changes ---------------- +* 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]). diff --git a/base/initdefs.jl b/base/initdefs.jl index c04a97971eff2..898d6c5fc18cd 100644 --- a/base/initdefs.jl +++ b/base/initdefs.jl @@ -86,9 +86,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") @@ -100,17 +98,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 diff --git a/doc/src/manual/environment-variables.md b/doc/src/manual/environment-variables.md index 2fc1dcbb2f32b..a2f6a0f2fb6cf 100644 --- a/doc/src/manual/environment-variables.md +++ b/doc/src/manual/environment-variables.md @@ -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 diff --git a/test/loading.jl b/test/loading.jl index d7e967f209eaa..84ca620e8aae4 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -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)