Skip to content

Commit

Permalink
add --shared option for activate (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
Evizero authored and KristofferC committed Aug 4, 2018
1 parent ff586ed commit f647d70
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 30 deletions.
58 changes: 39 additions & 19 deletions stdlib/Pkg/src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -546,27 +546,47 @@ function status(ctx::Context, mode=PKGMODE_PROJECT)
return
end

activate() = (Base.ACTIVE_PROJECT[] = Base.load_path_expand(nothing))
function activate(path::String)
devpath = nothing
env = Base.active_project() === nothing ? nothing : EnvCache()
if env !== nothing && haskey(env.project["deps"], path)
uuid = UUID(env.project["deps"][path])
info = manifest_info(env, uuid)
devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing
end
# `pkg> activate path`/`Pkg.activate(path)` does the following
# 1. if path exists, activate that
# 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above)
# 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env)
if Types.isdir_windows_workaround(path)
path = abspath(path)
elseif devpath !== nothing
path = abspath(devpath)
activate() = (Base.ACTIVE_PROJECT[] = nothing)
function activate(path::String; shared::Bool=false)
if !shared
devpath = nothing
env = Base.active_project() === nothing ? nothing : EnvCache()
if env !== nothing && haskey(env.project["deps"], path)
uuid = UUID(env.project["deps"][path])
info = manifest_info(env, uuid)
devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing
end
# `pkg> activate path`/`Pkg.activate(path)` does the following
# 1. if path exists, activate that
# 2. if path exists in deps, and the dep is deved, activate that path (`devpath` above)
# 3. activate the non-existing directory (e.g. as in `pkg> activate .` for initing a new env)
if Types.isdir_windows_workaround(path)
fullpath = abspath(path)
elseif devpath !== nothing
fullpath = abspath(devpath)
else
fullpath = abspath(path)
isdir(fullpath) || @info("new environment will be placed at $fullpath")
end
else
path = abspath(path)
# initialize `fullpath` in case of empty `Pkg.depots()`
fullpath = ""
# loop over all depots to check if the shared environment already exists
for depot in Pkg.depots()
fullpath = joinpath(Pkg.envdir(depot), path)
isdir(fullpath) && break
end
# this disallows names such as "Foo/bar", ".", "..", etc
if basename(abspath(fullpath)) != path
cmderror("not a valid name for a shared environment: $(path)")
end
# unless the shared environment already exists, place it in the first depots
if !isdir(fullpath)
fullpath = joinpath(Pkg.envdir(Pkg.depots1()), path)
@info("new shared environment \"$path\" will be placed at $fullpath")
end
end
Base.ACTIVE_PROJECT[] = Base.load_path_expand(path)
Base.ACTIVE_PROJECT[] = Base.load_path_expand(fullpath)
end

"""
Expand Down
13 changes: 8 additions & 5 deletions stdlib/Pkg/src/Pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ end

logdir() = joinpath(depots1(), "logs")
devdir() = get(ENV, "JULIA_PKG_DEVDIR", joinpath(depots1(), "dev"))
envdir(depot = depots1()) = joinpath(depot, "environments")
const UPDATED_REGISTRY_THIS_SESSION = Ref(false)

# load snapshotted dependencies
Expand Down Expand Up @@ -261,18 +262,20 @@ const status = API.status


"""
Pkg.activate([s::String])
Pkg.activate([s::String]; shared::Bool=false)
Activate the environment at `s`. The active environment is the environment
that is modified by executing package commands.
The logic for what path is activated is as follows:
* If `s` is a path that exist, that environment will be activcated.
* If `s` is a package name in the current projec activate that is tracking a path,
activate the environment at that path.
* If `shared` is `true`, the first existing environment named `s` from the depots
in the depot stack will be activated. If no such environment exists yet,
activate it in the first depot.
* If `s` is a path that exist, that environment will be activated.
* If `s` is a package name in the current project activate that is tracking a path,
activate the environment at that path.
* If `s` is a non-existing path, activate that path.
If no argument is given to `activate`, activate the home project,
which is the one specified by either `--project` command line when starting julia,
or `JULIA_PROJECT` environment variable.
Expand Down
17 changes: 14 additions & 3 deletions stdlib/Pkg/src/REPLMode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ function do_activate!(args::PkgArguments, api_opts::APIOptions)
if isempty(args)
return API.activate()
else
return API.activate(args[1])
return API.activate(args[1]; collect(api_opts)...)
end
end

Expand Down Expand Up @@ -1110,8 +1110,19 @@ packages have changed causing the current Manifest to_indices be out of sync.
["activate"],
do_activate!,
(ARG_RAW, [0,1]),
[],
nothing,
[
("shared", OPT_SWITCH, :shared => true),
],
md"""
activate
activate [--shared] path
Activate the environment at the given `path`, or the home project environment if no `path` is specified.
The active environment is the environment that is modified by executing package commands.
When the option `--shared` is given, `path` will be assumed to be a directory name and searched for in the
`environments` folders of the depots in the depot stack. In case no such environment exists in any of the depots,
it will be placed in the first depot of the stack.
""" ,
),( CMD_UP,
["update", "up"],
do_up!,
Expand Down
23 changes: 20 additions & 3 deletions stdlib/Pkg/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,14 @@ temp_pkg_dir() do project_path
cd(mktempdir()) do
path = pwd()
pkg"activate ."
@test Base.active_project() == joinpath(path, "Project.toml")
# tests illegal names for shared environments
@test_throws Pkg.Types.CommandError pkg"activate --shared ."
@test_throws Pkg.Types.CommandError pkg"activate --shared ./Foo"
@test_throws Pkg.Types.CommandError pkg"activate --shared Foo/Bar"
@test_throws Pkg.Types.CommandError pkg"activate --shared ../Bar"
# check that those didn't change te enviroment
@test Base.active_project() == joinpath(path, "Project.toml")
mkdir("Foo")
cd(mkdir("modules")) do
pkg"generate Foo"
Expand All @@ -269,23 +277,32 @@ temp_pkg_dir() do project_path
pkg"activate Foo" # activate path Foo over deps Foo
@test Base.active_project() == joinpath(path, "Foo", "Project.toml")
pkg"activate ."
@test_logs (:info, r"new shared environment") pkg"activate --shared Foo" # activate shared Foo
@test Base.active_project() == joinpath(Pkg.envdir(), "Foo", "Project.toml")
pkg"activate ."
rm("Foo"; force=true, recursive=true)
pkg"activate Foo" # activate path from developed Foo
@test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml")
pkg"activate ."
pkg"activate ./Foo" # activate empty directory Foo (sidestep the developed Foo)
@test_logs (:info, r"new environment") pkg"activate ./Foo" # activate empty directory Foo (sidestep the developed Foo)
@test Base.active_project() == joinpath(path, "Foo", "Project.toml")
pkg"activate ."
pkg"activate Bar" # activate empty directory Bar
@test_logs (:info, r"new environment") pkg"activate Bar" # activate empty directory Bar
@test Base.active_project() == joinpath(path, "Bar", "Project.toml")
pkg"activate ."
pkg"add Example" # non-deved deps should not be activated
pkg"activate Example"
@test_logs (:info, r"new environment") pkg"activate Example"
@test Base.active_project() == joinpath(path, "Example", "Project.toml")
pkg"activate ."
cd(mkdir("tests"))
pkg"activate Foo" # activate developed Foo from another directory
@test Base.active_project() == joinpath(path, "modules", "Foo", "Project.toml")
tmpdepot = mktempdir()
tmpdir = mkpath(joinpath(tmpdepot, "environments", "Foo"))
push!(Base.DEPOT_PATH, tmpdepot)
pkg"activate --shared Foo" # activate existing shared Foo
@test Base.active_project() == joinpath(tmpdir, "Project.toml")
pop!(Base.DEPOT_PATH)
pkg"activate" # activate home project
@test Base.ACTIVE_PROJECT[] === nothing
end
Expand Down

0 comments on commit f647d70

Please sign in to comment.