Skip to content

Commit 396b557

Browse files
topolarityKristofferCKristofferC
authored
[backports-release-1.10] allow extensions to trigger from packages in [deps] (#54009) (#56383)
This is a backport of #54009 --------- Co-authored-by: Kristoffer Carlsson <kcarlsson89@gmail.com> Co-authored-by: KristofferC <kristoffer.carlsson@juliacomputing.com>
1 parent bb86259 commit 396b557

File tree

12 files changed

+108
-50
lines changed

12 files changed

+108
-50
lines changed

base/loading.jl

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -878,14 +878,14 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St
878878
entry = entry::Dict{String, Any}
879879
uuid = get(entry, "uuid", nothing)::Union{String, Nothing}
880880
uuid === nothing && continue
881+
# deps is either a list of names (deps = ["DepA", "DepB"]) or
882+
# a table of entries (deps = {"DepA" = "6ea...", "DepB" = "55d..."}
883+
deps = get(entry, "deps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
881884
if UUID(uuid) === where.uuid
882885
found_where = true
883-
# deps is either a list of names (deps = ["DepA", "DepB"]) or
884-
# a table of entries (deps = {"DepA" = "6ea...", "DepB" = "55d..."}
885-
deps = get(entry, "deps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
886886
if deps isa Vector{String}
887887
found_name = name in deps
888-
break
888+
found_name && @goto done
889889
elseif deps isa Dict{String, Any}
890890
deps = deps::Dict{String, Any}
891891
for (dep, uuid) in deps
@@ -904,30 +904,33 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St
904904
return PkgId(UUID(uuid), name)
905905
end
906906
exts = extensions[where.name]::Union{String, Vector{String}}
907+
weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
907908
if (exts isa String && name == exts) || (exts isa Vector{String} && name in exts)
908-
weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
909-
if weakdeps !== nothing
910-
if weakdeps isa Vector{String}
911-
found_name = name in weakdeps
912-
break
913-
elseif weakdeps isa Dict{String, Any}
914-
weakdeps = weakdeps::Dict{String, Any}
915-
for (dep, uuid) in weakdeps
916-
uuid::String
917-
if dep === name
918-
return PkgId(UUID(uuid), name)
909+
for deps′ in [weakdeps, deps]
910+
if deps′ !== nothing
911+
if deps′ isa Vector{String}
912+
found_name = name in deps′
913+
found_name && @goto done
914+
elseif deps′ isa Dict{String, Any}
915+
deps′ = deps′::Dict{String, Any}
916+
for (dep, uuid) in deps′
917+
uuid::String
918+
if dep === name
919+
return PkgId(UUID(uuid), name)
920+
end
921+
end
919922
end
920923
end
921924
end
922925
end
923-
end
924926
# `name` is not an ext, do standard lookup as if this was the parent
925927
return identify_package(PkgId(UUID(uuid), dep_name), name)
926928
end
927929
end
928930
end
929931
end
930932
end
933+
@label done
931934
found_where || return nothing
932935
found_name || return PkgId(name)
933936
# Only reach here if deps was not a dict which mean we have a unique name for the dep
@@ -1262,12 +1265,13 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
12621265
proj_pkg = project_file_name_uuid(project_file, pkg.name)
12631266
if pkg == proj_pkg
12641267
d_proj = parsed_toml(project_file)
1265-
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
12661268
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
12671269
extensions === nothing && return
1268-
weakdeps === nothing && return
1269-
if weakdeps isa Dict{String, Any}
1270-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1270+
weakdeps = get(Dict{String, Any}, d_proj, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
1271+
deps = get(Dict{String, Any}, d_proj, "deps")::Union{Vector{String}, Dict{String,Any}}
1272+
if weakdeps isa Dict{String,Any} && deps isa Dict{String,Any}
1273+
total_deps = merge(weakdeps, deps)
1274+
return _insert_extension_triggers(pkg, extensions, total_deps)
12711275
end
12721276
end
12731277

@@ -1282,35 +1286,43 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
12821286
uuid = get(entry, "uuid", nothing)::Union{String, Nothing}
12831287
uuid === nothing && continue
12841288
if UUID(uuid) == pkg.uuid
1285-
weakdeps = get(entry, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
12861289
extensions = get(entry, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
12871290
extensions === nothing && return
1288-
weakdeps === nothing && return
1289-
if weakdeps isa Dict{String, Any}
1290-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1291+
weakdeps = get(Dict{String, Any}, entry, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
1292+
deps = get(Dict{String, Any}, entry, "deps")::Union{Vector{String}, Dict{String,Any}}
1293+
1294+
function expand_deps_list(deps′::Vector{String})
1295+
deps′_expanded = Dict{String, Any}()
1296+
for (dep_name, entries) in d
1297+
dep_name in deps′ || continue
1298+
entries::Vector{Any}
1299+
if length(entries) != 1
1300+
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
1301+
end
1302+
entry = first(entries)::Dict{String, Any}
1303+
uuid = entry["uuid"]::String
1304+
deps′_expanded[dep_name] = uuid
1305+
end
1306+
return deps′_expanded
12911307
end
12921308

1293-
d_weakdeps = Dict{String, Any}()
1294-
for (dep_name, entries) in d
1295-
dep_name in weakdeps || continue
1296-
entries::Vector{Any}
1297-
if length(entries) != 1
1298-
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
1299-
end
1300-
entry = first(entries)::Dict{String, Any}
1301-
uuid = entry["uuid"]::String
1302-
d_weakdeps[dep_name] = uuid
1309+
if weakdeps isa Vector{String}
1310+
weakdeps = expand_deps_list(weakdeps)
13031311
end
1304-
@assert length(d_weakdeps) == length(weakdeps)
1305-
return _insert_extension_triggers(pkg, extensions, d_weakdeps)
1312+
if deps isa Vector{String}
1313+
deps = expand_deps_list(deps)
1314+
end
1315+
1316+
total_deps = merge(weakdeps, deps)
1317+
return _insert_extension_triggers(pkg, extensions, total_deps)
13061318
end
13071319
end
13081320
end
13091321
end
13101322
return nothing
13111323
end
13121324

1313-
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, weakdeps::Dict{String, Any})
1325+
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, totaldeps::Dict{String, Any})
13141326
for (ext, triggers) in extensions
13151327
triggers = triggers::Union{String, Vector{String}}
13161328
triggers isa String && (triggers = [triggers])
@@ -1324,7 +1336,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}
13241336
push!(trigger1, gid)
13251337
for trigger in triggers
13261338
# TODO: Better error message if this lookup fails?
1327-
uuid_trigger = UUID(weakdeps[trigger]::String)
1339+
uuid_trigger = UUID(totaldeps[trigger]::String)
13281340
trigger_id = PkgId(uuid_trigger, trigger)
13291341
if !haskey(Base.loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
13301342
trigger1 = get!(Vector{ExtensionId}, EXT_DORMITORY, trigger_id)

doc/src/manual/code-loading.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ Since the primary environment is typically the environment of a project you're w
351351

352352
### [Package Extensions](@id man-extensions)
353353

354-
A package "extension" is a module that is automatically loaded when a specified set of other packages (its "extension dependencies") are loaded in the current Julia session. Extensions are defined under the `[extensions]` section in the project file. The extension dependencies of an extension are a subset of those packages listed under the `[weakdeps]` section of the project file. Those packages can have compat entries like other packages.
354+
A package "extension" is a module that is automatically loaded when a specified set of other packages (its "triggers") are loaded in the current Julia session. Extensions are defined under the `[extensions]` section in the project file. The triggers of an extension are a subset of those packages listed under the `[weakdeps]` (and possibly, but uncommonly the `[deps]`) section of the project file. Those packages can have compat entries like other packages.
355355

356356
```toml
357357
name = "MyPackage"
@@ -371,27 +371,27 @@ FooExt = "ExtDep"
371371
```
372372

373373
The keys under `extensions` are the names of the extensions.
374-
They are loaded when all the packages on the right hand side (the extension dependencies) of that extension are loaded.
375-
If an extension only has one extension dependency the list of extension dependencies can be written as just a string for brevity.
374+
They are loaded when all the packages on the right hand side (the triggers) of that extension are loaded.
375+
If an extension only has one trigger the list of triggers can be written as just a string for brevity.
376376
The location for the entry point of the extension is either in `ext/FooExt.jl` or `ext/FooExt/FooExt.jl` for
377377
extension `FooExt`.
378378
The content of an extension is often structured as:
379379

380380
```
381381
module FooExt
382382
383-
# Load main package and extension dependencies
383+
# Load main package and triggers
384384
using MyPackage, ExtDep
385385
386-
# Extend functionality in main package with types from the extension dependencies
386+
# Extend functionality in main package with types from the triggers
387387
MyPackage.func(x::ExtDep.SomeStruct) = ...
388388
389389
end
390390
```
391391

392392
When a package with extensions is added to an environment, the `weakdeps` and `extensions` sections
393393
are stored in the manifest file in the section for that package. The dependency lookup rules for
394-
a package are the same as for its "parent" except that the listed extension dependencies are also considered as
394+
a package are the same as for its "parent" except that the listed triggers are also considered as
395395
dependencies.
396396

397397
### [Package/Environment Preferences](@id preferences)

test/loading.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,9 @@ end
10401040
using ExtDep2
10411041
$ew using ExtDep2
10421042
$ew HasExtensions.ext_folder_loaded || error("ext_folder_loaded not set")
1043+
using ExtDep3
1044+
$ew using ExtDep3
1045+
$ew HasExtensions.ext_dep_loaded || error("ext_dep_loaded not set")
10431046
end
10441047
"""
10451048
return `$(Base.julia_cmd()) $compile --startup-file=no -e $cmd`
@@ -1088,6 +1091,8 @@ end
10881091
test_ext(HasExtensions, :Extension)
10891092
using ExtDep2
10901093
test_ext(HasExtensions, :ExtensionFolder)
1094+
using ExtDep3
1095+
test_ext(HasExtensions, :ExtensionDep)
10911096
end
10921097
"""
10931098
for compile in (`--compiled-modules=no`, ``)

test/project/Extensions/EnvWithHasExtensions/Manifest.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is machine-generated - editing it directly is not advised
22

3-
julia_version = "1.9.0-beta4"
3+
julia_version = "1.10.6"
44
manifest_format = "2.0"
55
project_hash = "caa716752e6dff3d77c3de929ebbb5d2024d04ef"
66

@@ -10,13 +10,20 @@ path = "../ExtDep.jl"
1010
uuid = "fa069be4-f60b-4d4c-8b95-f8008775090c"
1111
version = "0.1.0"
1212

13+
[[deps.ExtDep3]]
14+
path = "../ExtDep3.jl"
15+
uuid = "a5541f1e-a556-4fdc-af15-097880d743a1"
16+
version = "0.1.0"
17+
1318
[[deps.HasExtensions]]
19+
deps = ["ExtDep3"]
1420
path = "../HasExtensions.jl"
1521
uuid = "4d3288b3-3afc-4bb6-85f3-489fffe514c8"
1622
version = "0.1.0"
1723

1824
[deps.HasExtensions.extensions]
1925
Extension = "ExtDep"
26+
ExtensionDep = "ExtDep3"
2027
ExtensionFolder = ["ExtDep", "ExtDep2"]
2128

2229
[deps.HasExtensions.weakdeps]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name = "ExtDep3"
2+
uuid = "a5541f1e-a556-4fdc-af15-097880d743a1"
3+
version = "0.1.0"
4+
authors = ["Kristoffer <kcarlsson89@gmail.com>"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module ExtDep3
2+
3+
greet() = print("Hello World!")
4+
5+
end # module ExtDep3

test/project/Extensions/HasDepWithExtensions.jl/Manifest.toml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# This file is machine-generated - editing it directly is not advised
22

3-
julia_version = "1.10.0-DEV"
3+
julia_version = "1.10.6"
44
manifest_format = "2.0"
5-
project_hash = "d523b3401f72a1ed34b7b43749fd2655c6b78542"
5+
project_hash = "eed4f16fdd2e22799229e480394c255a569eb19c"
66

77
[[deps.ExtDep]]
88
deps = ["SomePackage"]
@@ -15,14 +15,21 @@ path = "../ExtDep2"
1515
uuid = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
1616
version = "0.1.0"
1717

18+
[[deps.ExtDep3]]
19+
path = "../ExtDep3.jl"
20+
uuid = "a5541f1e-a556-4fdc-af15-097880d743a1"
21+
version = "0.1.0"
22+
1823
[[deps.HasExtensions]]
24+
deps = ["ExtDep3"]
1925
path = "../HasExtensions.jl"
2026
uuid = "4d3288b3-3afc-4bb6-85f3-489fffe514c8"
2127
version = "0.1.0"
2228
weakdeps = ["ExtDep", "ExtDep2"]
2329

2430
[deps.HasExtensions.extensions]
2531
Extension = "ExtDep"
32+
ExtensionDep = "ExtDep3"
2633
ExtensionFolder = ["ExtDep", "ExtDep2"]
2734

2835
[[deps.SomePackage]]

test/project/Extensions/HasDepWithExtensions.jl/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ version = "0.1.0"
55
[deps]
66
ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c"
77
ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
8+
ExtDep3 = "a5541f1e-a556-4fdc-af15-097880d743a1"
89
HasExtensions = "4d3288b3-3afc-4bb6-85f3-489fffe514c8"
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# This file is machine-generated - editing it directly is not advised
22

3-
julia_version = "1.10.0-DEV"
3+
julia_version = "1.10.6"
44
manifest_format = "2.0"
5-
project_hash = "c87947f1f1f070eea848950c304d668a112dec3d"
5+
project_hash = "0948477fbecf27074f82e46d6fe927b1e66ada5b"
66

7-
[deps]
7+
[[deps.ExtDep3]]
8+
path = "../ExtDep3.jl"
9+
uuid = "a5541f1e-a556-4fdc-af15-097880d743a1"
10+
version = "0.1.0"

test/project/Extensions/HasExtensions.jl/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ name = "HasExtensions"
22
uuid = "4d3288b3-3afc-4bb6-85f3-489fffe514c8"
33
version = "0.1.0"
44

5+
[deps]
6+
ExtDep3 = "a5541f1e-a556-4fdc-af15-097880d743a1"
7+
58
[weakdeps]
69
ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c"
710
ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
811

912
[extensions]
1013
Extension = "ExtDep"
14+
ExtensionDep = "ExtDep3"
1115
ExtensionFolder = ["ExtDep", "ExtDep2"]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module ExtensionDep
2+
3+
using HasExtensions, ExtDep3
4+
5+
function __init__()
6+
HasExtensions.ext_dep_loaded = true
7+
end
8+
9+
end

test/project/Extensions/HasExtensions.jl/src/HasExtensions.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ foo(::HasExtensionsStruct) = 1
66

77
ext_loaded = false
88
ext_folder_loaded = false
9+
ext_dep_loaded = false
910

1011
end # module

0 commit comments

Comments
 (0)