Skip to content

Commit ca603a1

Browse files
KristofferCtopolarity
authored andcommitted
[backports-release-1.10] allow extensions to trigger from packages in [deps] (#54009)
There is a use case where you have a weak dependency (for one of your extensions) that is misbehaving and you quickly want to try debug that issue. A workflow that feels reasonable for this could be: ``` pkg> dev WeakDependency julia> using Package, WeakDependency ``` This doesn't work right now for two reasons: 1. Doing the `dev WeakDependency` will add the dependency to `[deps]` but not remove it from `[weakdeps]` which means you all of a sudden are in the scenario described in https://pkgdocs.julialang.org/v1/creating-packages/#Transition-from-normal-dependency-to-extension which is not what is desired. 2. The extension will not actually load because you can right now only trigger extensions from weak deps getting loaded, not from deps getting loaded. Point 1. is fixed by JuliaLang/Pkg.jl#3865 Point 2. is fixed by this PR. (cherry picked from commit f46cb4c)
1 parent bb86259 commit ca603a1

File tree

12 files changed

+89
-34
lines changed

12 files changed

+89
-34
lines changed

base/loading.jl

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,12 +1262,13 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
12621262
proj_pkg = project_file_name_uuid(project_file, pkg.name)
12631263
if pkg == proj_pkg
12641264
d_proj = parsed_toml(project_file)
1265-
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
12661265
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
12671266
extensions === nothing && return
1268-
weakdeps === nothing && return
1269-
if weakdeps isa Dict{String, Any}
1270-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1267+
weakdeps = get(Dict{String, Any}, d_proj, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
1268+
deps = get(Dict{String, Any}, d_proj, "deps")::Union{Vector{String}, Dict{String,Any}}
1269+
if weakdeps isa Dict{String,Any} && deps isa Dict{String,Any}
1270+
total_deps = merge(weakdeps, deps)
1271+
return _insert_extension_triggers(pkg, extensions, total_deps)
12711272
end
12721273
end
12731274

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

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
1306+
if weakdeps isa Vector{String}
1307+
weakdeps = expand_deps_list(weakdeps)
13031308
end
1304-
@assert length(d_weakdeps) == length(weakdeps)
1305-
return _insert_extension_triggers(pkg, extensions, d_weakdeps)
1309+
if deps isa Vector{String}
1310+
deps = expand_deps_list(deps)
1311+
end
1312+
1313+
total_deps = merge(weakdeps, deps)
1314+
return _insert_extension_triggers(pkg, extensions, total_deps)
13061315
end
13071316
end
13081317
end
13091318
end
13101319
return nothing
13111320
end
13121321

1313-
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, weakdeps::Dict{String, Any})
1322+
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, totaldeps::Dict{String, Any})
13141323
for (ext, triggers) in extensions
13151324
triggers = triggers::Union{String, Vector{String}}
13161325
triggers isa String && (triggers = [triggers])
@@ -1324,7 +1333,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}
13241333
push!(trigger1, gid)
13251334
for trigger in triggers
13261335
# TODO: Better error message if this lookup fails?
1327-
uuid_trigger = UUID(weakdeps[trigger]::String)
1336+
uuid_trigger = UUID(totaldeps[trigger]::String)
13281337
trigger_id = PkgId(uuid_trigger, trigger)
13291338
if !haskey(Base.loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
13301339
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 <[email protected]>"]
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"]

0 commit comments

Comments
 (0)