Skip to content

Commit

Permalink
make dependencies of extensions be found in implicit environments (#5…
Browse files Browse the repository at this point in the history
…3314)

Alternative to #53293

This does kind of the same thing but it does not rely on `EXT_PRIMED` to
identify extensions which I think is a better idea since we don't really
want code lookup to depend on the state of Julia itself imo.

Fixes #53264

-----------------------

Co-authored by: Mark Kittisopikul <`markkitti@fosstodon.org`>
  • Loading branch information
KristofferC committed Feb 14, 2024
1 parent 52006ae commit a19fbac
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 9 deletions.
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

0 comments on commit a19fbac

Please sign in to comment.