Skip to content

Commit f46cb4c

Browse files
authored
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 # do some fixes in this dependency julia> using Package, WeakDependency # this loads the extension of Package triggered by loading WeakDependency # check that things work ok now ``` 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.
1 parent e9a24d4 commit f46cb4c

File tree

13 files changed

+85
-38
lines changed

13 files changed

+85
-38
lines changed

base/loading.jl

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,13 +1388,12 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
13881388
proj_pkg = project_file_name_uuid(implicit_project_file, pkg.name)
13891389
if pkg == proj_pkg
13901390
d_proj = parsed_toml(implicit_project_file)
1391-
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
13921391
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
13931392
extensions === nothing && return
1394-
weakdeps === nothing && return
1395-
if weakdeps isa Dict{String, Any}
1396-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1397-
end
1393+
weakdeps = get(Dict{String, Any}, d_proj, "weakdeps")::Dict{String,Any}
1394+
deps = get(Dict{String, Any}, d_proj, "deps")::Dict{String,Any}
1395+
total_deps = merge(weakdeps, deps)
1396+
return _insert_extension_triggers(pkg, extensions, total_deps)
13981397
end
13991398

14001399
# Now look in manifest
@@ -1409,35 +1408,43 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
14091408
uuid = get(entry, "uuid", nothing)::Union{String, Nothing}
14101409
uuid === nothing && continue
14111410
if UUID(uuid) == pkg.uuid
1412-
weakdeps = get(entry, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
14131411
extensions = get(entry, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
14141412
extensions === nothing && return
1415-
weakdeps === nothing && return
1416-
if weakdeps isa Dict{String, Any}
1417-
return _insert_extension_triggers(pkg, extensions, weakdeps)
1413+
weakdeps = get(Dict{String, Any}, entry, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
1414+
deps = get(Dict{String, Any}, entry, "deps")::Union{Vector{String}, Dict{String,Any}}
1415+
1416+
function expand_deps_list(deps′::Vector{String})
1417+
deps′_expanded = Dict{String, Any}()
1418+
for (dep_name, entries) in d
1419+
dep_name in deps′ || continue
1420+
entries::Vector{Any}
1421+
if length(entries) != 1
1422+
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
1423+
end
1424+
entry = first(entries)::Dict{String, Any}
1425+
uuid = entry["uuid"]::String
1426+
deps′_expanded[dep_name] = uuid
1427+
end
1428+
return deps′_expanded
14181429
end
14191430

1420-
d_weakdeps = Dict{String, Any}()
1421-
for (dep_name, entries) in d
1422-
dep_name in weakdeps || continue
1423-
entries::Vector{Any}
1424-
if length(entries) != 1
1425-
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
1426-
end
1427-
entry = first(entries)::Dict{String, Any}
1428-
uuid = entry["uuid"]::String
1429-
d_weakdeps[dep_name] = uuid
1431+
if weakdeps isa Vector{String}
1432+
weakdeps = expand_deps_list(weakdeps)
1433+
end
1434+
if deps isa Vector{String}
1435+
deps = expand_deps_list(deps)
14301436
end
1431-
@assert length(d_weakdeps) == length(weakdeps)
1432-
return _insert_extension_triggers(pkg, extensions, d_weakdeps)
1437+
1438+
total_deps = merge(weakdeps, deps)
1439+
return _insert_extension_triggers(pkg, extensions, total_deps)
14331440
end
14341441
end
14351442
end
14361443
end
14371444
return nothing
14381445
end
14391446

1440-
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, weakdeps::Dict{String, Any})
1447+
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, totaldeps::Dict{String, Any})
14411448
for (ext, triggers) in extensions
14421449
triggers = triggers::Union{String, Vector{String}}
14431450
triggers isa String && (triggers = [triggers])
@@ -1451,7 +1458,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}
14511458
push!(trigger1, gid)
14521459
for trigger in triggers
14531460
# TODO: Better error message if this lookup fails?
1454-
uuid_trigger = UUID(weakdeps[trigger]::String)
1461+
uuid_trigger = UUID(totaldeps[trigger]::String)
14551462
trigger_id = PkgId(uuid_trigger, trigger)
14561463
if !haskey(explicit_loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
14571464
trigger1 = get!(Vector{ExtensionId}, EXT_DORMITORY, trigger_id)

base/precompilation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
409409
all_extdeps_available = true
410410
for extdep_uuid in extdep_uuids
411411
extdep_name = env.names[extdep_uuid]
412-
if extdep_uuid in keys(env.deps) || Base.in_sysimage(Base.PkgId(extdep_uuid, extdep_name))
412+
if extdep_uuid in keys(env.deps)
413413
push!(ext_deps, Base.PkgId(extdep_uuid, extdep_name))
414414
else
415415
all_extdeps_available = false

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
### [Workspaces](@id workspaces)

test/loading.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,9 @@ end
10571057
$ew HasDepWithExtensions.do_something() || error("do_something errored")
10581058
using ExtDep2
10591059
$ew using ExtDep2
1060-
$ew HasExtensions.ext_folder_loaded || error("ext_folder_loaded not set")
1060+
using ExtDep3
1061+
$ew using ExtDep3
1062+
$ew HasExtensions.ext_dep_loaded || error("ext_dep_loaded not set")
10611063
end
10621064
"""
10631065
return `$(Base.julia_cmd()) $compile --startup-file=no -e $cmd`
@@ -1105,6 +1107,8 @@ end
11051107
Base.get_extension(HasExtensions, :Extension) isa Module || error("expected extension to load")
11061108
using ExtDep2
11071109
Base.get_extension(HasExtensions, :ExtensionFolder) isa Module || error("expected extension to load")
1110+
using ExtDep3
1111+
Base.get_extension(HasExtensions, :ExtensionDep) isa Module || error("expected extension to load")
11081112
end
11091113
"""
11101114
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 <[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"
3+
julia_version = "1.12.0-DEV"
44
manifest_format = "2.0"
5-
project_hash = "d523b3401f72a1ed34b7b43749fd2655c6b78542"
5+
project_hash = "4e196b07f2ee7adc48ac9d528d42b3cf3737c7a0"
66

77
[[deps.ExtDep]]
88
deps = ["SomePackage"]
@@ -15,13 +15,20 @@ 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

2329
[deps.HasExtensions.extensions]
2430
Extension = "ExtDep"
31+
ExtensionDep = "ExtDep3"
2532
ExtensionFolder = ["ExtDep", "ExtDep2"]
2633
LinearAlgebraExt = "LinearAlgebra"
2734

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"

0 commit comments

Comments
 (0)