Skip to content

Commit 70825b8

Browse files
KristofferCtopolarity
authored andcommitted
[backports-release-1.10] allow extensions to trigger from packages in [deps] (JuliaLang#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 85aecff commit 70825b8

12 files changed

Lines changed: 84 additions & 34 deletions

File tree

base/loading.jl

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,12 +1211,13 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
12111211
proj_pkg = project_file_name_uuid(project_file, pkg.name)
12121212
if pkg == proj_pkg
12131213
d_proj = parsed_toml(project_file)
1214-
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
12151214
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
12161215
extensions === nothing && return
1217-
weakdeps === nothing && return
1218-
if weakdeps isa Dict{String, Any}
1219-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1216+
weakdeps = get(Dict{String, Any}, d_proj, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
1217+
deps = get(Dict{String, Any}, d_proj, "deps")::Union{Vector{String}, Dict{String,Any}}
1218+
if weakdeps isa Dict{String,Any} && deps isa Dict{String,Any}
1219+
total_deps = merge(weakdeps, deps)
1220+
return _insert_extension_triggers(pkg, extensions, total_deps)
12201221
end
12211222
end
12221223

@@ -1231,35 +1232,43 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
12311232
uuid = get(entry, "uuid", nothing)::Union{String, Nothing}
12321233
uuid === nothing && continue
12331234
if UUID(uuid) == pkg.uuid
1234-
weakdeps = get(entry, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
12351235
extensions = get(entry, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
12361236
extensions === nothing && return
1237-
weakdeps === nothing && return
1238-
if weakdeps isa Dict{String, Any}
1239-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1237+
weakdeps = get(Dict{String, Any}, entry, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
1238+
deps = get(Dict{String, Any}, entry, "deps")::Union{Vector{String}, Dict{String,Any}}
1239+
1240+
function expand_deps_list(deps′::Vector{String})
1241+
deps′_expanded = Dict{String, Any}()
1242+
for (dep_name, entries) in d
1243+
dep_name in deps′ || continue
1244+
entries::Vector{Any}
1245+
if length(entries) != 1
1246+
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
1247+
end
1248+
entry = first(entries)::Dict{String, Any}
1249+
uuid = entry["uuid"]::String
1250+
deps′_expanded[dep_name] = uuid
1251+
end
1252+
return deps′_expanded
12401253
end
12411254

1242-
d_weakdeps = Dict{String, Any}()
1243-
for (dep_name, entries) in d
1244-
dep_name in weakdeps || continue
1245-
entries::Vector{Any}
1246-
if length(entries) != 1
1247-
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
1248-
end
1249-
entry = first(entries)::Dict{String, Any}
1250-
uuid = entry["uuid"]::String
1251-
d_weakdeps[dep_name] = uuid
1255+
if weakdeps isa Vector{String}
1256+
weakdeps = expand_deps_list(weakdeps)
12521257
end
1253-
@assert length(d_weakdeps) == length(weakdeps)
1254-
return _insert_extension_triggers(pkg, extensions, d_weakdeps)
1258+
if deps isa Vector{String}
1259+
deps = expand_deps_list(deps)
1260+
end
1261+
1262+
total_deps = merge(weakdeps, deps)
1263+
return _insert_extension_triggers(pkg, extensions, total_deps)
12551264
end
12561265
end
12571266
end
12581267
end
12591268
return nothing
12601269
end
12611270

1262-
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, weakdeps::Dict{String, Any})
1271+
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, totaldeps::Dict{String, Any})
12631272
for (ext, triggers) in extensions
12641273
triggers = triggers::Union{String, Vector{String}}
12651274
triggers isa String && (triggers = [triggers])
@@ -1273,7 +1282,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}
12731282
push!(trigger1, gid)
12741283
for trigger in triggers
12751284
# TODO: Better error message if this lookup fails?
1276-
uuid_trigger = UUID(weakdeps[trigger]::String)
1285+
uuid_trigger = UUID(totaldeps[trigger]::String)
12771286
trigger_id = PkgId(uuid_trigger, trigger)
12781287
if !haskey(Base.loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
12791288
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
@@ -1028,6 +1028,9 @@ end
10281028
using ExtDep2
10291029
$ew using ExtDep2
10301030
$ew HasExtensions.ext_folder_loaded || error("ext_folder_loaded not set")
1031+
using ExtDep3
1032+
$ew using ExtDep3
1033+
$ew HasExtensions.ext_dep_loaded || error("ext_dep_loaded not set")
10311034
end
10321035
"""
10331036
return `$(Base.julia_cmd()) $compile --startup-file=no -e $cmd`
@@ -1075,6 +1078,8 @@ end
10751078
Base.get_extension(HasExtensions, :Extension) isa Module || error("expected extension to load")
10761079
using ExtDep2
10771080
Base.get_extension(HasExtensions, :ExtensionFolder) isa Module || error("expected extension to load")
1081+
using ExtDep3
1082+
Base.get_extension(HasExtensions, :ExtensionDep) isa Module || error("expected extension to load")
10781083
end
10791084
"""
10801085
for compile in (`--compiled-modules=no`, ``)

test/project/Extensions/EnvWithHasExtensions/Manifest.toml

Lines changed: 4 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.9.0-beta4"
3+
julia_version = "1.12.0-DEV"
44
manifest_format = "2.0"
5-
project_hash = "caa716752e6dff3d77c3de929ebbb5d2024d04ef"
5+
project_hash = "a4c480cfa7da9610333d5c42623bf746bd286c5f"
66

77
[[deps.ExtDep]]
88
deps = ["SomePackage"]
@@ -18,10 +18,12 @@ version = "0.1.0"
1818
[deps.HasExtensions.extensions]
1919
Extension = "ExtDep"
2020
ExtensionFolder = ["ExtDep", "ExtDep2"]
21+
LinearAlgebraExt = "LinearAlgebra"
2122

2223
[deps.HasExtensions.weakdeps]
2324
ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c"
2425
ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
26+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2527

2628
[[deps.SomePackage]]
2729
path = "../SomePackage"
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: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
julia_version = "1.10.0-DEV"
44
manifest_format = "2.0"
5-
project_hash = "d523b3401f72a1ed34b7b43749fd2655c6b78542"
5+
project_hash = "4e196b07f2ee7adc48ac9d528d42b3cf3737c7a0"
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.12.0-DEV"
44
manifest_format = "2.0"
5-
project_hash = "c87947f1f1f070eea848950c304d668a112dec3d"
5+
project_hash = "c0bb526b75939a74a6195ee4819e598918a22ad7"
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)