Skip to content

Commit 046ac6f

Browse files
committed
chore: Cleanup error messages when reloading a module
Signed-off-by: Danielle Voznyy <dan.voznyy@gmail.com>
1 parent ab24a43 commit 046ac6f

File tree

5 files changed

+52
-25
lines changed

5 files changed

+52
-25
lines changed

core/src/commonMain/kotlin/com/mineinabyss/dependencies/DIAware.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.mineinabyss.dependencies
22

33
import co.touchlab.kermit.Logger
44
import com.mineinabyss.dependencies.exceptions.DIBindingException
5+
import com.mineinabyss.dependencies.exceptions.LoadResult
56
import com.mineinabyss.dependencies.impl.MutableDIImpl
67
import kotlin.contracts.ExperimentalContracts
78
import kotlin.contracts.InvocationKind
@@ -16,7 +17,7 @@ import kotlin.reflect.typeOf
1617
* @see DIContext
1718
* @see MutableDI
1819
*/
19-
@FeatureDSLMarker
20+
@DependenciesDSLMarker
2021
interface DI : AutoCloseable {
2122
val di: DIContext
2223

@@ -58,7 +59,7 @@ interface DI : AutoCloseable {
5859

5960
fun load(module: Module): DI
6061
fun unload(module: Module)
61-
fun reload(module: Module)
62+
fun reload(module: Module): LoadResult
6263

6364
val loaded: List<Module>
6465
}

core/src/commonMain/kotlin/com/mineinabyss/dependencies/DIScope.kt

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.mineinabyss.dependencies
22

33
import co.touchlab.kermit.Logger
4+
import com.mineinabyss.dependencies.exceptions.LoadResult
45

56
class DIScope(root: MutableDI.() -> Unit = {}) : DI.Scope, DI, AutoCloseable {
67
private val _loaded = mutableMapOf<DI.Module.Key, DI>()
@@ -35,51 +36,62 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DI.Scope, DI, AutoCloseable {
3536
created.addCloseable {
3637
_loaded.remove(key)
3738
loadOrder.remove(module)
38-
logger.i { "Unloaded feature $module" }
39+
logger.i { "Unloaded module $module" }
3940
}
40-
logger.i { "Loaded feature $module" }
41+
logger.i { "Loaded module $module" }
4142
return created
4243
}
4344

4445
fun loadAll(vararg modules: DI.Module) {
4546
modules.forEach { load(it) }
4647
}
4748

48-
override fun reload(module: DI.Module) {
49+
override fun reload(module: DI.Module): LoadResult {
4950
val beforeUnload = loadOrder.toList()
5051
unload(module)
5152
val unloadedDependencies = beforeUnload.minus(loadOrder.toSet())
52-
loadAll(*unloadedDependencies.toTypedArray())
53+
return loadAllCatching(*unloadedDependencies.toTypedArray())
5354
}
5455

55-
fun reload(vararg module: DI.Module) {
56+
fun reload(vararg module: DI.Module): LoadResult {
5657
val beforeUnload = loadOrder.toList()
5758
module.forEach { unload(it) }
5859
val unloadedDependencies = beforeUnload.minus(loadOrder.toSet())
59-
loadAll(*unloadedDependencies.toTypedArray())
60+
return loadAllCatching(*unloadedDependencies.toTypedArray())
6061
}
6162

62-
fun reloadAll() {
63+
fun reloadAll(): LoadResult {
6364
val load = loadOrder.toTypedArray()
6465
unloadAll()
65-
loadAll(*load)
66+
return loadAllCatching(*load)
6667
}
6768

68-
operator fun get(module: DI.Module): DI? {
69-
return _loaded[module.key]?.di
69+
fun getOrNull(module: DI.Module): DI? {
70+
return _loaded[module.key]?.takeIf { it != FailedModule }?.di
7071
}
7172

72-
operator fun <T> get(module: DI.ModuleWithConfig<T>): T? {
73-
return _loaded[module.key]?.di?.let { module.get(it) }
73+
fun <T> getOrNull(module: DI.ModuleWithConfig<T>): T? {
74+
return _loaded[module.key]?.takeIf { it != FailedModule }?.di?.let { module.get(it) }
75+
}
76+
77+
operator fun get(module: DI.Module): DI {
78+
return getOrNull(module) ?: error("Failed to get module ${module.name}")
79+
}
80+
81+
operator fun <T> get(module: DI.ModuleWithConfig<T>): T {
82+
return getOrNull(module) ?: error("Failed to get module ${module.name}")
7483
}
7584

7685
override fun unload(module: DI.Module) {
7786
val key = module.key
7887
val feat = _loaded[key] ?: return
79-
feat.close()
80-
// Ensure removed in case of FailedModule
81-
_loaded.remove(key)
82-
loadOrder.remove(module)
88+
try {
89+
feat.close()
90+
} finally {
91+
// Ensure removed in case of FailedModule or error
92+
_loaded.remove(key)
93+
loadOrder.remove(module)
94+
}
8395
}
8496

8597
fun unloadAll() {
@@ -94,13 +106,18 @@ class DIScope(root: MutableDI.() -> Unit = {}) : DI.Scope, DI, AutoCloseable {
94106
fun DI.Scope.loadCatching(module: DI.Module): Result<DI> {
95107
return runCatching { load(module) }.onFailure {
96108
if (it is IllegalArgumentException) {
97-
logger.e { "Failed to load feature $module: ${it.message}" }
109+
logger.e { "Failed to load module ${module.name}: ${it.message}" }
98110
} else {
99-
logger.e(it) { "Failed to load feature $module" }
111+
logger.e(it) { "Failed to load module ${module.name}" }
100112
}
101113
}
102114
}
103115

104-
fun DI.Scope.loadAllCatching(vararg modules: DI.Module) {
105-
modules.forEach { loadCatching(it) }
116+
/**
117+
* Loads passed [modules] and their dependencies, printing error messages instead of throwing them when any fail to load.
118+
*
119+
* @return Whether all modules successfully loaded
120+
*/
121+
fun DI.Scope.loadAllCatching(vararg modules: DI.Module): LoadResult {
122+
return LoadResult(modules.associateWith { loadCatching(it) })
106123
}

core/src/commonMain/kotlin/com/mineinabyss/dependencies/FeatureDSL.kt renamed to core/src/commonMain/kotlin/com/mineinabyss/dependencies/DependenciesDSLMarker.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package com.mineinabyss.dependencies
22

33
@DslMarker
4-
annotation class FeatureDSLMarker
4+
annotation class DependenciesDSLMarker
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.mineinabyss.dependencies.exceptions
2+
3+
import com.mineinabyss.dependencies.DI
4+
5+
class LoadResult(
6+
val results: Map<DI.Module, Result<DI>>,
7+
) {
8+
val isSuccess = results.values.all { it.isSuccess }
9+
}

core/src/commonMain/kotlin/com/mineinabyss/dependencies/impl/MutableDIImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ class MutableDIImpl(
3333
return _injected[type] as? InjectedValue<T> ?: throw DIBindingException.of(type, null)
3434
}
3535

36-
3736
override fun singleModule(di: DI.Module): DI {
38-
val loaded = scope.load(di)
37+
val loaded = scope.loadCatching(di).getOrNull()
38+
if (loaded == null || loaded == FailedModule) throw IllegalArgumentException("Depends on module [${di.name}] which failed to load.")
3939
if (di in dependsOn) return loaded
4040
dependsOn += di
4141
loaded.addCloseable { this@MutableDIImpl.close() }

0 commit comments

Comments
 (0)