diff --git a/stdlib/Pkg/docs/src/index.md b/stdlib/Pkg/docs/src/index.md index e71fa1e9976e0a..571f4f157a81a0 100644 --- a/stdlib/Pkg/docs/src/index.md +++ b/stdlib/Pkg/docs/src/index.md @@ -359,6 +359,7 @@ Note the info message saying that it is using the existing path. This means that an already developed package. If `dev` is used on a local path, that path to that package is recorded and used when loading that package. +The path will be recorded relative to the project file, unless it is given as an absolute path. To stop tracking a path and use the registered version again, use `free` diff --git a/stdlib/Pkg/src/Operations.jl b/stdlib/Pkg/src/Operations.jl index 6d6b6aaf7ce619..547cebdc75842f 100644 --- a/stdlib/Pkg/src/Operations.jl +++ b/stdlib/Pkg/src/Operations.jl @@ -94,7 +94,7 @@ function collect_fixed!(ctx::Context, pkgs::Vector{PackageSpec}, uuid_to_name::D @assert pkg.repo !== nothing && pkg.repo.git_tree_sha1 !== nothing path = find_installed(pkg.name, pkg.uuid, pkg.repo.git_tree_sha1) elseif info !== nothing && haskey(info, "path") - pkg.path = project_rel_path(ctx, info["path"]) + pkg.path = info["path"] path = pkg.path elseif info !== nothing && haskey(info, "repo-url") path = find_installed(pkg.name, pkg.uuid, SHA1(info["git-tree-sha1"])) @@ -678,7 +678,7 @@ function update_manifest(ctx::Context, pkg::PackageSpec, hash::Union{SHA1, Nothi if !is_stdlib info["version"] = string(version) hash == nothing ? delete!(info, "git-tree-sha1") : (info["git-tree-sha1"] = string(hash)) - path == nothing ? delete!(info, "path") : (info["path"] = relative_project_path_if_in_project(ctx, path)) + path == nothing ? delete!(info, "path") : (info["path"] = path) if special_action == PKGSPEC_DEVELOPED delete!(info, "pinned") delete!(info, "repo-url") diff --git a/stdlib/Pkg/src/REPLMode.jl b/stdlib/Pkg/src/REPLMode.jl index 5d5337edc1d9b7..a7df17f52b8a04 100644 --- a/stdlib/Pkg/src/REPLMode.jl +++ b/stdlib/Pkg/src/REPLMode.jl @@ -135,7 +135,7 @@ end function parse_package(word::AbstractString; add_or_develop=false)::PackageSpec word = replace(word, "~" => homedir()) if add_or_develop && casesensitive_isdir(word) - return PackageSpec(Types.GitRepo(abspath(word))) + return PackageSpec(Types.GitRepo(word)) elseif occursin(uuid_re, word) return PackageSpec(UUID(word)) elseif occursin(name_re, word) @@ -840,7 +840,7 @@ function do_activate!(env::Union{EnvCache,Nothing}, tokens::Vector{Token}) if env !== nothing && haskey(env.project["deps"], path) uuid = UUID(env.project["deps"][path]) info = manifest_info(env, uuid) - devpath = haskey(info, "path") ? info["path"] : nothing + devpath = haskey(info, "path") ? joinpath(dirname(env.project_file), info["path"]) : nothing end # `pkg> activate path` does the following # 1. if path exists, activate that diff --git a/stdlib/Pkg/src/Types.jl b/stdlib/Pkg/src/Types.jl index 80276b32a5e818..0a247849650d70 100644 --- a/stdlib/Pkg/src/Types.jl +++ b/stdlib/Pkg/src/Types.jl @@ -493,7 +493,15 @@ function handle_repos_develop!(ctx::Context, pkgs::AbstractVector{PackageSpec}, if isdir_windows_workaround(pkg.repo.url) # Developing a local package, just point `pkg.path` to it - pkg.path = abspath(pkg.repo.url) + if isabspath(pkg.repo.url) + # absolute paths should stay absolute + pkg.path = pkg.repo.url + else + # Relative paths are given relative pwd() so we + # translate that to be relative the project instead. + # `realpath` is needed to expand symlinks before taking the relative path. + pkg.path = relpath(realpath(abspath(pkg.repo.url)), realpath(dirname(ctx.env.project_file))) + end folder_already_downloaded = true project_path = pkg.repo.url parse_package!(ctx, pkg, project_path) @@ -559,7 +567,9 @@ function handle_repos_develop!(ctx::Context, pkgs::AbstractVector{PackageSpec}, mv(project_path, dev_pkg_path; force=true) push!(new_uuids, pkg.uuid) end - pkg.path = dev_pkg_path + # Save the path as relative if the location is inside the project + # (e.g. from `dev --local`), otherwise put in the absolute path. + pkg.path = Pkg.Operations.relative_project_path_if_in_project(ctx, dev_pkg_path) end @assert pkg.path != nothing end diff --git a/stdlib/Pkg/test/repl.jl b/stdlib/Pkg/test/repl.jl index ed73173397f26e..128ae36c973b30 100644 --- a/stdlib/Pkg/test/repl.jl +++ b/stdlib/Pkg/test/repl.jl @@ -226,6 +226,10 @@ temp_pkg_dir() do project_path; cd(project_path) do pkg"develop ../SubModule2" @test Pkg.installed()["SubModule1"] == v"0.1.0" @test Pkg.installed()["SubModule2"] == v"0.1.0" + # make sure paths to SubModule1 and SubModule2 are relative + manifest = Pkg.Types.Context().env.manifest + @test manifest["SubModule1"][1]["path"] == "SubModule1" + @test manifest["SubModule2"][1]["path"] == "SubModule2" end end cp("HelloWorld", joinpath(other_dir, "HelloWorld")) @@ -266,6 +270,26 @@ cd(mktempdir()) do pkg"add Example" # non-deved deps should not be activated 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") +end + +# test relative dev paths (#490) +cd(mktempdir()) do + pkg"generate HelloWorld" + cd("HelloWorld") + pkg"generate SubModule" + cd(mkdir("tests")) + pkg"activate ." + pkg"develop .." # HelloWorld + pkg"develop ../SubModule" + @test Pkg.installed()["HelloWorld"] == v"0.1.0" + @test Pkg.installed()["SubModule"] == v"0.1.0" + manifest = Pkg.Types.Context().env.manifest + @test manifest["HelloWorld"][1]["path"] == ".." + @test manifest["SubModule"][1]["path"] == joinpath("..", "SubModule") end # develop with --shared and --local @@ -273,7 +297,7 @@ using Pkg.Types: manifest_info, EnvCache cd(mktempdir()) do uuid = UUID("7876af07-990d-54b4-ab0e-23690620f79a") # Example pkg"activate ." - pkg"develop Example" # test --shared default + pkg"develop Example" # test default @test manifest_info(EnvCache(), uuid)["path"] == joinpath(Pkg.devdir(), "Example") pkg"develop --shared Example" @test manifest_info(EnvCache(), uuid)["path"] == joinpath(Pkg.devdir(), "Example")