Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JULIA_DEPOT_PATH: expand empty path to default #31009

Merged
merged 4 commits into from
Feb 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Multi-threading changes

Language changes
----------------

* Empty entries in `JULIA_DEPOT_PATH` are now expanded to default depot entries ([#31009]).
* `Enum` now behaves like a scalar when used in broadcasting ([#30670]).

Command-line option changes
Expand Down
58 changes: 53 additions & 5 deletions base/initdefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,63 @@ isinteractive() = (is_interactive::Bool)

## package depots (registries, packages, environments) ##

"""
DEPOT_PATH

A stack of "depot" locations where the package manager, as well as Julia's code
loading mechanisms, look for package registries, installed packages, named
environments, repo clones, cached compiled package images, and configuration
files. By default it includes:

1. `~/.julia` where `~` is the user home as appropriate on the system;
2. an architecture-specific shared system directory, e.g. `/usr/local/share/julia`;
3. an architecture-independent shared system directory, e.g. `/usr/share/julia`.

So `DEPOT_PATH` might be:
```julia
[joinpath(homedir(), ".julia"), "/usr/local/share/julia", "/usr/share/julia"]
```
The first entry is the "user depot" and should be writable by and owned by the
current user. The user depot is where: registries are cloned, new package versions
are installed, named environments are created and updated, package repos are cloned,
newly compiled package image files are saved, log files are written, development
packages are checked out by default, and global configuration data is saved. Later
entries in the depot path are treated as read-only and are appropriate for
registries, packages, etc. installed and managed by system administrators.

`DEPOT_PATH` is populated based on the [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH)
environment variable if set.

See also:
[`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH), and
[Code Loading](@ref Code-Loading).
"""
const DEPOT_PATH = String[]

function append_default_depot_path!(DEPOT_PATH)
path = joinpath(homedir(), ".julia")
path in DEPOT_PATH || push!(DEPOT_PATH, path)
path = abspath(Sys.BINDIR, "..", "local", "share", "julia")
path in DEPOT_PATH || push!(DEPOT_PATH, path)
path = abspath(Sys.BINDIR, "..", "share", "julia")
path in DEPOT_PATH || push!(DEPOT_PATH, path)
end

function init_depot_path()
empty!(DEPOT_PATH)
if haskey(ENV, "JULIA_DEPOT_PATH")
depots = split(ENV["JULIA_DEPOT_PATH"], Sys.iswindows() ? ';' : ':')
append!(empty!(DEPOT_PATH), map(expanduser, depots))
str = ENV["JULIA_DEPOT_PATH"]
isempty(str) && return
for path in split(str, Sys.iswindows() ? ';' : ':')
if isempty(path)
append_default_depot_path!(DEPOT_PATH)
else
path = expanduser(path)
path in DEPOT_PATH || push!(DEPOT_PATH, path)
end
end
else
push!(empty!(DEPOT_PATH), joinpath(homedir(), ".julia"))
push!(DEPOT_PATH, abspath(Sys.BINDIR, "..", "local", "share", "julia"))
push!(DEPOT_PATH, abspath(Sys.BINDIR, "..", "share", "julia"))
append_default_depot_path!(DEPOT_PATH)
end
end

Expand Down Expand Up @@ -148,6 +195,7 @@ function parse_load_path(str::String)
env = current_project()
env === nothing && continue
end
env = expanduser(env)
env in envs || push!(envs, env)
end
end
Expand Down
1 change: 1 addition & 0 deletions doc/src/base/constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Base.PROGRAM_FILE
Base.ARGS
Base.C_NULL
Base.VERSION
Base.DEPOT_PATH
Base.LOAD_PATH
Base.Sys.BINDIR
Base.Sys.CPU_THREADS
Expand Down
61 changes: 36 additions & 25 deletions doc/src/manual/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ the chapter on [Code Loading](@ref).

The `JULIA_LOAD_PATH` environment variable is used to populate the global Julia
[`LOAD_PATH`](@ref) variable, which determines which packages can be loaded via
`import` and `using` (see [Code Loading](@ref)). Unlike the shell `PATH` variable,
empty entries in `JULIA_LOAD_PATH` are expanded to the default value of `LOAD_PATH`,
`["@", "@v#.#", "@stdlib"]` when populating `LOAD_PATH`. This allows easy appending,
prepending, etc. of the load path value in shell scripts regardless of whether
`JULIA_LOAD_PATH` is already set or not. For example, to prepend the directory
`/foo/bar` to `LOAD_PATH` just do
`import` and `using` (see [Code Loading](@ref)).

Unlike the shell `PATH` variable, empty entries in `JULIA_LOAD_PATH` are expanded to
the default value of `LOAD_PATH`, `["@", "@v#.#", "@stdlib"]` when populating
`LOAD_PATH`. This allows easy appending, prepending, etc. of the load path value in
shell scripts regardless of whether `JULIA_LOAD_PATH` is already set or not. For
example, to prepend the directory `/foo/bar` to `LOAD_PATH` just do
```sh
export JULIA_LOAD_PATH="/foo/bar:$JULIA_LOAD_PATH"
```
Expand All @@ -110,6 +111,32 @@ This behavior was chosen so that it would be possible to set an empty load path
the environment variable. If you want the default load path, either unset the
environment variable or if it must have a value, set it to the string `:`.

### `JULIA_DEPOT_PATH`

The `JULIA_DEPOT_PATH` environment variable is used to populate the global Julia
[`DEPOT_PATH`](@ref) variable, which controls where the package manager, as well
as Julia's code loading mechanisms, look for package registries, installed
packages, named environments, repo clones, cached compiled package images, and
configuration files.

Unlike the shell `PATH` variable but similar to `JULIA_LOAD_PATH`, empty entries in
`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` is already set or not. For example, to prepend the
directory `/foo/bar` to `DEPOT_PATH` just do
```sh
export JULIA_DEPOT_PATH="/foo/bar:$JULIA_DEPOT_PATH"
```
If the `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` 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` 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 `:`.

### `JULIA_HISTORY`

The absolute path `REPL.find_hist_file()` of the REPL's history file. If
Expand All @@ -128,25 +155,9 @@ by default `1`, and larger values correspond to larger amounts of time.

Suppose the value of `$JULIA_PKGRESOLVE_ACCURACY` is `n`. Then

* the number of pre-decimation iterations is `20*n`,
* the number of iterations between decimation steps is `10*n`, and
* at decimation steps, at most one in every `20*n` packages is decimated.

### `JULIA_DEPOT_PATH`

A stack of depot locations where the package manager, as well as Julia's code loading
mechanisms, look for package registries, installed packages, named environments,
repo clones, cached compiled package images, and configuration files.

The depot path is controlled by Julia's `DEPOT_PATH` global variable which is populated at
startup based on the value of the `JULIA_DEPOT_PATH` environment variable. The first entry
is the “user depot” and should be writable by and owned by the current user. The user depot
is where: registries are cloned, new package versions are installed, named environments are
created and updated, package repos are cloned, newly compiled package image files are
saved, log files are written, development packages are checked out by default, and global
configuration data is saved. Later entries in the depot path are treated as read-only and
are appropriate for registries, packages, etc. installed and managed by system
administrators.
* the number of pre-decimation iterations is `20*n`,
* the number of iterations between decimation steps is `10*n`, and
* at decimation steps, at most one in every `20*n` packages is decimated.


## External applications
Expand Down
37 changes: 37 additions & 0 deletions test/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,43 @@ mktempdir() do dir
end
end

@testset "expansion of JULIA_LOAD_PATH" begin
s = Sys.iswindows() ? ';' : ':'
tmp = "/foo/bar"
cases = Dict{Any,Vector{String}}(
nothing => Base.DEFAULT_LOAD_PATH,
"" => [],
"$s" => Base.DEFAULT_LOAD_PATH,
"$tmp$s" => [tmp; Base.DEFAULT_LOAD_PATH],
"$s$tmp" => [Base.DEFAULT_LOAD_PATH; tmp],
)
for (env, result) in pairs(cases)
withenv("JULIA_LOAD_PATH" => env) do
script = "LOAD_PATH == $(repr(result)) || error()"
@test success(`$(Base.julia_cmd()) -e $script`)
end
end
end

@testset "expansion of JULIA_DEPOT_PATH" begin
s = Sys.iswindows() ? ';' : ':'
tmp = "/foo/bar"
DEFAULT = Base.append_default_depot_path!(String[])
cases = Dict{Any,Vector{String}}(
nothing => DEFAULT,
"" => [],
"$s" => DEFAULT,
"$tmp$s" => [tmp; DEFAULT],
"$s$tmp" => [DEFAULT; tmp],
)
for (env, result) in pairs(cases)
withenv("JULIA_DEPOT_PATH" => env) do
script = "DEPOT_PATH == $(repr(result)) || error()"
@test success(`$(Base.julia_cmd()) -e $script`)
end
end
end

## cleanup after tests ##

for env in keys(envs)
Expand Down