Skip to content

Commit 369ed27

Browse files
vtjnashKristofferC
authored andcommitted
[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 ``` (cherry picked from commit 94570e1)
1 parent c585f7e commit 369ed27

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
@@ -2710,7 +2710,7 @@ end
27102710

27112711
# load a serialized file directly from append_bundled_depot_path for uuidkey without stalechecks
27122712
"""
2713-
require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=nothing)
2713+
require_stdlib(package_uuidkey::PkgId, [ext::String, from::Module])
27142714
27152715
!!! warning "May load duplicate copies of stdlib packages."
27162716
@@ -2749,7 +2749,8 @@ end
27492749
[1] https://github.com/JuliaLang/Pkg.jl/issues/4017#issuecomment-2377589989
27502750
[2] https://github.com/JuliaLang/StyledStrings.jl/issues/91#issuecomment-2379602914
27512751
"""
2752-
function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=nothing)
2752+
require_stdlib(package_uuidkey::PkgId) = require_stdlib(package_uuidkey, nothing, Base)
2753+
function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}, from::Module)
27532754
if generating_output(#=incremental=#true)
27542755
# Otherwise this would lead to awkward dependency issues by loading a package that isn't in the Project/Manifest
27552756
error("This interactive function requires a stdlib to be loaded, and package code should instead use it directly from that stdlib.")
@@ -2761,15 +2762,29 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth
27612762
newm = start_loading(this_uuidkey, UInt128(0), true)
27622763
newm === nothing || return newm
27632764
try
2764-
# first since this is a stdlib, try to look there directly first
2765-
if ext === nothing
2766-
sourcepath = normpath(env, this_uuidkey.name, "src", this_uuidkey.name * ".jl")
2767-
else
2768-
sourcepath = find_ext_path(normpath(joinpath(env, package_uuidkey.name)), ext)
2769-
end
27702765
depot_path = append_bundled_depot_path!(empty(DEPOT_PATH))
2771-
set_pkgorigin_version_path(this_uuidkey, sourcepath)
2772-
newm = _require_search_from_serialized(this_uuidkey, sourcepath, UInt128(0), false; DEPOT_PATH=depot_path)
2766+
from_stdlib = true # set to false if `from` is a normal package so we do not want the internal loader for the extension either
2767+
if ext isa String
2768+
from_uuid = PkgId(from)
2769+
from_m = get(loaded_modules, from_uuid, nothing)
2770+
if from_m === from
2771+
# if from_uuid is either nothing or points to something else, assume we should use require_stdlib
2772+
# otherwise check cachepath for from to see if it looks like it is from depot_path, since try_build_ids
2773+
cachepath = get(PkgOrigin, pkgorigins, from_uuid).cachepath
2774+
entrypath, entryfile = cache_file_entry(from_uuid)
2775+
from_stdlib = any(x -> startswith(entrypath, x), depot_path)
2776+
end
2777+
end
2778+
if from_stdlib
2779+
# first since this is a stdlib, try to look there directly first
2780+
if ext === nothing
2781+
sourcepath = normpath(env, this_uuidkey.name, "src", this_uuidkey.name * ".jl")
2782+
else
2783+
sourcepath = find_ext_path(normpath(joinpath(env, package_uuidkey.name)), ext)
2784+
end
2785+
set_pkgorigin_version_path(this_uuidkey, sourcepath)
2786+
newm = _require_search_from_serialized(this_uuidkey, sourcepath, UInt128(0), false; DEPOT_PATH=depot_path)
2787+
end
27732788
finally
27742789
end_loading(this_uuidkey, newm)
27752790
end
@@ -2779,10 +2794,12 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth
27792794
run_package_callbacks(this_uuidkey)
27802795
else
27812796
# if the user deleted their bundled depot, next try to load it completely normally
2797+
# if it is an extension, we first need to indicate where to find its parant via EXT_PRIMED
2798+
ext isa String && (EXT_PRIMED[this_uuidkey] = PkgId[package_uuidkey])
27822799
newm = _require_prelocked(this_uuidkey)
27832800
end
27842801
return newm
2785-
end
2802+
end # release lock
27862803
end
27872804

27882805
# 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)