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

make dependencies of extensions be found in implicit environments #53314

Merged
merged 2 commits into from
Feb 14, 2024
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
64 changes: 55 additions & 9 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -776,15 +776,30 @@ end
function entry_point_and_project_file(dir::String, name::String)::Union{Tuple{Nothing,Nothing},Tuple{String,Nothing},Tuple{String,String}}
path = normpath(joinpath(dir, "$name.jl"))
isfile_casesensitive(path) && return path, nothing
dir = joinpath(dir, name)
path, project_file = entry_point_and_project_file_inside(dir, name)
dir_name = joinpath(dir, name)
path, project_file = entry_point_and_project_file_inside(dir_name, name)
path === nothing || return path, project_file
dir = dir * ".jl"
path, project_file = entry_point_and_project_file_inside(dir, name)
dir_jl = dir_name * ".jl"
path, project_file = entry_point_and_project_file_inside(dir_jl, name)
path === nothing || return path, project_file
return nothing, nothing
end

# Find the project file for the extension `ext` in the implicit env `dir``
function implicit_env_project_file_extension(dir::String, ext::PkgId)
for pkg in readdir(dir; join=true)
project_file = env_project_file(pkg)
project_file isa String || continue
proj = project_file_name_uuid(project_file, "")
uuid5(proj.uuid, ext.name) == ext.uuid || continue
path = project_file_ext_path(project_file, ext.name)
if path !== nothing
return path, project_file
end
end
return nothing, nothing
end

# given a path and a name, return the entry point
function entry_path(path::String, name::String)::Union{Nothing,String}
isfile_casesensitive(path) && return normpath(path)
Expand All @@ -796,11 +811,12 @@ end
## explicit project & manifest API ##

# find project file root or deps `name => uuid` mapping
# `ext` is the name of the extension if `name` is loaded from one
# return `nothing` if `name` is not found
function explicit_project_deps_get(project_file::String, name::String)::Union{Nothing,UUID}
function explicit_project_deps_get(project_file::String, name::String, ext::Union{String,Nothing}=nothing)::Union{Nothing,UUID}
d = parsed_toml(project_file)
root_uuid = dummy_uuid(project_file)
if get(d, "name", nothing)::Union{String, Nothing} === name
root_uuid = dummy_uuid(project_file)
uuid = get(d, "uuid", nothing)::Union{String, Nothing}
return uuid === nothing ? root_uuid : UUID(uuid)
end
Expand All @@ -809,6 +825,19 @@ function explicit_project_deps_get(project_file::String, name::String)::Union{No
uuid = get(deps, name, nothing)::Union{String, Nothing}
uuid === nothing || return UUID(uuid)
end
if ext !== nothing
extensions = get(d, "extensions", nothing)
extensions === nothing && return nothing
ext_data = get(extensions, ext, nothing)
ext_data === nothing && return nothing
if (ext_data isa String && name == ext_data) || (ext_data isa Vector{String} && name in ext_data)
weakdeps = get(d, "weakdeps", nothing)::Union{Dict{String, Any}, Nothing}
weakdeps === nothing && return nothing
wuuid = get(weakdeps, name, nothing)::Union{String, Nothing}
wuuid === nothing && return nothing
return UUID(wuuid)
end
end
return nothing
end

Expand Down Expand Up @@ -996,11 +1025,28 @@ end
function implicit_manifest_deps_get(dir::String, where::PkgId, name::String)::Union{Nothing,PkgId}
@assert where.uuid !== nothing
project_file = entry_point_and_project_file(dir, where.name)[2]
project_file === nothing && return nothing # a project file is mandatory for a package with a uuid
if project_file === nothing
# `where` could be an extension
project_file = implicit_env_project_file_extension(dir, where)[2]
project_file === nothing && return nothing
end
proj = project_file_name_uuid(project_file, where.name)
proj == where || return nothing # verify that this is the correct project file
ext = nothing
if proj !== where
# `where` could be an extension in `proj`
d = parsed_toml(project_file)
exts = get(d, "extensions", nothing)::Union{Dict{String, Any}, Nothing}
if exts !== nothing && where.name in keys(exts)
if where.uuid !== uuid5(proj.uuid, where.name)
return nothing
end
ext = where.name
else
return nothing
end
end
# this is the correct project, so stop searching here
pkg_uuid = explicit_project_deps_get(project_file, name)
pkg_uuid = explicit_project_deps_get(project_file, name, ext)
return PkgId(pkg_uuid, name)
end

Expand Down
12 changes: 12 additions & 0 deletions test/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,18 @@ end
cmd = `$(Base.julia_cmd()) --startup-file=no -e $sysimg_ext_test_code`
cmd = addenv(cmd, "JULIA_LOAD_PATH" => join([proj, "@stdlib"], sep))
run(cmd)


# Extensions in implicit environments
old_load_path = copy(LOAD_PATH)
try
empty!(LOAD_PATH)
push!(LOAD_PATH, joinpath(@__DIR__, "project", "Extensions", "ImplicitEnv"))
pkgid_B = Base.PkgId(Base.uuid5(Base.identify_package("A").uuid, "BExt"), "BExt")
@test Base.identify_package(pkgid_B, "B") isa Base.PkgId
finally
copy!(LOAD_PATH, old_load_path)
end
finally
try
rm(depot_path, force=true, recursive=true)
Expand Down
9 changes: 9 additions & 0 deletions test/project/Extensions/ImplicitEnv/A/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name = "A"
uuid = "299a509a-2181-4868-8714-15151945d902"
version = "0.1.0"

[weakdeps]
B = "c2c18cb0-3543-497c-ac2a-523c527589e5"

[extensions]
BExt = "B"
3 changes: 3 additions & 0 deletions test/project/Extensions/ImplicitEnv/A/ext/BExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module BExt

end
5 changes: 5 additions & 0 deletions test/project/Extensions/ImplicitEnv/A/src/A.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module A

greet() = print("Hello World!")

end # module A
3 changes: 3 additions & 0 deletions test/project/Extensions/ImplicitEnv/B/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "B"
uuid = "c2c18cb0-3543-497c-ac2a-523c527589e5"
version = "0.1.0"
5 changes: 5 additions & 0 deletions test/project/Extensions/ImplicitEnv/B/src/B.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module B

greet() = print("Hello World!")

end # module B