Skip to content

Commit 5f4f7ce

Browse files
committed
loading: More simplification
Mostly unswitches the distinction between a top-level load and a load into another project. The hope is that by keeping the code load flow more linear, it becomes easier to follow. No behavioral changes intended.
1 parent 7dfa7d1 commit 5f4f7ce

File tree

2 files changed

+93
-81
lines changed

2 files changed

+93
-81
lines changed

base/loading.jl

Lines changed: 87 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -333,62 +333,56 @@ Same as [`Base.identify_package`](@ref) except that the path to the environment
333333
is also returned, except when the identity is not identified.
334334
"""
335335
identify_package_env(where::Module, name::String) = identify_package_env(PkgId(where), name)
336-
function identify_package_env(where::PkgId, name::String)
337-
assert_havelock(require_lock)
338-
cache = LOADING_CACHE[]
339-
if cache !== nothing
340-
pkg_env = get(cache.identified_where, (where, name), missing)
341-
pkg_env === missing || return pkg_env
342-
end
343-
pkg_env = nothing
344-
if where.name === name
345-
return (where, nothing)
346-
elseif where.uuid === nothing
347-
pkg_env = identify_package_env(name) # ignore `where`
348-
else
349-
for env in load_path()
350-
pkgid = manifest_deps_get(env, where, name)
351-
# If we didn't find `where` at all, keep looking through the environment stack
352-
pkgid === nothing && continue
353-
if pkgid.uuid !== nothing
354-
pkg_env = pkgid, env
355-
end
356-
# If we don't have pkgid.uuid, still break here - this is a sentinel that indicates
357-
# that we've found `where` but it did not have the required dependency. We terminate the search.
358-
break
336+
function identify_package_env(where::Union{PkgId, Nothing}, name::String)
337+
# Special cases
338+
if where !== nothing
339+
if where.name === name
340+
# Project tries to load itself
341+
return (where, nothing)
342+
elseif where.uuid === nothing
343+
# Project without Project.toml - treat as toplevel load
344+
where = nothing
359345
end
360-
if pkg_env === nothing && is_stdlib(where)
361-
# if not found it could be that manifests are from a different julia version/commit
362-
# where stdlib dependencies have changed, so look up deps based on the stdlib Project.toml
363-
# as a fallback
364-
pkg_env = identify_stdlib_project_dep(where, name)
365-
end
366-
end
367-
if cache !== nothing
368-
cache.identified_where[(where, name)] = pkg_env
369346
end
370-
return pkg_env
371-
end
372-
function identify_package_env(name::String)
347+
348+
# Check if we have a cached answer for this
373349
assert_havelock(require_lock)
374350
cache = LOADING_CACHE[]
351+
cache_key = where === nothing ? name : (where, name)
375352
if cache !== nothing
376-
pkg_env = get(cache.identified, name, missing)
353+
env_cache = where === nothing ? cache.identified : cache.identified_where
354+
pkg_env = get(env_cache, cache_key, missing)
377355
pkg_env === missing || return pkg_env
378356
end
357+
358+
# Main part: Search through all environments in the load path to see if we have
359+
# a matching entry.
379360
pkg_env = nothing
380361
for env in load_path()
381-
pkg = project_deps_get(env, name)
382-
if pkg !== nothing
383-
pkg_env = pkg, env # found--return it
384-
break
362+
pkgid = environment_deps_get(env, where, name)
363+
# If we didn't find `where` at all, keep looking through the environment stack
364+
pkgid === nothing && continue
365+
if pkgid.uuid !== nothing || where === nothing
366+
pkg_env = pkgid, env
385367
end
368+
# If we don't have pkgid.uuid, still break here - this is a sentinel that indicates
369+
# that we've found `where` but it did not have the required dependency. We terminate the search.
370+
break
386371
end
372+
if pkg_env === nothing && where !== nothing && is_stdlib(where)
373+
# if not found it could be that manifests are from a different julia version/commit
374+
# where stdlib dependencies have changed, so look up deps based on the stdlib Project.toml
375+
# as a fallback
376+
pkg_env = identify_stdlib_project_dep(where, name)
377+
end
378+
379+
# Cache the result
387380
if cache !== nothing
388-
cache.identified[name] = pkg_env
381+
env_cache[cache_key] = pkg_env
389382
end
390383
return pkg_env
391384
end
385+
identify_package_env(name::String) = identify_package_env(nothing, name)
392386

393387
function identify_stdlib_project_dep(stdlib::PkgId, depname::String)
394388
@debug """
@@ -447,19 +441,18 @@ function locate_package_env(pkg::PkgId, stopenv::Union{String, Nothing}=nothing)
447441
path = nothing
448442
env′ = nothing
449443
if pkg.uuid === nothing
444+
# The project we're looking for does not have a Project.toml (n.b. - present
445+
# `Project.toml` without UUID gets a path-based dummy UUID). It must have
446+
# come from an implicit manifest environment, so go through those only.
450447
for env in load_path()
451-
# look for the toplevel pkg `pkg.name` in this entry
452-
found = project_deps_get(env, pkg.name)
453-
if found !== nothing
448+
project_file = env_project_file(env)
449+
(project_file isa Bool && project_file) || continue
450+
found = implicit_manifest_pkgid(env, pkg.name)
451+
if found !== nothing && found.uuid === nothing
454452
@assert found.name == pkg.name
455-
if found.uuid === nothing
456-
# pkg.name is present in this directory or project file,
457-
# return the path the entry point for the code, if it could be found
458-
# otherwise, signal failure
459-
path = implicit_manifest_uuid_path(env, pkg)
460-
env′ = env
461-
@goto done
462-
end
453+
path = implicit_manifest_uuid_path(env, pkg)
454+
env′ = env
455+
@goto done
463456
end
464457
if !(loading_extension || precompiling_extension)
465458
stopenv == env && @goto done
@@ -715,27 +708,18 @@ function base_project(project_file)
715708
end
716709
end
717710

718-
function project_deps_get(env::String, name::String)::Union{Nothing,PkgId}
719-
project_file = env_project_file(env)
720-
if project_file isa String
721-
pkg_uuid = explicit_project_deps_get(project_file, name)
722-
pkg_uuid === nothing || return PkgId(pkg_uuid, name)
723-
elseif project_file
724-
return implicit_project_deps_get(env, name)
725-
end
726-
return nothing
727-
end
728-
729711
function package_get_here(project_file, name::String)
730712
# if `where` matches the project, use [deps] section as manifest, and stop searching
731713
pkg_uuid = explicit_project_deps_get(project_file, name)
732714
pkg_uuid === nothing && return PkgId(name)
733715
return PkgId(pkg_uuid, name)
734716
end
735717

736-
function package_get(project_file, where::PkgId, name::String)
737-
proj = project_file_name_uuid(project_file, where.name)
738-
proj != where && return nothing
718+
function package_get(project_file, where::Union{Nothing, PkgId}, name::String)
719+
if where !== nothing
720+
proj = project_file_name_uuid(project_file, where.name)
721+
proj != where && return nothing
722+
end
739723
return package_get_here(project_file, name)
740724
end
741725

@@ -766,23 +750,51 @@ function package_extension_get(project_file, where::PkgId, name::String)
766750
return nothing
767751
end
768752

769-
function manifest_deps_get(env::String, where::PkgId, name::String)::Union{Nothing,PkgId}
770-
@assert where.uuid !== nothing
753+
function environment_deps_get(env::String, where::Union{Nothing,PkgId}, name::String)::Union{Nothing,PkgId}
754+
@assert where === nothing || where.uuid !== nothing
771755
project_file = env_project_file(env)
772756
implicit_manifest = !(project_file isa String)
773757
if implicit_manifest
774758
project_file || return nothing
759+
if where === nothing
760+
# Toplevel load with a directory (implicit manifest) - all we look for is the
761+
# existence of the package name in the directory.
762+
pkg = implicit_manifest_pkgid(env, name)
763+
return pkg
764+
end
775765
project_file = implicit_manifest_project(env, where)
776766
project_file === nothing && return nothing
777767
end
778768

779-
# 1. Are we loading into the top-level project itself? dependencies come from [deps]
780-
# N.B.: Here "top-level" includes package loaded from an implicit manifest, which
781-
# uses the same code path.
769+
# Are we
770+
# a) loading into a top-level project itself
771+
# b) loading into a non-top-level project that was part of an implicit
772+
# manifest environment (and for which we found the project file above)
773+
# c) performing a top-level load (where === nothing) - i.e. we're looking
774+
# at an environment's project file.
775+
#
776+
# If so, we may load either:
777+
# I: the project itself (if name matches where)
778+
# II: a dependency from [deps] section of the project file
779+
#
780+
# N.B.: Here "top-level" includes package loaded from an implicit manifest, which
781+
# uses the same code path. Otherwise this is the active project.
782782
pkg = package_get(project_file, where, name)
783-
pkg === nothing || return pkg
783+
if pkg !== nothing
784+
if where === nothing && pkg.uuid === nothing
785+
# This is a top-level load - even though we didn't find the dependency
786+
# here, we still want to keep looking through the top-level environment stack.
787+
return nothing
788+
end
789+
return pkg
790+
end
784791

785-
# 2. Are we an extension of the top-level project? dependencies come from [weakdeps] and [deps]
792+
@assert where !== nothing
793+
794+
# Are we an extension of a project from cases a), b) above
795+
# If so, in addition to I, II above, we get:
796+
# III: A dependency from [weakdeps] section of the project file as long
797+
# as it is an extension trigger for `where` in the `extensions` section.
786798
pkg = package_extension_get(project_file, where, name)
787799
pkg === nothing || return pkg
788800

@@ -1159,10 +1171,7 @@ function explicit_manifest_entry_path(manifest_file::String, pkg::PkgId, entry::
11591171
end
11601172

11611173
## implicit project & manifest API ##
1162-
1163-
# look for an entry point for `name` from a top-level package (no environment)
1164-
# otherwise return `nothing` to indicate the caller should keep searching
1165-
function implicit_project_deps_get(dir::String, name::String)::Union{Nothing,PkgId}
1174+
function implicit_manifest_pkgid(dir::String, name::String)::Union{Nothing,PkgId}
11661175
path, project_file = entry_point_and_project_file(dir, name)
11671176
if project_file === nothing
11681177
path === nothing && return nothing
@@ -1173,7 +1182,7 @@ function implicit_project_deps_get(dir::String, name::String)::Union{Nothing,Pkg
11731182
return proj
11741183
end
11751184

1176-
function implicit_manifest_project(dir, pkg::PkgId)::Union{Nothing, String}
1185+
function implicit_manifest_project(dir::String, pkg::PkgId)::Union{Nothing, String}
11771186
@assert pkg.uuid !== nothing
11781187
project_file = entry_point_and_project_file(dir, pkg.name)[2]
11791188
if project_file === nothing

test/loading.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -623,9 +623,12 @@ function test_find(
623623
end
624624

625625
@testset "find_package with one env in load path" begin
626-
for (env, (_, _, roots, graph, paths)) in envs
627-
push!(empty!(LOAD_PATH), env)
628-
test_find(roots, graph, paths)
626+
for idx in eachindex(envs)
627+
@testset let idx=idx
628+
(env, (_, _, roots, graph, paths)) = envs[idx]
629+
push!(empty!(LOAD_PATH), env)
630+
test_find(roots, graph, paths)
631+
end
629632
end
630633
end
631634

0 commit comments

Comments
 (0)