Skip to content

Commit b4a5694

Browse files
committed
Restarter: Add properties to exclude directories from restarter classpath
1 parent 1c9864e commit b4a5694

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

BotCommands-restarter/src/main/kotlin/dev/freya02/botcommands/internal/restart/Restarter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Restarter private constructor(
3030
val thread = Thread.currentThread()
3131

3232
appClassLoader = thread.contextClassLoader
33-
appClasspathUrls = AppClasspath.getPaths().map { it.toUri().toURL() }
33+
appClasspathUrls = AppClasspath.paths.map { it.toUri().toURL() }
3434

3535
mainClassName = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
3636
.walk { stream -> stream.filter { it.methodName == "main" }.toList().last() }
Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,60 @@
11
package dev.freya02.botcommands.internal.restart.utils
22

3+
import io.github.oshai.kotlinlogging.KotlinLogging
34
import java.io.File
45
import java.lang.management.ManagementFactory
56
import java.nio.file.Path
7+
import java.util.*
68
import kotlin.io.path.Path
79
import kotlin.io.path.isDirectory
810

11+
private val logger = KotlinLogging.logger { }
12+
913
internal object AppClasspath {
1014

11-
fun getPaths(): List<Path> {
12-
return ManagementFactory.getRuntimeMXBean().classPath
15+
val paths: List<Path>
16+
17+
init {
18+
val resources = Thread.currentThread().contextClassLoader.getResources("META-INF/BotCommands-restarter.properties")
19+
20+
val excludePatterns = buildSet {
21+
resources.iterator().forEach { url ->
22+
val properties = url.openStream().use { inputStream ->
23+
val prop = Properties()
24+
prop.load(inputStream)
25+
prop
26+
}
27+
28+
// Load "restart.exclude.[patternName]=[pattern]"
29+
properties.forEach { key, value ->
30+
if (key !is String) return@forEach
31+
if (value !is String) return@forEach
32+
33+
val patternName = key.substringAfter("restart.exclude.", missingDelimiterValue = "")
34+
if (patternName.isNotBlank() && value.isNotBlank()) {
35+
add(value.toRegex())
36+
}
37+
}
38+
}
39+
}
40+
41+
logger.debug { "Restart classpath exclude patterns: $excludePatterns" }
42+
43+
val (includedPaths, excludedPaths) = ManagementFactory.getRuntimeMXBean().classPath
1344
.split(File.pathSeparator)
1445
.map(::Path)
1546
.filter { it.isDirectory() }
16-
.filter { it.endsWith("test-classes") } // TODO add proper configurable filters
47+
.partition { path ->
48+
val uri = path.toUri().toString()
49+
if (excludePatterns.any { it.containsMatchIn(uri) })
50+
return@partition false // Exclude
51+
52+
true // Include
53+
}
54+
55+
logger.info { "Restart classpath includes (+ JARs) $includedPaths" }
56+
logger.info { "Restart classpath excludes $excludedPaths" }
57+
58+
paths = includedPaths
1759
}
18-
}
60+
}

BotCommands-restarter/src/main/kotlin/dev/freya02/botcommands/internal/restart/watcher/ClasspathWatcher.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ internal class ClasspathWatcher private constructor(
4141
private val snapshots: MutableMap<Path, SourceFiles> = hashMapOf()
4242

4343
init {
44-
AppClasspath.getPaths().forEach { classRoot ->
44+
AppClasspath.paths.forEach { classRoot ->
4545
require(classRoot.isDirectory())
4646

4747
logger.trace { "Creating snapshot of ${classRoot.absolutePathString()}" }
@@ -179,4 +179,4 @@ internal class ClasspathWatcher private constructor(
179179

180180
private fun Path.takeSnapshot(): SourceFiles = walkFiles().associate { (it, attrs) ->
181181
it.relativeTo(this).pathString to SourceFile(attrs.lastModifiedTime().toInstant())
182-
}.let(::SourceFiles)
182+
}.let(::SourceFiles)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This file is for BotCommands's own tests
2+
# It is in the production resources so it can be applied regardless of in which module it is used
3+
# This principally excludes source sets which are used by the restarter, to avoid classpath issues
4+
5+
restart.exclude.jda-cache-prod=BotCommands-jda-cache/build/classes/(?:kotlin|java)/main
6+
restart.exclude.jda-cache-prod-res=BotCommands-jda-cache/build/resources/main
7+
8+
restart.exclude.restarter-prod=BotCommands-restarter/build/classes/(?:kotlin|java)/main
9+
restart.exclude.restarter-prod-res=BotCommands-restarter/build/resources/main
10+
11+
# Have to use a negative lookbehind as the main module doesn't have a dedicated directory
12+
restart.exclude.core-prod=(?<!BotCommands-jda-cache/)build/classes/(?:kotlin|java)/main
13+
restart.exclude.core-prod-res=(?<!BotCommands-jda-cache/)build/resources/main

0 commit comments

Comments
 (0)