Skip to content

Commit 94570e1

Browse files
authored
[REPL] more reliable extension loading (#58415)
A weird edge case of loading, if REPL is loaded explicitly and does not come from a require_stdlib call, it should not be getting REPLExt from a require_stdlib call either. This is a convoluted bit of hackery specific to work around problems with the way Pkg's REPLExt is designed to mutate the REPL in unsafe ways. No other stdlib should ever want to access an extension, particularly of a different module, as that is a private API violation on multiple counts, so this only needs to be made to work specifically for that REPL-Pkg scenario, even if it looks seemingly more general. Refs #58373 Reproducer: ``` JULIA_DEPOT_PATH=tmpdir/.julia ./julia --hist=no -qie 'using REPL' ] status ```
1 parent d54f9b6 commit 94570e1

File tree

2 files changed

+31
-12
lines changed

2 files changed

+31
-12
lines changed

base/loading.jl

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2715,7 +2715,7 @@ end
27152715

27162716
# load a serialized file directly from append_bundled_depot_path for uuidkey without stalechecks
27172717
"""
2718-
require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=nothing)
2718+
require_stdlib(package_uuidkey::PkgId, [ext::String, from::Module])
27192719
27202720
!!! warning "May load duplicate copies of stdlib packages."
27212721
@@ -2754,7 +2754,8 @@ end
27542754
[1] https://github.com/JuliaLang/Pkg.jl/issues/4017#issuecomment-2377589989
27552755
[2] https://github.com/JuliaLang/StyledStrings.jl/issues/91#issuecomment-2379602914
27562756
"""
2757-
function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=nothing)
2757+
require_stdlib(package_uuidkey::PkgId) = require_stdlib(package_uuidkey, nothing, Base)
2758+
function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}, from::Module)
27582759
if generating_output(#=incremental=#true)
27592760
# Otherwise this would lead to awkward dependency issues by loading a package that isn't in the Project/Manifest
27602761
error("This interactive function requires a stdlib to be loaded, and package code should instead use it directly from that stdlib.")
@@ -2766,15 +2767,29 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth
27662767
newm = start_loading(this_uuidkey, UInt128(0), true)
27672768
newm === nothing || return newm
27682769
try
2769-
# first since this is a stdlib, try to look there directly first
2770-
if ext === nothing
2771-
sourcepath = normpath(env, this_uuidkey.name, "src", this_uuidkey.name * ".jl")
2772-
else
2773-
sourcepath = find_ext_path(normpath(joinpath(env, package_uuidkey.name)), ext)
2774-
end
27752770
depot_path = append_bundled_depot_path!(empty(DEPOT_PATH))
2776-
set_pkgorigin_version_path(this_uuidkey, sourcepath)
2777-
newm = _require_search_from_serialized(this_uuidkey, sourcepath, UInt128(0), false; DEPOT_PATH=depot_path)
2771+
from_stdlib = true # set to false if `from` is a normal package so we do not want the internal loader for the extension either
2772+
if ext isa String
2773+
from_uuid = PkgId(from)
2774+
from_m = get(loaded_modules, from_uuid, nothing)
2775+
if from_m === from
2776+
# if from_uuid is either nothing or points to something else, assume we should use require_stdlib
2777+
# otherwise check cachepath for from to see if it looks like it is from depot_path, since try_build_ids
2778+
cachepath = get(PkgOrigin, pkgorigins, from_uuid).cachepath
2779+
entrypath, entryfile = cache_file_entry(from_uuid)
2780+
from_stdlib = any(x -> startswith(entrypath, x), depot_path)
2781+
end
2782+
end
2783+
if from_stdlib
2784+
# first since this is a stdlib, try to look there directly first
2785+
if ext === nothing
2786+
sourcepath = normpath(env, this_uuidkey.name, "src", this_uuidkey.name * ".jl")
2787+
else
2788+
sourcepath = find_ext_path(normpath(joinpath(env, package_uuidkey.name)), ext)
2789+
end
2790+
set_pkgorigin_version_path(this_uuidkey, sourcepath)
2791+
newm = _require_search_from_serialized(this_uuidkey, sourcepath, UInt128(0), false; DEPOT_PATH=depot_path)
2792+
end
27782793
finally
27792794
end_loading(this_uuidkey, newm)
27802795
end
@@ -2784,10 +2799,12 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth
27842799
run_package_callbacks(this_uuidkey)
27852800
else
27862801
# if the user deleted their bundled depot, next try to load it completely normally
2802+
# if it is an extension, we first need to indicate where to find its parant via EXT_PRIMED
2803+
ext isa String && (EXT_PRIMED[this_uuidkey] = PkgId[package_uuidkey])
27872804
newm = _require_prelocked(this_uuidkey)
27882805
end
27892806
return newm
2790-
end
2807+
end # release lock
27912808
end
27922809

27932810
# relative-path load

stdlib/REPL/src/Pkg_beforeload.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
# This file is a part of Julia. License is MIT: https://julialang.org/license
2+
13
## Pkg stuff needed before Pkg has loaded
24

35
const Pkg_pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")
4-
load_pkg() = Base.require_stdlib(Pkg_pkgid, "REPLExt")
6+
load_pkg() = Base.require_stdlib(Pkg_pkgid, "REPLExt", REPL)
57

68
## Below here copied/tweaked from Pkg Types.jl so that the dummy Pkg prompt
79
# can populate the env correctly before Pkg loads

0 commit comments

Comments
 (0)