diff --git a/base/loading.jl b/base/loading.jl index f6d2512f2734c..20f95524c7758 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -201,6 +201,10 @@ const package_locks = Dict{Symbol,Condition}() # Callbacks take the form (mod::Symbol) -> nothing. # WARNING: This is an experimental feature and might change later, without deprecation. const package_callbacks = Any[] +# to notify downstream consumers that a file has been included into a particular module +# Callbacks take the form (mod::Module, filename::String) -> nothing +# WARNING: This is an experimental feature and might change later, without deprecation. +const include_callbacks = Any[] # used to optionally track dependencies when requiring a module: const _concrete_dependencies = Any[] # these dependency versions are "set in stone", and the process should try to avoid invalidating them @@ -519,6 +523,9 @@ end include_relative(mod::Module, path::AbstractString) = include_relative(mod, String(path)) function include_relative(mod::Module, _path::String) path, prev = _include_dependency(_path) + for callback in include_callbacks # to preserve order, must come before Core.include + invokelatest(callback, mod, path) + end tls = task_local_storage() tls[:SOURCE_PATH] = path local result diff --git a/test/loading.jl b/test/loading.jl index 4c4809765b6ed..f85be6cac24fd 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -31,7 +31,11 @@ end @test @nested_LINE_expansion() == ((@__LINE__() - 4, @__LINE__() - 12), @__LINE__()) @test @nested_LINE_expansion2() == ((@__LINE__() - 5, @__LINE__() - 9), @__LINE__()) +loaded_files = String[] +push!(Base.include_callbacks, (mod::Module, fn::String) -> push!(loaded_files, fn)) include("test_sourcepath.jl") +@test length(loaded_files) == 1 && endswith(loaded_files[1], "test_sourcepath.jl") +pop!(Base.include_callbacks) thefname = "the fname!//\\&\1*" include_string_test_func = include_string(@__MODULE__, "include_string_test() = @__FILE__", thefname) @test include_string_test_func() == thefname