Skip to content

Commit 71fa11f

Browse files
fattenederlongqian95vtjnash
authored
Raise an error when using include_dependency with non-existent file or directory (#53286)
Replaces #52105 Fixes #52063 There is a question about whether the `ispath & uperm` check should be moved inside the `_track_dependencies[]` check (like it was in #52105), which would make it such that any errors are thrown only during precompilation. --------- Co-authored-by: Qian Long <longqian95@gmail.com> Co-authored-by: Jameson Nash <vtjnash@gmail.com>
1 parent 4a65772 commit 71fa11f

File tree

3 files changed

+84
-10
lines changed

3 files changed

+84
-10
lines changed

base/loading.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,14 +2049,21 @@ const include_callbacks = Any[]
20492049
const _concrete_dependencies = Pair{PkgId,UInt128}[] # these dependency versions are "set in stone", and the process should try to avoid invalidating them
20502050
const _require_dependencies = Any[] # a list of (mod, abspath, fsize, hash, mtime) tuples that are the file dependencies of the module currently being precompiled
20512051
const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies
2052-
function _include_dependency(mod::Module, _path::AbstractString; track_content=true)
2052+
function _include_dependency(mod::Module, _path::AbstractString; track_content=true,
2053+
path_may_be_dir=false)
20532054
prev = source_path(nothing)
20542055
if prev === nothing
20552056
path = abspath(_path)
20562057
else
20572058
path = normpath(joinpath(dirname(prev), _path))
20582059
end
2059-
if _track_dependencies[]
2060+
if !_track_dependencies[]
2061+
if !path_may_be_dir && !isfile(path)
2062+
throw(SystemError("opening file $(repr(path))", Libc.ENOENT))
2063+
elseif path_may_be_dir && !Filesystem.isreadable(path)
2064+
throw(SystemError("opening file or folder $(repr(path))", Libc.ENOENT))
2065+
end
2066+
else
20602067
@lock require_lock begin
20612068
if track_content
20622069
hash = isdir(path) ? _crc32c(join(readdir(path))) : open(_crc32c, path, "r")
@@ -2086,7 +2093,7 @@ no effect outside of compilation.
20862093
Keyword argument `track_content` requires at least Julia 1.11.
20872094
"""
20882095
function include_dependency(path::AbstractString; track_content::Bool=false)
2089-
_include_dependency(Main, path, track_content=track_content)
2096+
_include_dependency(Main, path, track_content=track_content, path_may_be_dir=true)
20902097
return nothing
20912098
end
20922099

test/loading.jl

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,29 @@ end
15491549
end
15501550

15511551
file = joinpath(depot, "dev", "non-existent.jl")
1552-
@test_throws SystemError("opening file $(repr(file))") include(file)
1552+
@test try
1553+
include(file); false
1554+
catch e
1555+
@test e isa SystemError
1556+
@test e.prefix == "opening file $(repr(file))"
1557+
true
1558+
end
1559+
touch(file)
1560+
@test include_dependency(file) === nothing
1561+
chmod(file, 0x000)
1562+
1563+
# same for include_dependency: #52063
1564+
dir = mktempdir() do dir
1565+
@test include_dependency(dir) === nothing
1566+
dir
1567+
end
1568+
@test try
1569+
include_dependency(dir); false
1570+
catch e
1571+
@test e isa SystemError
1572+
@test e.prefix == "opening file or folder $(repr(dir))"
1573+
true
1574+
end
15531575
end
15541576
end
15551577

test/precompile.jl

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ using REPL # doc lookup function
66
include("precompile_utils.jl")
77

88
Foo_module = :Foo4b3a94a1a081a8cb
9+
foo_incl_dep = :foo4b3a94a1a081a8cb
10+
bar_incl_dep = :bar4b3a94a1a081a8cb
911
Foo2_module = :F2oo4b3a94a1a081a8cb
1012
FooBase_module = :FooBase4b3a94a1a081a8cb
1113
@eval module ConflictingBindings
@@ -75,6 +77,8 @@ precompile_test_harness(false) do dir
7577
Foo_file = joinpath(dir, "$Foo_module.jl")
7678
Foo2_file = joinpath(dir, "$Foo2_module.jl")
7779
FooBase_file = joinpath(dir, "$FooBase_module.jl")
80+
foo_file = joinpath(dir, "$foo_incl_dep.jl")
81+
bar_file = joinpath(dir, "$bar_incl_dep.jl")
7882

7983
write(FooBase_file,
8084
"""
@@ -123,11 +127,11 @@ precompile_test_harness(false) do dir
123127
124128
# test that docs get reconnected
125129
@doc "foo function" foo(x) = x + 1
126-
include_dependency("foo.jl")
127-
include_dependency("foo.jl")
130+
include_dependency("$foo_incl_dep.jl")
131+
include_dependency("$foo_incl_dep.jl")
128132
module Bar
129133
public bar
130-
include_dependency("bar.jl")
134+
include_dependency("$bar_incl_dep.jl")
131135
end
132136
@doc "Bar module" Bar # this needs to define the META dictionary via eval
133137
@eval Bar @doc "bar function" bar(x) = x + 2
@@ -270,6 +274,8 @@ precompile_test_harness(false) do dir
270274
oid_mat_int = objectid(a_mat_int)
271275
end
272276
""")
277+
# Issue #52063
278+
touch(foo_file); touch(bar_file)
273279
# Issue #12623
274280
@test __precompile__(false) === nothing
275281

@@ -412,8 +418,7 @@ precompile_test_harness(false) do dir
412418
modules, (deps, _, requires), required_modules, _... = Base.parse_cache_header(cachefile)
413419
discard_module = mod_fl_mt -> mod_fl_mt.filename
414420
@test modules == [ Base.PkgId(Foo) => Base.module_build_id(Foo) % UInt64 ]
415-
# foo.jl and bar.jl are never written to disk, so they are not relocatable
416-
@test map(x -> x.filename, deps) == [ Foo_file, joinpath("@depot", "foo.jl"), joinpath("@depot", "bar.jl") ]
421+
@test map(x -> x.filename, deps) == [ Foo_file, joinpath("@depot", foo_file), joinpath("@depot", bar_file) ]
417422
@test requires == [ Base.PkgId(Foo) => Base.PkgId(string(FooBase_module)),
418423
Base.PkgId(Foo) => Base.PkgId(Foo2),
419424
Base.PkgId(Foo) => Base.PkgId(Test),
@@ -422,7 +427,7 @@ precompile_test_harness(false) do dir
422427
@test !isempty(srctxt) && srctxt == read(Foo_file, String)
423428
@test_throws ErrorException Base.read_dependency_src(cachefile, "/tmp/nonexistent.txt")
424429
# dependencies declared with `include_dependency` should not be stored
425-
@test_throws ErrorException Base.read_dependency_src(cachefile, joinpath(dir, "foo.jl"))
430+
@test_throws ErrorException Base.read_dependency_src(cachefile, joinpath(dir, foo_file))
426431

427432
modules, deps1 = Base.cache_dependencies(cachefile)
428433
modules_ok = merge(
@@ -1996,4 +2001,44 @@ precompile_test_harness("Generated Opaque") do load_path
19962001
end
19972002
end
19982003

2004+
precompile_test_harness("Issue #52063") do load_path
2005+
fname = joinpath(load_path, "i_do_not_exist.jl")
2006+
@test try
2007+
include_dependency(fname); false
2008+
catch e
2009+
@test e isa SystemError
2010+
@test e.prefix == "opening file or folder $(repr(fname))"
2011+
true
2012+
end
2013+
touch(fname)
2014+
@test include_dependency(fname) === nothing
2015+
chmod(fname, 0x000)
2016+
@test try
2017+
include_dependency(fname); false
2018+
catch e
2019+
@test e isa SystemError
2020+
@test e.prefix == "opening file or folder $(repr(fname))"
2021+
true
2022+
end broken=Sys.iswindows()
2023+
dir = mktempdir() do dir
2024+
@test include_dependency(dir) === nothing
2025+
chmod(dir, 0x000)
2026+
@test try
2027+
include_dependency(dir); false
2028+
catch e
2029+
@test e isa SystemError
2030+
@test e.prefix == "opening file or folder $(repr(dir))"
2031+
true
2032+
end broken=Sys.iswindows()
2033+
dir
2034+
end
2035+
@test try
2036+
include_dependency(dir); false
2037+
catch e
2038+
@test e isa SystemError
2039+
@test e.prefix == "opening file or folder $(repr(dir))"
2040+
true
2041+
end
2042+
end
2043+
19992044
finish_precompile_test!()

0 commit comments

Comments
 (0)