Skip to content

Commit 2181fd0

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 34e6520 commit 2181fd0

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
@@ -690,27 +683,18 @@ function base_project(project_file)
690683
return nothing
691684
end
692685

693-
function project_deps_get(env::String, name::String)::Union{Nothing,PkgId}
694-
project_file = env_project_file(env)
695-
if project_file isa String
696-
pkg_uuid = explicit_project_deps_get(project_file, name)
697-
pkg_uuid === nothing || return PkgId(pkg_uuid, name)
698-
elseif project_file
699-
return implicit_project_deps_get(env, name)
700-
end
701-
return nothing
702-
end
703-
704686
function package_get_here(project_file, name::String)
705687
# if `where` matches the project, use [deps] section as manifest, and stop searching
706688
pkg_uuid = explicit_project_deps_get(project_file, name)
707689
pkg_uuid === nothing && return PkgId(name)
708690
return PkgId(pkg_uuid, name)
709691
end
710692

711-
function package_get(project_file, where::PkgId, name::String)
712-
proj = project_file_name_uuid(project_file, where.name)
713-
proj != where && return nothing
693+
function package_get(project_file, where::Union{Nothing, PkgId}, name::String)
694+
if where !== nothing
695+
proj = project_file_name_uuid(project_file, where.name)
696+
proj != where && return nothing
697+
end
714698
return package_get_here(project_file, name)
715699
end
716700

@@ -741,23 +725,51 @@ function package_extension_get(project_file, where::PkgId, name::String)
741725
return nothing
742726
end
743727

744-
function manifest_deps_get(env::String, where::PkgId, name::String)::Union{Nothing,PkgId}
745-
@assert where.uuid !== nothing
728+
function environment_deps_get(env::String, where::Union{Nothing,PkgId}, name::String)::Union{Nothing,PkgId}
729+
@assert where === nothing || where.uuid !== nothing
746730
project_file = env_project_file(env)
747731
implicit_manifest = !(project_file isa String)
748732
if implicit_manifest
749733
project_file || return nothing
734+
if where === nothing
735+
# Toplevel load with a directory (implicit manifest) - all we look for is the
736+
# existence of the package name in the directory.
737+
pkg = implicit_manifest_pkgid(env, name)
738+
return pkg
739+
end
750740
project_file = implicit_manifest_project(env, where)
751741
project_file === nothing && return nothing
752742
end
753743

754-
# 1. Are we loading into the top-level project itself? dependencies come from [deps]
755-
# N.B.: Here "top-level" includes package loaded from an implicit manifest, which
756-
# uses the same code path.
744+
# Are we
745+
# a) loading into a top-level project itself
746+
# b) loading into a non-top-level project that was part of an implicit
747+
# manifest environment (and for which we found the project file above)
748+
# c) performing a top-level load (where === nothing) - i.e. we're looking
749+
# at an environment's project file.
750+
#
751+
# If so, we may load either:
752+
# I: the project itself (if name matches where)
753+
# II: a dependency from [deps] section of the project file
754+
#
755+
# N.B.: Here "top-level" includes package loaded from an implicit manifest, which
756+
# uses the same code path. Otherwise this is the active project.
757757
pkg = package_get(project_file, where, name)
758-
pkg === nothing || return pkg
758+
if pkg !== nothing
759+
if where === nothing && pkg.uuid === nothing
760+
# This is a top-level load - even though we didn't find the dependency
761+
# here, we still want to keep looking through the top-level environment stack.
762+
return nothing
763+
end
764+
return pkg
765+
end
759766

760-
# 2. Are we an extension of the top-level project? dependencies come from [weakdeps] and [deps]
767+
@assert where !== nothing
768+
769+
# Are we an extension of a project from cases a), b) above
770+
# If so, in addition to I, II above, we get:
771+
# III: A dependency from [weakdeps] section of the project file as long
772+
# as it is an extension trigger for `where` in the `extensions` section.
761773
pkg = package_extension_get(project_file, where, name)
762774
pkg === nothing || return pkg
763775

@@ -1134,10 +1146,7 @@ function explicit_manifest_entry_path(manifest_file::String, pkg::PkgId, entry::
11341146
end
11351147

11361148
## implicit project & manifest API ##
1137-
1138-
# look for an entry point for `name` from a top-level package (no environment)
1139-
# otherwise return `nothing` to indicate the caller should keep searching
1140-
function implicit_project_deps_get(dir::String, name::String)::Union{Nothing,PkgId}
1149+
function implicit_manifest_pkgid(dir::String, name::String)::Union{Nothing,PkgId}
11411150
path, project_file = entry_point_and_project_file(dir, name)
11421151
if project_file === nothing
11431152
path === nothing && return nothing
@@ -1148,7 +1157,7 @@ function implicit_project_deps_get(dir::String, name::String)::Union{Nothing,Pkg
11481157
return proj
11491158
end
11501159

1151-
function implicit_manifest_project(dir, pkg::PkgId)::Union{Nothing, String}
1160+
function implicit_manifest_project(dir::String, pkg::PkgId)::Union{Nothing, String}
11521161
@assert pkg.uuid !== nothing
11531162
project_file = entry_point_and_project_file(dir, pkg.name)[2]
11541163
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)