@@ -1076,9 +1076,9 @@ function register_restored_modules(sv::SimpleVector, pkg::PkgId, path::String)
10761076end
10771077
10781078function run_package_callbacks (modkey:: PkgId )
1079+ run_extension_callbacks (modkey)
10791080 assert_havelock (require_lock)
10801081 unlock (require_lock)
1081- run_extension_callbacks ()
10821082 try
10831083 for callback in package_callbacks
10841084 invokelatest (callback, modkey)
@@ -1099,14 +1099,13 @@ end
10991099# #############
11001100
11011101mutable struct ExtensionId
1102- const id:: PkgId # Could be symbol?
1103- const parentid:: PkgId
1104- const triggers:: Vector{PkgId} # What packages have to be loaded for the extension to get loaded
1105- triggered:: Bool
1106- succeeded:: Bool
1102+ const id:: PkgId
1103+ const parentid:: PkgId # just need the name, for printing
1104+ ntriggers:: Int # how many more packages must be defined until this is loaded
11071105end
11081106
1109- const EXT_DORMITORY = ExtensionId[]
1107+ const EXT_DORMITORY = Dict {PkgId,Vector{ExtensionId}} ()
1108+ const EXT_DORMITORY_FAILED = ExtensionId[]
11101109
11111110function insert_extension_triggers (pkg:: PkgId )
11121111 pkg. uuid === nothing && return
@@ -1159,59 +1158,84 @@ end
11591158function _insert_extension_triggers (parent:: PkgId , extensions:: Dict{String, <:Any} , weakdeps:: Dict{String, <:Any} )
11601159 for (ext:: String , triggers:: Union{String, Vector{String}} ) in extensions
11611160 triggers isa String && (triggers = [triggers])
1162- triggers_id = PkgId[]
11631161 id = PkgId (uuid5 (parent. uuid, ext), ext)
1162+ gid = ExtensionId (id, parent, 1 + length (triggers))
1163+ trigger1 = get! (Vector{ExtensionId}, EXT_DORMITORY, parent)
1164+ push! (trigger1, gid)
11641165 for trigger in triggers
11651166 # TODO : Better error message if this lookup fails?
11661167 uuid_trigger = UUID (weakdeps[trigger]:: String )
1167- push! (triggers_id, PkgId (uuid_trigger, trigger))
1168+ trigger_id = PkgId (uuid_trigger, trigger)
1169+ if ! haskey (Base. loaded_modules, trigger_id) || haskey (package_locks, trigger_id)
1170+ trigger1 = get! (Vector{ExtensionId}, EXT_DORMITORY, trigger_id)
1171+ push! (trigger1, gid)
1172+ else
1173+ gid. ntriggers -= 1
1174+ end
11681175 end
1169- gid = ExtensionId (id, parent, triggers_id, false , false )
1170- push! (EXT_DORMITORY, gid)
11711176 end
11721177end
11731178
1174- function run_extension_callbacks (; force:: Bool = false )
1175- try
1176- # TODO , if `EXT_DORMITORY` becomes very long, do something smarter
1177- for extid in EXT_DORMITORY
1178- extid. succeeded && continue
1179- ! force && extid. triggered && continue
1180- if all (x -> haskey (Base. loaded_modules, x) && ! haskey (package_locks, x), extid. triggers)
1181- ext_not_allowed_load = nothing
1182- extid. triggered = true
1183- # It is possible that some of the triggers were loaded in an environment
1184- # below the one of the parent. This will cause a load failure when the
1185- # pkg ext tries to load the triggers. Therefore, check this first
1186- # before loading the pkg ext.
1187- for trigger in extid. triggers
1188- pkgenv = Base. identify_package_env (extid. id, trigger. name)
1189- if pkgenv === nothing
1190- ext_not_allowed_load = trigger
1191- break
1192- else
1193- pkg, env = pkgenv
1194- path = Base. locate_package (pkg, env)
1195- if path === nothing
1196- ext_not_allowed_load = trigger
1197- break
1198- end
1199- end
1200- end
1201- if ext_not_allowed_load != = nothing
1202- @debug " Extension $(extid. id. name) of $(extid. parentid. name) not loaded due to \
1203- $(ext_not_allowed_load. name) loaded in environment lower in load path"
1204- else
1205- require (extid. id)
1206- @debug " Extension $(extid. id. name) of $(extid. parentid. name) loaded"
1207- end
1208- extid. succeeded = true
1209- end
1210- end
1179+ function run_extension_callbacks (extid:: ExtensionId )
1180+ assert_havelock (require_lock)
1181+ succeeded = try
1182+ _require_prelocked (extid. id)
1183+ @debug " Extension $(extid. id. name) of $(extid. parentid. name) loaded"
1184+ true
12111185 catch
12121186 # Try to continue loading if loading an extension errors
12131187 errs = current_exceptions ()
12141188 @error " Error during loading of extension" exception= errs
1189+ false
1190+ end
1191+ return succeeded
1192+ end
1193+
1194+ function run_extension_callbacks (pkgid:: PkgId )
1195+ assert_havelock (require_lock)
1196+ # take ownership of extids that depend on this pkgid
1197+ extids = pop! (EXT_DORMITORY, pkgid, nothing )
1198+ extids === nothing && return
1199+ for extid in extids
1200+ if extid. ntriggers > 0
1201+ # It is possible that pkgid was loaded in an environment
1202+ # below the one of the parent. This will cause a load failure when the
1203+ # pkg ext tries to load the triggers. Therefore, check this first
1204+ # before loading the pkg ext.
1205+ pkgenv = Base. identify_package_env (extid. id, pkgid. name)
1206+ ext_not_allowed_load = false
1207+ if pkgenv === nothing
1208+ ext_not_allowed_load = true
1209+ else
1210+ pkg, env = pkgenv
1211+ path = Base. locate_package (pkg, env)
1212+ if path === nothing
1213+ ext_not_allowed_load = true
1214+ end
1215+ end
1216+ if ext_not_allowed_load
1217+ @debug " Extension $(extid. id. name) of $(extid. parentid. name) will not be loaded \
1218+ since $(pkgid. name) loaded in environment lower in load path"
1219+ # indicate extid is expected to fail
1220+ extid. ntriggers *= - 1
1221+ else
1222+ # indicate pkgid is loaded
1223+ extid. ntriggers -= 1
1224+ end
1225+ end
1226+ if extid. ntriggers < 0
1227+ # indicate pkgid is loaded
1228+ extid. ntriggers += 1
1229+ succeeded = false
1230+ else
1231+ succeeded = true
1232+ end
1233+ if extid. ntriggers == 0
1234+ # actually load extid, now that all dependencies are met,
1235+ # and record the result
1236+ succeeded = succeeded && run_extension_callbacks (extid)
1237+ succeeded || push! (EXT_DORMITORY_FAILED, extid)
1238+ end
12151239 end
12161240 nothing
12171241end
@@ -1224,7 +1248,19 @@ This is used in cases where the automatic loading of an extension failed
12241248due to some problem with the extension. Instead of restarting the Julia session,
12251249the extension can be fixed, and this function run.
12261250"""
1227- retry_load_extensions () = run_extension_callbacks (; force= true )
1251+ function retry_load_extensions ()
1252+ @lock require_lock begin
1253+ # this copy is desired since run_extension_callbacks will release this lock
1254+ # so this can still mutate the list to drop successful ones
1255+ failed = copy (EXT_DORMITORY_FAILED)
1256+ empty! (EXT_DORMITORY_FAILED)
1257+ filter! (failed) do extid
1258+ return ! run_extension_callbacks (extid)
1259+ end
1260+ prepend! (EXT_DORMITORY_FAILED, failed)
1261+ end
1262+ nothing
1263+ end
12281264
12291265"""
12301266 get_extension(parent::Module, extension::Symbol)
0 commit comments