Skip to content

Commit d55314c

Browse files
authored
allow loading extensions when a trigger is loaded from below the parent's load path (#49701)
also allow loading extensions of the active project
1 parent c6fc12c commit d55314c

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
@@ -1160,6 +1201,18 @@ end
11601201
function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missing}
11611202
project_file = env_project_file(env)
11621203
if project_file isa String
1204+
# Look in project for extensions to insert
1205+
proj_pkg = project_file_name_uuid(project_file, pkg.name)
1206+
if pkg == proj_pkg
1207+
d_proj = parsed_toml(project_file)
1208+
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
1209+
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
1210+
extensions === nothing && return
1211+
weakdeps === nothing && return
1212+
return _insert_extension_triggers(pkg, extensions, weakdeps)
1213+
end
1214+
1215+
# Now look in manifest
11631216
manifest_file = project_file_manifest_path(project_file)
11641217
manifest_file === nothing && return
11651218
d = get_deps(parsed_toml(manifest_file))
@@ -1224,6 +1277,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, <:An
12241277
end
12251278

12261279
loading_extension::Bool = false
1280+
precompiling_extension::Bool = false
12271281
function run_extension_callbacks(extid::ExtensionId)
12281282
assert_havelock(require_lock)
12291283
succeeded = try
@@ -1251,30 +1305,8 @@ function run_extension_callbacks(pkgid::PkgId)
12511305
extids === nothing && return
12521306
for extid in extids
12531307
if extid.ntriggers > 0
1254-
# It is possible that pkgid was loaded in an environment
1255-
# below the one of the parent. This will cause a load failure when the
1256-
# pkg ext tries to load the triggers. Therefore, check this first
1257-
# before loading the pkg ext.
1258-
pkgenv = identify_package_env(extid.id, pkgid.name)
1259-
ext_not_allowed_load = false
1260-
if pkgenv === nothing
1261-
ext_not_allowed_load = true
1262-
else
1263-
pkg, env = pkgenv
1264-
path = locate_package(pkg, env)
1265-
if path === nothing
1266-
ext_not_allowed_load = true
1267-
end
1268-
end
1269-
if ext_not_allowed_load
1270-
@debug "Extension $(extid.id.name) of $(extid.parentid.name) will not be loaded \
1271-
since $(pkgid.name) loaded in environment lower in load path"
1272-
# indicate extid is expected to fail
1273-
extid.ntriggers *= -1
1274-
else
1275-
# indicate pkgid is loaded
1276-
extid.ntriggers -= 1
1277-
end
1308+
# indicate pkgid is loaded
1309+
extid.ntriggers -= 1
12781310
end
12791311
if extid.ntriggers < 0
12801312
# indicate pkgid is loaded
@@ -2148,6 +2180,7 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
21482180
# write data over stdin to avoid the (unlikely) case of exceeding max command line size
21492181
write(io.in, """
21502182
empty!(Base.EXT_DORMITORY) # If we have a custom sysimage with `EXT_DORMITORY` prepopulated
2183+
Base.precompiling_extension = $(loading_extension)
21512184
Base.include_package_for_output($(pkg_str(pkg)), $(repr(abspath(input))), $(repr(depot_path)), $(repr(dl_load_path)),
21522185
$(repr(load_path)), $deps, $(repr(source_path(nothing))))
21532186
""")

test/loading.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,8 +1056,6 @@ end
10561056
envs = [joinpath(@__DIR__, "project", "Extensions", "EnvWithHasExtensionsv2"), joinpath(@__DIR__, "project", "Extensions", "EnvWithHasExtensions")]
10571057
cmd = addenv(```$(Base.julia_cmd()) --startup-file=no -e '
10581058
begin
1059-
1060-
10611059
push!(empty!(DEPOT_PATH), '$(repr(depot_path))')
10621060
using HasExtensions
10631061
using ExtDep
@@ -1067,6 +1065,22 @@ end
10671065
'
10681066
```, "JULIA_LOAD_PATH" => join(envs, sep))
10691067
@test success(cmd)
1068+
1069+
test_ext_proj = """
1070+
begin
1071+
using HasExtensions
1072+
using ExtDep
1073+
Base.get_extension(HasExtensions, :Extension) isa Module || error("expected extension to load")
1074+
using ExtDep2
1075+
Base.get_extension(HasExtensions, :ExtensionFolder) isa Module || error("expected extension to load")
1076+
end
1077+
"""
1078+
for compile in (`--compiled-modules=no`, ``)
1079+
cmd_proj_ext = `$(Base.julia_cmd()) $compile --startup-file=no -e $test_ext_proj`
1080+
proj = joinpath(@__DIR__, "project", "Extensions")
1081+
cmd_proj_ext = addenv(cmd_proj_ext, "JULIA_LOAD_PATH" => join([joinpath(proj, "HasExtensions.jl"), joinpath(proj, "EnvWithDeps")], sep))
1082+
run(cmd_proj_ext)
1083+
end
10701084
finally
10711085
try
10721086
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)