Skip to content

Commit 1856c5a

Browse files
KristofferCKristofferC
authored andcommitted
allow loading extensions when a trigger is loaded from below the parent's load path (#49701)
also allow loading extensions of the active project (cherry picked from commit d55314c)
1 parent 21e90e0 commit 1856c5a

File tree

4 files changed

+103
-31
lines changed

4 files changed

+103
-31
lines changed

base/loading.jl

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,9 @@ function locate_package_env(pkg::PkgId, stopenv::Union{String, Nothing}=nothing)
413413
@goto done
414414
end
415415
end
416-
stopenv == env && @goto done
416+
if !(loading_extension || precompiling_extension)
417+
stopenv == env && @goto done
418+
end
417419
end
418420
else
419421
for env in load_path()
@@ -428,7 +430,9 @@ function locate_package_env(pkg::PkgId, stopenv::Union{String, Nothing}=nothing)
428430
path = entry_path(path, pkg.name)
429431
@goto done
430432
end
431-
stopenv == env && break
433+
if !(loading_extension || precompiling_extension)
434+
stopenv == env && break
435+
end
432436
end
433437
# Allow loading of stdlibs if the name/uuid are given
434438
# e.g. if they have been explicitly added to the project/manifest
@@ -619,6 +623,24 @@ function manifest_deps_get(env::String, where::PkgId, name::String)::Union{Nothi
619623
pkg_uuid = explicit_project_deps_get(project_file, name)
620624
return PkgId(pkg_uuid, name)
621625
end
626+
d = parsed_toml(project_file)
627+
exts = get(d, "extensions", nothing)::Union{Dict{String, Any}, Nothing}
628+
if exts !== nothing
629+
# Check if `where` is an extension of the project
630+
if where.name in keys(exts) && where.uuid == uuid5(proj.uuid, where.name)
631+
# Extensions can load weak deps...
632+
weakdeps = get(d, "weakdeps", nothing)::Union{Dict{String, Any}, Nothing}
633+
if weakdeps !== nothing
634+
wuuid = get(weakdeps, name, nothing)::Union{String, Nothing}
635+
if wuuid !== nothing
636+
return PkgId(UUID(wuuid), name)
637+
end
638+
end
639+
# ... and they can load same deps as the project itself
640+
mby_uuid = explicit_project_deps_get(project_file, name)
641+
mby_uuid === nothing || return PkgId(mby_uuid, name)
642+
end
643+
end
622644
# look for manifest file and `where` stanza
623645
return explicit_manifest_deps_get(project_file, where, name)
624646
elseif project_file
@@ -636,6 +658,8 @@ function manifest_uuid_path(env::String, pkg::PkgId)::Union{Nothing,String,Missi
636658
# if `pkg` matches the project, return the project itself
637659
return project_file_path(project_file)
638660
end
661+
mby_ext = project_file_ext_path(project_file, pkg.name)
662+
mby_ext === nothing || return mby_ext
639663
# look for manifest file and `where` stanza
640664
return explicit_manifest_uuid_path(project_file, pkg)
641665
elseif project_file
@@ -645,6 +669,25 @@ function manifest_uuid_path(env::String, pkg::PkgId)::Union{Nothing,String,Missi
645669
return nothing
646670
end
647671

672+
673+
function find_ext_path(project_path::String, extname::String)
674+
extfiledir = joinpath(project_path, "ext", extname, extname * ".jl")
675+
isfile(extfiledir) && return extfiledir
676+
return joinpath(project_path, "ext", extname * ".jl")
677+
end
678+
679+
function project_file_ext_path(project_file::String, name::String)
680+
d = parsed_toml(project_file)
681+
p = project_file_path(project_file)
682+
exts = get(d, "extensions", nothing)::Union{Dict{String, Any}, Nothing}
683+
if exts !== nothing
684+
if name in keys(exts)
685+
return find_ext_path(p, name)
686+
end
687+
end
688+
return nothing
689+
end
690+
648691
# find project file's top-level UUID entry (or nothing)
649692
function project_file_name_uuid(project_file::String, name::String)::PkgId
650693
d = parsed_toml(project_file)
@@ -876,9 +919,7 @@ function explicit_manifest_uuid_path(project_file::String, pkg::PkgId)::Union{No
876919
error("failed to find source of parent package: \"$name\"")
877920
end
878921
p = normpath(dirname(parent_path), "..")
879-
extfiledir = joinpath(p, "ext", pkg.name, pkg.name * ".jl")
880-
isfile(extfiledir) && return extfiledir
881-
return joinpath(p, "ext", pkg.name * ".jl")
922+
return find_ext_path(p, pkg.name)
882923
end
883924
end
884925
end
@@ -1126,6 +1167,18 @@ end
11261167
function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missing}
11271168
project_file = env_project_file(env)
11281169
if project_file isa String
1170+
# Look in project for extensions to insert
1171+
proj_pkg = project_file_name_uuid(project_file, pkg.name)
1172+
if pkg == proj_pkg
1173+
d_proj = parsed_toml(project_file)
1174+
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
1175+
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
1176+
extensions === nothing && return
1177+
weakdeps === nothing && return
1178+
return _insert_extension_triggers(pkg, extensions, weakdeps)
1179+
end
1180+
1181+
# Now look in manifest
11291182
manifest_file = project_file_manifest_path(project_file)
11301183
manifest_file === nothing && return
11311184
d = get_deps(parsed_toml(manifest_file))
@@ -1190,6 +1243,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, <:An
11901243
end
11911244

11921245
loading_extension::Bool = false
1246+
precompiling_extension::Bool = false
11931247
function run_extension_callbacks(extid::ExtensionId)
11941248
assert_havelock(require_lock)
11951249
succeeded = try
@@ -1217,30 +1271,8 @@ function run_extension_callbacks(pkgid::PkgId)
12171271
extids === nothing && return
12181272
for extid in extids
12191273
if extid.ntriggers > 0
1220-
# It is possible that pkgid was loaded in an environment
1221-
# below the one of the parent. This will cause a load failure when the
1222-
# pkg ext tries to load the triggers. Therefore, check this first
1223-
# before loading the pkg ext.
1224-
pkgenv = identify_package_env(extid.id, pkgid.name)
1225-
ext_not_allowed_load = false
1226-
if pkgenv === nothing
1227-
ext_not_allowed_load = true
1228-
else
1229-
pkg, env = pkgenv
1230-
path = locate_package(pkg, env)
1231-
if path === nothing
1232-
ext_not_allowed_load = true
1233-
end
1234-
end
1235-
if ext_not_allowed_load
1236-
@debug "Extension $(extid.id.name) of $(extid.parentid.name) will not be loaded \
1237-
since $(pkgid.name) loaded in environment lower in load path"
1238-
# indicate extid is expected to fail
1239-
extid.ntriggers *= -1
1240-
else
1241-
# indicate pkgid is loaded
1242-
extid.ntriggers -= 1
1243-
end
1274+
# indicate pkgid is loaded
1275+
extid.ntriggers -= 1
12441276
end
12451277
if extid.ntriggers < 0
12461278
# indicate pkgid is loaded
@@ -2066,6 +2098,7 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
20662098
# write data over stdin to avoid the (unlikely) case of exceeding max command line size
20672099
write(io.in, """
20682100
empty!(Base.EXT_DORMITORY) # If we have a custom sysimage with `EXT_DORMITORY` prepopulated
2101+
Base.precompiling_extension = $(loading_extension)
20692102
Base.include_package_for_output($(pkg_str(pkg)), $(repr(abspath(input))), $(repr(depot_path)), $(repr(dl_load_path)),
20702103
$(repr(load_path)), $deps, $(repr(source_path(nothing))))
20712104
""")

test/loading.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,8 +1053,6 @@ end
10531053
envs = [joinpath(@__DIR__, "project", "Extensions", "EnvWithHasExtensionsv2"), joinpath(@__DIR__, "project", "Extensions", "EnvWithHasExtensions")]
10541054
cmd = addenv(```$(Base.julia_cmd()) --startup-file=no -e '
10551055
begin
1056-
1057-
10581056
push!(empty!(DEPOT_PATH), '$(repr(depot_path))')
10591057
using HasExtensions
10601058
using ExtDep
@@ -1064,6 +1062,22 @@ end
10641062
'
10651063
```, "JULIA_LOAD_PATH" => join(envs, sep))
10661064
@test success(cmd)
1065+
1066+
test_ext_proj = """
1067+
begin
1068+
using HasExtensions
1069+
using ExtDep
1070+
Base.get_extension(HasExtensions, :Extension) isa Module || error("expected extension to load")
1071+
using ExtDep2
1072+
Base.get_extension(HasExtensions, :ExtensionFolder) isa Module || error("expected extension to load")
1073+
end
1074+
"""
1075+
for compile in (`--compiled-modules=no`, ``)
1076+
cmd_proj_ext = `$(Base.julia_cmd()) $compile --startup-file=no -e $test_ext_proj`
1077+
proj = joinpath(@__DIR__, "project", "Extensions")
1078+
cmd_proj_ext = addenv(cmd_proj_ext, "JULIA_LOAD_PATH" => join([joinpath(proj, "HasExtensions.jl"), joinpath(proj, "EnvWithDeps")], sep))
1079+
run(cmd_proj_ext)
1080+
end
10671081
finally
10681082
try
10691083
rm(depot_path, force=true, recursive=true)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This file is machine-generated - editing it directly is not advised
2+
3+
julia_version = "1.9.0-rc3"
4+
manifest_format = "2.0"
5+
project_hash = "ec25ff8df3a5e2212a173c3de2c7d716cc47cd36"
6+
7+
[[deps.ExtDep]]
8+
deps = ["SomePackage"]
9+
path = "../ExtDep.jl"
10+
uuid = "fa069be4-f60b-4d4c-8b95-f8008775090c"
11+
version = "0.1.0"
12+
13+
[[deps.ExtDep2]]
14+
path = "../ExtDep2"
15+
uuid = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
16+
version = "0.1.0"
17+
18+
[[deps.SomePackage]]
19+
path = "../SomePackage"
20+
uuid = "678608ae-7bb3-42c7-98b1-82102067a3d8"
21+
version = "0.1.0"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[deps]
2+
ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c"
3+
ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
4+
SomePackage = "678608ae-7bb3-42c7-98b1-82102067a3d8"

0 commit comments

Comments
 (0)