From e73f66b3cbe5e4fb417de8d1ae6cf6d814ed5b75 Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Tue, 8 Apr 2025 23:18:41 +0200 Subject: [PATCH 1/5] basic submodules implementation --- base/exports.jl | 1 + base/loading.jl | 95 +++++++++++++++++-- test/loading.jl | 24 +++++ .../HasDepWithSubmodules/Manifest.toml | 17 ++++ .../HasDepWithSubmodules/Project.toml | 7 ++ .../Submodules/HasSubmodules/Project.toml | 6 ++ .../HasSubmodules/src/HasSubmodules.jl | 5 + .../HasSubmodules/sub/Submodule1.jl | 12 +++ 8 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 test/project/Submodules/HasDepWithSubmodules/Manifest.toml create mode 100644 test/project/Submodules/HasDepWithSubmodules/Project.toml create mode 100644 test/project/Submodules/HasSubmodules/Project.toml create mode 100644 test/project/Submodules/HasSubmodules/src/HasSubmodules.jl create mode 100644 test/project/Submodules/HasSubmodules/sub/Submodule1.jl diff --git a/base/exports.jl b/base/exports.jl index 2e0bb3ccfe4cf..b66f74351e6e8 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -864,6 +864,7 @@ export evalfile, include_string, include_dependency, + @submodule_using, # RTS internals GC, diff --git a/base/loading.jl b/base/loading.jl index c7397df8f4515..fe0f645bd9bbf 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -772,6 +772,11 @@ function manifest_uuid_path(env::String, pkg::PkgId)::Union{Nothing,String,Missi return nothing end +function find_sub_path(project_path::String, subname::String) + subfiledir = joinpath(project_path, "sub", subname, subname * ".jl") + isfile(subfiledir) && return subfiledir + return joinpath(project_path, "sub", subname * ".jl") +end function find_ext_path(project_path::String, extname::String) extfiledir = joinpath(project_path, "ext", extname, extname * ".jl") @@ -991,7 +996,8 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St end end end - else # Check for extensions + else + # Check for extensions extensions = get(entry, "extensions", nothing) if extensions !== nothing if haskey(extensions, where.name) && where.uuid == uuid5(UUID(uuid), where.name) @@ -1023,6 +1029,38 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St return identify_package(PkgId(UUID(uuid), dep_name), name) end end + # Check for submodules + submodules = get(entry, "submodules", nothing) + if submodules !== nothing + if haskey(submodules, where.name) && where.uuid == uuid5(UUID(uuid), where.name) + found_where = true + if name == dep_name + return PkgId(UUID(uuid), name) + end + subs = submodules[where.name]::Union{String, Vector{String}} + # weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing} + if (subs isa String && name == subs) || (subs isa Vector{String} && name in subs) + for deps′ in deps#[weakdeps, deps] + if deps′ !== nothing + if deps′ isa Vector{String} + found_name = name in deps′ + found_name && @goto done + elseif deps′ isa Dict{String, Any} + deps′ = deps′::Dict{String, Any} + for (dep, uuid) in deps′ + uuid::String + if dep === name + return PkgId(UUID(uuid), name) + end + end + end + end + end + end + # `name` is not an ext, do standard lookup as if this was the parent + return identify_package(PkgId(UUID(uuid), dep_name), name) + end + end end end end @@ -1057,19 +1095,33 @@ function explicit_manifest_uuid_path(project_file::String, pkg::PkgId)::Union{No end end end - # Extensions for (name, entries) in d entries = entries::Vector{Any} for entry in entries uuid = get(entry, "uuid", nothing)::Union{Nothing, String} - extensions = get(entry, "extensions", nothing)::Union{Nothing, Dict{String, Any}} - if extensions !== nothing && haskey(extensions, pkg.name) && uuid !== nothing && uuid5(UUID(uuid), pkg.name) == pkg.uuid - parent_path = locate_package(PkgId(UUID(uuid), name)) - if parent_path === nothing - error("failed to find source of parent package: \"$name\"") + # Extensions + let extensions = get(entry, "extensions", nothing)::Union{Nothing, Dict{String, Any}} + if extensions !== nothing && haskey(extensions, pkg.name) && uuid !== nothing && uuid5(UUID(uuid), pkg.name) == pkg.uuid + parent_path = locate_package(PkgId(UUID(uuid), name)) + if parent_path === nothing + error("failed to find source of parent package: \"$name\"") + end + p = normpath(dirname(parent_path), "..") + return find_ext_path(p, pkg.name) + end + end + # Submodules + let submodules = get(entry, "submodules", nothing)::Union{Nothing, Dict{String, Any}} + if submodules !== nothing + if haskey(submodules, pkg.name) && uuid !== nothing && uuid5(UUID(uuid), pkg.name) == pkg.uuid + parent_path = locate_package(PkgId(UUID(uuid), name)) + if parent_path === nothing + error("failed to find source of parent package: \"$name\"") + end + p = normpath(dirname(parent_path), "..") + return find_sub_path(p, pkg.name) + end end - p = normpath(dirname(parent_path), "..") - return find_ext_path(p, pkg.name) end end end @@ -1670,6 +1722,31 @@ end # End extensions +############## +# Submodules # +############## +function load_submodule(mod::Module, subname::Union{Symbol, String}) + parent_id = PkgId(mod) + str_subname = string(subname) + id = PkgId(uuid5(parent_id.uuid, str_subname), str_subname) + __require(id) +end + +macro submodule_using(parent_sub) + if isexpr(parent_sub, :(.), 2) + parent, sub = parent_sub.args + @gensym mod + esc(quote + $mod = $load_submodule($parent, $sub) + using .$mod + end) + else + throw(ArgumentError("Malformed expression, `@submodule_using` only takes expressions of the form `Parent.Submodule`")) + end +end +# End submodules + + struct CacheFlags # OOICCDDP - see jl_cache_flags use_pkgimages::Bool diff --git a/test/loading.jl b/test/loading.jl index d12cd2769ef1d..7ce9f09839c84 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1264,6 +1264,30 @@ end end end +@testset "Submodules" begin + old_depot_path = copy(DEPOT_PATH) + try + tmp = mktempdir() + push!(empty!(DEPOT_PATH), joinpath(tmp, "depot")) + proj = joinpath(@__DIR__, "project", "Submodules", "HasDepWithSubmodules.jl") + for i in 1:2 # Once when requiring precomilation, once where it is already precompiled + cmd = `$(Base.julia_cmd()) --project=$proj --startup-file=no -e ' + begin + using HasSubmodules + HasSubmodules.sub_loaded && error("sub_loaded set") + using HasDepWithSubmodules + HasSubmodules.sub_loaded || error("sub_loaded not set") + HasDepWithSubmodules.g(1) == 1 || error("g failed") + end + '` + @test success(cmd) + end + finally + copy!(DEPOT_PATH, old_depot_path) + end +end + + pkgimage(val) = val == 1 ? `--pkgimages=yes` : `--pkgimages=no` opt_level(val) = `-O$val` debug_level(val) = `-g$val` diff --git a/test/project/Submodules/HasDepWithSubmodules/Manifest.toml b/test/project/Submodules/HasDepWithSubmodules/Manifest.toml new file mode 100644 index 0000000000000..01bd9138854fe --- /dev/null +++ b/test/project/Submodules/HasDepWithSubmodules/Manifest.toml @@ -0,0 +1,17 @@ +julia_version = "1.13.0-DEV" +manifest_format = "2.0" +project_hash = "cd51eae9e59902fd893210e4f8a4d4dc2ac81722" + +[[deps.HasDepWithSubmodules]] +deps = ["HasSubmodules"] +path = "." +uuid = "0237f425-1828-4bb9-8eeb-a4f4cdb55107" +version = "0.1.0" + +[[deps.HasSubmodules]] +path = "../HasSubmodules" +uuid = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" +version = "0.1.0" + + [deps.HasSubmodules.submodules] + Submodule1 = "" diff --git a/test/project/Submodules/HasDepWithSubmodules/Project.toml b/test/project/Submodules/HasDepWithSubmodules/Project.toml new file mode 100644 index 0000000000000..3702d444e5164 --- /dev/null +++ b/test/project/Submodules/HasDepWithSubmodules/Project.toml @@ -0,0 +1,7 @@ +name = "HasDepWithSubmodules" +uuid = "0237f425-1828-4bb9-8eeb-a4f4cdb55107" +authors = ["Mason Protter "] +version = "0.1.0" + +[deps] +HasSubmodules = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" diff --git a/test/project/Submodules/HasSubmodules/Project.toml b/test/project/Submodules/HasSubmodules/Project.toml new file mode 100644 index 0000000000000..4d20b7b7a953f --- /dev/null +++ b/test/project/Submodules/HasSubmodules/Project.toml @@ -0,0 +1,6 @@ +name = "HasSubmodules" +uuid = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" +version = "0.1.0" + +[submodules] +Submodule1 = "" diff --git a/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl b/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl new file mode 100644 index 0000000000000..faf2e642f6a39 --- /dev/null +++ b/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl @@ -0,0 +1,5 @@ +module HasSubmodules + +sub1_loaded = false + +end diff --git a/test/project/Submodules/HasSubmodules/sub/Submodule1.jl b/test/project/Submodules/HasSubmodules/sub/Submodule1.jl new file mode 100644 index 0000000000000..25b6dde0f05f5 --- /dev/null +++ b/test/project/Submodules/HasSubmodules/sub/Submodule1.jl @@ -0,0 +1,12 @@ +module Submodule1 +using HasSubmodules + +function __init__() + HasSubmodules.sub1_loaded = true +end + +f(x) = x + 1 + +export f + +end From 97bf3343870f57169756fa8de6ef5ebf0bfc11e1 Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Tue, 8 Apr 2025 23:27:43 +0200 Subject: [PATCH 2/5] push forgotten files --- .../HasDepWithSubmodules/src/HasDepWithSubmodules.jl | 10 ++++++++++ .../HasDepWithSubmodules/src/HasDepsWithSubmodules.jl | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl create mode 100644 test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl diff --git a/test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl b/test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl new file mode 100644 index 0000000000000..82fff9901f2be --- /dev/null +++ b/test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl @@ -0,0 +1,10 @@ +module HasDepWithSubmodules + +using HasSubmodules +@submodule_using HasSubmodules.Submodule1 + +g(x) = f(x) - 1 + +export g + +end diff --git a/test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl b/test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl new file mode 100644 index 0000000000000..82fff9901f2be --- /dev/null +++ b/test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl @@ -0,0 +1,10 @@ +module HasDepWithSubmodules + +using HasSubmodules +@submodule_using HasSubmodules.Submodule1 + +g(x) = f(x) - 1 + +export g + +end From 1e1a8ac10790aa66a3993f5c44da71741ae4415b Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Wed, 9 Apr 2025 10:52:11 +0200 Subject: [PATCH 3/5] add (broken) case where submodule depends on a weakdep --- base/loading.jl | 11 ++++++++--- test/loading.jl | 17 ++++++++++++++--- .../HasDepWithSubmodules/Manifest.toml | 6 ++++++ .../HasDepWithSubmodules/Project.toml | 1 + .../src/HasDepsWithSubmodules.jl | 10 ---------- .../Submodules/HasSubmodules/Project.toml | 4 ++++ .../HasSubmodules/src/HasSubmodules.jl | 1 + 7 files changed, 34 insertions(+), 16 deletions(-) delete mode 100644 test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl diff --git a/base/loading.jl b/base/loading.jl index fe0f645bd9bbf..b5f647b6a51b9 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1038,9 +1038,9 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St return PkgId(UUID(uuid), name) end subs = submodules[where.name]::Union{String, Vector{String}} - # weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing} + weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing} if (subs isa String && name == subs) || (subs isa Vector{String} && name in subs) - for deps′ in deps#[weakdeps, deps] + for deps′ in [weakdeps, deps] if deps′ !== nothing if deps′ isa Vector{String} found_name = name in deps′ @@ -1057,7 +1057,7 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St end end end - # `name` is not an ext, do standard lookup as if this was the parent + # `name` is not a submodule, do standard lookup as if this was the parent return identify_package(PkgId(UUID(uuid), dep_name), name) end end @@ -1732,6 +1732,11 @@ function load_submodule(mod::Module, subname::Union{Symbol, String}) __require(id) end +""" + @submodule_using Parent.Sub + +Load the `Sub` submodule from the `Parent` package. +""" macro submodule_using(parent_sub) if isexpr(parent_sub, :(.), 2) parent, sub = parent_sub.args diff --git a/test/loading.jl b/test/loading.jl index 7ce9f09839c84..7f1025f462616 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1269,19 +1269,30 @@ end try tmp = mktempdir() push!(empty!(DEPOT_PATH), joinpath(tmp, "depot")) - proj = joinpath(@__DIR__, "project", "Submodules", "HasDepWithSubmodules.jl") + proj = joinpath(@__DIR__, "project", "Submodules", "HasDepWithSubmodules") for i in 1:2 # Once when requiring precomilation, once where it is already precompiled cmd = `$(Base.julia_cmd()) --project=$proj --startup-file=no -e ' begin using HasSubmodules - HasSubmodules.sub_loaded && error("sub_loaded set") + HasSubmodules.sub1_loaded && error("sub1_loaded set") using HasDepWithSubmodules - HasSubmodules.sub_loaded || error("sub_loaded not set") + HasSubmodules.sub1_loaded || error("sub1_loaded not set") HasDepWithSubmodules.g(1) == 1 || error("g failed") end '` @test success(cmd) end + let cmd = `$(Base.julia_cmd()) --project=$proj --startup-file=no -e ' + begin + using HasSubmodules + using ADep + HasSubmodules.sub2_loaded && error("sub2_loaded set!") + @submodule_using HasSubmodules.Submodule2 # currently broken + HasSubmodules.sub2_loaded && error("sub2_loaded set!") + end + '` + @test_broken success(cmd) + end finally copy!(DEPOT_PATH, old_depot_path) end diff --git a/test/project/Submodules/HasDepWithSubmodules/Manifest.toml b/test/project/Submodules/HasDepWithSubmodules/Manifest.toml index 01bd9138854fe..fe195c3f0cfc2 100644 --- a/test/project/Submodules/HasDepWithSubmodules/Manifest.toml +++ b/test/project/Submodules/HasDepWithSubmodules/Manifest.toml @@ -15,3 +15,9 @@ version = "0.1.0" [deps.HasSubmodules.submodules] Submodule1 = "" + Submodule2 = "ADep" + +[[deps.ADep]] +path = "../ADep" +uuid = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" +version = "0.1.0" diff --git a/test/project/Submodules/HasDepWithSubmodules/Project.toml b/test/project/Submodules/HasDepWithSubmodules/Project.toml index 3702d444e5164..e3f260272c887 100644 --- a/test/project/Submodules/HasDepWithSubmodules/Project.toml +++ b/test/project/Submodules/HasDepWithSubmodules/Project.toml @@ -5,3 +5,4 @@ version = "0.1.0" [deps] HasSubmodules = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" +ADep = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" diff --git a/test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl b/test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl deleted file mode 100644 index 82fff9901f2be..0000000000000 --- a/test/project/Submodules/HasDepWithSubmodules/src/HasDepsWithSubmodules.jl +++ /dev/null @@ -1,10 +0,0 @@ -module HasDepWithSubmodules - -using HasSubmodules -@submodule_using HasSubmodules.Submodule1 - -g(x) = f(x) - 1 - -export g - -end diff --git a/test/project/Submodules/HasSubmodules/Project.toml b/test/project/Submodules/HasSubmodules/Project.toml index 4d20b7b7a953f..22534b1ffde0d 100644 --- a/test/project/Submodules/HasSubmodules/Project.toml +++ b/test/project/Submodules/HasSubmodules/Project.toml @@ -2,5 +2,9 @@ name = "HasSubmodules" uuid = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" version = "0.1.0" +[weakdeps] +ADep = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" + [submodules] Submodule1 = "" +Submodule2 = "ADep" diff --git a/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl b/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl index faf2e642f6a39..342569ca9db7f 100644 --- a/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl +++ b/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl @@ -1,5 +1,6 @@ module HasSubmodules sub1_loaded = false +sub2_loaded = false end From da115be26ee546daa3da46c8e935e3964e74e513 Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Wed, 9 Apr 2025 15:11:32 +0200 Subject: [PATCH 4/5] rename submodule -> subpackage; allow loading submodule without parent --- base/exports.jl | 2 +- base/loading.jl | 71 +++++++++++++------ test/loading.jl | 31 +++++--- .../HasDepWithSubmodules/Project.toml | 8 --- .../src/HasDepWithSubmodules.jl | 10 --- .../HasSubmodules/sub/Submodule1.jl | 12 ---- test/project/Subpackages/ADep/Project.toml | 4 ++ test/project/Subpackages/ADep/src/ADep.jl | 7 ++ .../HasDepWithSubpackages}/Manifest.toml | 15 ++-- .../HasDepWithSubpackages/Project.toml | 7 ++ .../src/HasDepWithSubpackages.jl | 10 +++ .../HasSubpackages}/Project.toml | 9 +-- .../HasSubpackages/src/HasSubpackages.jl} | 2 +- .../HasSubpackages/sub/Subpackage1.jl | 12 ++++ .../HasSubpackages/sub/Subpackage2.jl | 14 ++++ 15 files changed, 138 insertions(+), 76 deletions(-) delete mode 100644 test/project/Submodules/HasDepWithSubmodules/Project.toml delete mode 100644 test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl delete mode 100644 test/project/Submodules/HasSubmodules/sub/Submodule1.jl create mode 100644 test/project/Subpackages/ADep/Project.toml create mode 100644 test/project/Subpackages/ADep/src/ADep.jl rename test/project/{Submodules/HasDepWithSubmodules => Subpackages/HasDepWithSubpackages}/Manifest.toml (60%) create mode 100644 test/project/Subpackages/HasDepWithSubpackages/Project.toml create mode 100644 test/project/Subpackages/HasDepWithSubpackages/src/HasDepWithSubpackages.jl rename test/project/{Submodules/HasSubmodules => Subpackages/HasSubpackages}/Project.toml (50%) rename test/project/{Submodules/HasSubmodules/src/HasSubmodules.jl => Subpackages/HasSubpackages/src/HasSubpackages.jl} (67%) create mode 100644 test/project/Subpackages/HasSubpackages/sub/Subpackage1.jl create mode 100644 test/project/Subpackages/HasSubpackages/sub/Subpackage2.jl diff --git a/base/exports.jl b/base/exports.jl index b66f74351e6e8..97908d78c39f8 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -864,7 +864,7 @@ export evalfile, include_string, include_dependency, - @submodule_using, + @subpackage_using, # RTS internals GC, diff --git a/base/loading.jl b/base/loading.jl index b5f647b6a51b9..2777910ce7114 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1029,15 +1029,15 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St return identify_package(PkgId(UUID(uuid), dep_name), name) end end - # Check for submodules - submodules = get(entry, "submodules", nothing) - if submodules !== nothing - if haskey(submodules, where.name) && where.uuid == uuid5(UUID(uuid), where.name) + # Check for subpackages + subpackages = get(entry, "subpackages", nothing) + if subpackages !== nothing + if haskey(subpackages, where.name) && where.uuid == uuid5(UUID(uuid), where.name) found_where = true if name == dep_name return PkgId(UUID(uuid), name) end - subs = submodules[where.name]::Union{String, Vector{String}} + subs = subpackages[where.name]::Union{String, Vector{String}} weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing} if (subs isa String && name == subs) || (subs isa Vector{String} && name in subs) for deps′ in [weakdeps, deps] @@ -1057,7 +1057,7 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St end end end - # `name` is not a submodule, do standard lookup as if this was the parent + # `name` is not a subpackage, do standard lookup as if this was the parent return identify_package(PkgId(UUID(uuid), dep_name), name) end end @@ -1110,10 +1110,10 @@ function explicit_manifest_uuid_path(project_file::String, pkg::PkgId)::Union{No return find_ext_path(p, pkg.name) end end - # Submodules - let submodules = get(entry, "submodules", nothing)::Union{Nothing, Dict{String, Any}} - if submodules !== nothing - if haskey(submodules, pkg.name) && uuid !== nothing && uuid5(UUID(uuid), pkg.name) == pkg.uuid + # Subpackages + let subpackages = get(entry, "subpackages", nothing)::Union{Nothing, Dict{String, Any}} + if subpackages !== nothing + if haskey(subpackages, pkg.name) && uuid !== nothing && uuid5(UUID(uuid), pkg.name) == pkg.uuid parent_path = locate_package(PkgId(UUID(uuid), name)) if parent_path === nothing error("failed to find source of parent package: \"$name\"") @@ -1722,34 +1722,61 @@ end # End extensions -############## -# Submodules # -############## -function load_submodule(mod::Module, subname::Union{Symbol, String}) +############### +# Subpackages # +############### +function load_subpackage(into::Module, parentname::Symbol, subname::Union{Symbol, String}) + str_parentname = string(parentname) + str_subname = string(subname) + parent_uuid = @lock require_lock begin + uuidkey_env = identify_package_env(into, String(parentname)) + if uuidkey_env === nothing + where = PkgId(into) + if where.uuid === nothing + throw(ArgumentError("Package $parentname not found in current path.")) + else + manifest_warnings = collect_manifest_warnings() + throw(ArgumentError(""" + Package $(where.name) does not have $parentname in its dependencies: + $manifest_warnings- You may have a partially installed environment. Try `Pkg.instantiate()` + to ensure all packages in the environment are installed. + - Or, if you have $(where.name) checked out for development and have + added $parentname as a dependency but haven't updated your primary + environment's manifest file, try `Pkg.resolve()`. + - Otherwise you may need to report an issue with $(where.name)""")) + end + end + uuidkey, env = uuidkey_env + uuidkey.uuid + end + sub_id = PkgId(uuid5(parent_uuid, str_subname), str_subname) + __require(sub_id) +end +function load_subpackage(mod::Module, subname::Union{Symbol, String}) parent_id = PkgId(mod) str_subname = string(subname) - id = PkgId(uuid5(parent_id.uuid, str_subname), str_subname) - __require(id) + sub_id = PkgId(uuid5(parent_id.uuid, str_subname), str_subname) + __require(sub_id) end """ - @submodule_using Parent.Sub + @subpackage_using Parent.Sub -Load the `Sub` submodule from the `Parent` package. +Load the `Sub` subpackage from the `Parent` package. """ -macro submodule_using(parent_sub) +macro subpackage_using(parent_sub) if isexpr(parent_sub, :(.), 2) parent, sub = parent_sub.args @gensym mod esc(quote - $mod = $load_submodule($parent, $sub) + $mod = $load_subpackage($__module__, $(QuoteNode(parent)), $sub) using .$mod end) else - throw(ArgumentError("Malformed expression, `@submodule_using` only takes expressions of the form `Parent.Submodule`")) + throw(ArgumentError("Malformed expression, `@subpackage_using` only takes expressions of the form `Parent.Subpackage`")) end end -# End submodules +# End subpackages struct CacheFlags diff --git a/test/loading.jl b/test/loading.jl index 7f1025f462616..85f364f26ddcf 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1264,35 +1264,44 @@ end end end -@testset "Submodules" begin +@testset "Subpackages" begin old_depot_path = copy(DEPOT_PATH) try tmp = mktempdir() push!(empty!(DEPOT_PATH), joinpath(tmp, "depot")) - proj = joinpath(@__DIR__, "project", "Submodules", "HasDepWithSubmodules") + proj = joinpath(@__DIR__, "project", "Subpackages", "HasDepWithSubpackages") for i in 1:2 # Once when requiring precomilation, once where it is already precompiled cmd = `$(Base.julia_cmd()) --project=$proj --startup-file=no -e ' begin - using HasSubmodules - HasSubmodules.sub1_loaded && error("sub1_loaded set") - using HasDepWithSubmodules - HasSubmodules.sub1_loaded || error("sub1_loaded not set") - HasDepWithSubmodules.g(1) == 1 || error("g failed") + using HasSubpackages + HasSubpackages.sub1_loaded && error("sub1_loaded set") + using HasDepWithSubpackages + HasSubpackages.sub1_loaded || error("sub1_loaded not set") + HasDepWithSubpackages.g(1) == 1 || error("g failed") end '` @test success(cmd) end let cmd = `$(Base.julia_cmd()) --project=$proj --startup-file=no -e ' begin - using HasSubmodules + using HasSubpackages using ADep - HasSubmodules.sub2_loaded && error("sub2_loaded set!") - @submodule_using HasSubmodules.Submodule2 # currently broken - HasSubmodules.sub2_loaded && error("sub2_loaded set!") + HasSubpackages.sub2_loaded && error("sub2_loaded set!") + @submodule_using HasSubpackages.Subpackage2 # currently broken + HasSubpackages.sub2_loaded && error("sub2_loaded set!") end '` @test_broken success(cmd) end + let cmd = `$(Base.julia_cmd()) --project=$proj --startup-file=no -e ' + begin + @subpackage_using HasSubpackages.Subpackage3 + Subpackage3.x == 1 || error("Something went wrong with HasSubpackages.Subpackage3") + "HasSubpackages" ∉ string.(values(Base.loaded_modules)) || error("HasSubpackages was loaded when it was not needed!") + end + '` + @test success(cmd) + end finally copy!(DEPOT_PATH, old_depot_path) end diff --git a/test/project/Submodules/HasDepWithSubmodules/Project.toml b/test/project/Submodules/HasDepWithSubmodules/Project.toml deleted file mode 100644 index e3f260272c887..0000000000000 --- a/test/project/Submodules/HasDepWithSubmodules/Project.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "HasDepWithSubmodules" -uuid = "0237f425-1828-4bb9-8eeb-a4f4cdb55107" -authors = ["Mason Protter "] -version = "0.1.0" - -[deps] -HasSubmodules = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" -ADep = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" diff --git a/test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl b/test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl deleted file mode 100644 index 82fff9901f2be..0000000000000 --- a/test/project/Submodules/HasDepWithSubmodules/src/HasDepWithSubmodules.jl +++ /dev/null @@ -1,10 +0,0 @@ -module HasDepWithSubmodules - -using HasSubmodules -@submodule_using HasSubmodules.Submodule1 - -g(x) = f(x) - 1 - -export g - -end diff --git a/test/project/Submodules/HasSubmodules/sub/Submodule1.jl b/test/project/Submodules/HasSubmodules/sub/Submodule1.jl deleted file mode 100644 index 25b6dde0f05f5..0000000000000 --- a/test/project/Submodules/HasSubmodules/sub/Submodule1.jl +++ /dev/null @@ -1,12 +0,0 @@ -module Submodule1 -using HasSubmodules - -function __init__() - HasSubmodules.sub1_loaded = true -end - -f(x) = x + 1 - -export f - -end diff --git a/test/project/Subpackages/ADep/Project.toml b/test/project/Subpackages/ADep/Project.toml new file mode 100644 index 0000000000000..8fe46839862e1 --- /dev/null +++ b/test/project/Subpackages/ADep/Project.toml @@ -0,0 +1,4 @@ +name = "ADep" +uuid = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" +authors = ["Mason Protter "] +version = "0.1.0" diff --git a/test/project/Subpackages/ADep/src/ADep.jl b/test/project/Subpackages/ADep/src/ADep.jl new file mode 100644 index 0000000000000..61c6e22ebe2c8 --- /dev/null +++ b/test/project/Subpackages/ADep/src/ADep.jl @@ -0,0 +1,7 @@ +module ADep + +foo(x) = x^2 + +export foo + +end # module ADep diff --git a/test/project/Submodules/HasDepWithSubmodules/Manifest.toml b/test/project/Subpackages/HasDepWithSubpackages/Manifest.toml similarity index 60% rename from test/project/Submodules/HasDepWithSubmodules/Manifest.toml rename to test/project/Subpackages/HasDepWithSubpackages/Manifest.toml index fe195c3f0cfc2..b4dbffa078ac4 100644 --- a/test/project/Submodules/HasDepWithSubmodules/Manifest.toml +++ b/test/project/Subpackages/HasDepWithSubpackages/Manifest.toml @@ -2,20 +2,21 @@ julia_version = "1.13.0-DEV" manifest_format = "2.0" project_hash = "cd51eae9e59902fd893210e4f8a4d4dc2ac81722" -[[deps.HasDepWithSubmodules]] -deps = ["HasSubmodules"] +[[deps.HasDepWithSubpackages]] +deps = ["HasSubpackages"] path = "." uuid = "0237f425-1828-4bb9-8eeb-a4f4cdb55107" version = "0.1.0" -[[deps.HasSubmodules]] -path = "../HasSubmodules" +[[deps.HasSubpackages]] +path = "../HasSubpackages" uuid = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" version = "0.1.0" - [deps.HasSubmodules.submodules] - Submodule1 = "" - Submodule2 = "ADep" + [deps.HasSubpackages.subpackages] + Subpackage1 = "HasSubpackages" + Subpackage2 = "ADep" + Subpackage3 = "" [[deps.ADep]] path = "../ADep" diff --git a/test/project/Subpackages/HasDepWithSubpackages/Project.toml b/test/project/Subpackages/HasDepWithSubpackages/Project.toml new file mode 100644 index 0000000000000..11053ea403287 --- /dev/null +++ b/test/project/Subpackages/HasDepWithSubpackages/Project.toml @@ -0,0 +1,7 @@ +name = "HasDepWithSubpackages" +uuid = "0237f425-1828-4bb9-8eeb-a4f4cdb55107" +version = "0.1.0" + +[deps] +HasSubpackages = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" +ADep = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" diff --git a/test/project/Subpackages/HasDepWithSubpackages/src/HasDepWithSubpackages.jl b/test/project/Subpackages/HasDepWithSubpackages/src/HasDepWithSubpackages.jl new file mode 100644 index 0000000000000..9380c6b52a557 --- /dev/null +++ b/test/project/Subpackages/HasDepWithSubpackages/src/HasDepWithSubpackages.jl @@ -0,0 +1,10 @@ +module HasDepWithSubpackages + +using HasSubpackages +@subpackage_using HasSubpackages.Subpackage1 + +g(x) = f(x) - 1 + +export g + +end diff --git a/test/project/Submodules/HasSubmodules/Project.toml b/test/project/Subpackages/HasSubpackages/Project.toml similarity index 50% rename from test/project/Submodules/HasSubmodules/Project.toml rename to test/project/Subpackages/HasSubpackages/Project.toml index 22534b1ffde0d..0108bec8e04d9 100644 --- a/test/project/Submodules/HasSubmodules/Project.toml +++ b/test/project/Subpackages/HasSubpackages/Project.toml @@ -1,10 +1,11 @@ -name = "HasSubmodules" +name = "HasSubpackages" uuid = "0f595f7f-271a-49d7-b31d-0f5ff0a9189a" version = "0.1.0" [weakdeps] ADep = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" -[submodules] -Submodule1 = "" -Submodule2 = "ADep" +[subpackages] +Subpackage1 = "HasSubpackages" +Subpackage2 = "HasSubpackages, ADep" +Subpackage3 = "" diff --git a/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl b/test/project/Subpackages/HasSubpackages/src/HasSubpackages.jl similarity index 67% rename from test/project/Submodules/HasSubmodules/src/HasSubmodules.jl rename to test/project/Subpackages/HasSubpackages/src/HasSubpackages.jl index 342569ca9db7f..0e8a1a5b94a60 100644 --- a/test/project/Submodules/HasSubmodules/src/HasSubmodules.jl +++ b/test/project/Subpackages/HasSubpackages/src/HasSubpackages.jl @@ -1,4 +1,4 @@ -module HasSubmodules +module HasSubpackages sub1_loaded = false sub2_loaded = false diff --git a/test/project/Subpackages/HasSubpackages/sub/Subpackage1.jl b/test/project/Subpackages/HasSubpackages/sub/Subpackage1.jl new file mode 100644 index 0000000000000..9ef73fbbaf3f6 --- /dev/null +++ b/test/project/Subpackages/HasSubpackages/sub/Subpackage1.jl @@ -0,0 +1,12 @@ +module Subpackage1 +using HasSubpackages + +function __init__() + HasSubpackages.sub1_loaded = true +end + +f(x) = x + 1 + +export f + +end diff --git a/test/project/Subpackages/HasSubpackages/sub/Subpackage2.jl b/test/project/Subpackages/HasSubpackages/sub/Subpackage2.jl new file mode 100644 index 0000000000000..3e12aa33c465b --- /dev/null +++ b/test/project/Subpackages/HasSubpackages/sub/Subpackage2.jl @@ -0,0 +1,14 @@ +module Subpackage2 + +using ADep +using HasSubpackages + +bar(x) = foo(x) + 1 + +export bar + +function __init__() + HasSubpackages.sub2_loaded = true +end + +end From 7273ffa09ccf3258e1993d69acd4944edca27da4 Mon Sep 17 00:00:00 2001 From: Mason Protter Date: Wed, 9 Apr 2025 15:17:11 +0200 Subject: [PATCH 5/5] fixup toml --- test/project/Subpackages/HasDepWithSubpackages/Manifest.toml | 2 +- test/project/Subpackages/HasSubpackages/Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/project/Subpackages/HasDepWithSubpackages/Manifest.toml b/test/project/Subpackages/HasDepWithSubpackages/Manifest.toml index b4dbffa078ac4..6e39123f17d1c 100644 --- a/test/project/Subpackages/HasDepWithSubpackages/Manifest.toml +++ b/test/project/Subpackages/HasDepWithSubpackages/Manifest.toml @@ -15,7 +15,7 @@ version = "0.1.0" [deps.HasSubpackages.subpackages] Subpackage1 = "HasSubpackages" - Subpackage2 = "ADep" + Subpackage2 = ["HasSubpackages", "ADep"] Subpackage3 = "" [[deps.ADep]] diff --git a/test/project/Subpackages/HasSubpackages/Project.toml b/test/project/Subpackages/HasSubpackages/Project.toml index 0108bec8e04d9..ca980386dcf4e 100644 --- a/test/project/Subpackages/HasSubpackages/Project.toml +++ b/test/project/Subpackages/HasSubpackages/Project.toml @@ -7,5 +7,5 @@ ADep = "81016d05-d0fa-4c22-8125-5c67d6cf9f2f" [subpackages] Subpackage1 = "HasSubpackages" -Subpackage2 = "HasSubpackages, ADep" +Subpackage2 = ["HasSubpackages", "ADep"] Subpackage3 = ""