diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-05-04 20:31:48 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-05-05 10:03:18 +0200 |
| commit | 6466d5e1b8da4582434f02dff2ab56e8f736ef85 (patch) | |
| tree | e8c8e6b96c7abdd80fa0a3198da5776488cd06fe /opendc-harness | |
| parent | 4a8b32d288ba3ee986ecef7933fa77554d34e762 (diff) | |
harness: Extend Harness CLI with classpath options
This change adds support for appending libraries to the classpath when
searching for experiments to run using the OpenDC Harness command line
interface.
Diffstat (limited to 'opendc-harness')
8 files changed, 68 insertions, 14 deletions
diff --git a/opendc-harness/opendc-harness-cli/build.gradle.kts b/opendc-harness/opendc-harness-cli/build.gradle.kts index 26f02f55..3e169e2a 100644 --- a/opendc-harness/opendc-harness-cli/build.gradle.kts +++ b/opendc-harness/opendc-harness-cli/build.gradle.kts @@ -25,6 +25,12 @@ description = "Command line interface of OpenDC Harness" /* Build configuration */ plugins { `kotlin-library-conventions` + application +} + +application { + applicationName = "opendc-harness" + mainClass.set("org.opendc.harness.runner.cli.ConsoleRunnerKt") } dependencies { diff --git a/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt b/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt index c59e623c..82adb2fd 100644 --- a/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt +++ b/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt @@ -23,16 +23,23 @@ package org.opendc.harness.runner.cli import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.arguments.multiple +import com.github.ajalt.clikt.parameters.arguments.unique import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.multiple import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.options.unique +import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.int import mu.KotlinLogging +import org.junit.platform.commons.util.ClassLoaderUtils import org.opendc.harness.engine.ExperimentEngineLauncher import org.opendc.harness.engine.discovery.DiscoveryProvider import org.opendc.harness.engine.discovery.DiscoveryRequest import org.opendc.harness.engine.discovery.DiscoverySelector import org.opendc.harness.engine.scheduler.ThreadPoolExperimentScheduler +import java.net.URLClassLoader /** * The logger for this experiment runner. @@ -53,23 +60,38 @@ public class ConsoleRunner : CliktCommand(name = "opendc-harness") { /** * The selected experiments to run by name. */ - private val experiments by option("-e", "--experiments", help = "Names of experiments to explore") - .multiple(emptyList()) + private val experiments by argument(help = "Experiments to explore") + .multiple() + .unique() /** * The maximum number of worker threads to use. */ private val parallelism by option("-p", "--parallelism", help = "Maximum number of concurrent simulation runs") .int() - .default(Runtime.getRuntime().availableProcessors()) + .default(Runtime.getRuntime().availableProcessors() - 1) + + /** + * Additional classpath entries to load. + */ + private val additionalClasspathEntries by option("--class-path", help = "Additional classpath entries to load") + .file(mustExist = true) + .multiple() + .unique() override fun run() { logger.info { "Starting OpenDC Console Experiment Runner" } - val discovery = DiscoveryProvider.createComposite() + val classLoader = createClassLoader() + // TODO: Add way to specify class loader for scheduler + Thread.currentThread().contextClassLoader = classLoader + + val discovery = DiscoveryProvider.createComposite(classLoader) val experiments = discovery.discover( DiscoveryRequest( - selectors = experiments.map { DiscoverySelector.Name(it) } + selectors = experiments.flatMap { + listOf(DiscoverySelector.Name(it), DiscoverySelector.Meta("class.name", it)) + } ) ) @@ -91,6 +113,30 @@ public class ConsoleRunner : CliktCommand(name = "opendc-harness") { logger.info { "Finished all experiments. Exiting." } } + + /** + * Create a [ClassLoader] that is used to load the + */ + private fun createClassLoader(): ClassLoader { + val parent = ClassLoaderUtils.getDefaultClassLoader() + + if (additionalClasspathEntries.isNotEmpty()) { + val urls = additionalClasspathEntries.flatMap { file -> + if (file.isDirectory) { + file.walk() + .filter { it.extension == "jar" } + .map { it.toURI().toURL() } + .toList() + } else { + listOf(file.toURI().toURL()) + } + } + + return URLClassLoader.newInstance(urls.toTypedArray(), parent) + } + + return parent + } } /** diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt index 204de3fc..c4b420c5 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt @@ -40,7 +40,7 @@ public interface DiscoveryProvider { /** * Factory method for creating a new [Discovery] instance. */ - public fun create(): Discovery + public fun create(classLoader: ClassLoader): Discovery public companion object { /** @@ -58,8 +58,8 @@ public interface DiscoveryProvider { /** * Obtain a composite [Discovery] that combines the results of all available providers. */ - public fun createComposite(): Discovery { - return CompositeDiscovery(providers) + public fun createComposite(classLoader: ClassLoader): Discovery { + return CompositeDiscovery(classLoader, providers) } } } diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt index 8ebc485a..726125a8 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt @@ -32,11 +32,11 @@ import org.opendc.harness.engine.discovery.DiscoveryRequest /** * A composite [Discovery] instance that combines the results of multiple delegate instances. */ -internal class CompositeDiscovery(providers: Iterable<DiscoveryProvider>) : Discovery { +internal class CompositeDiscovery(classLoader: ClassLoader, providers: Iterable<DiscoveryProvider>) : Discovery { /** * The [Discovery] instances to delegate to. */ - private val delegates = providers.map { it.create() } + private val delegates = providers.map { it.create(classLoader) } @OptIn(FlowPreview::class) override fun discover(request: DiscoveryRequest): Flow<ExperimentDefinition> { diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt index 20708230..3fa3fe35 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt @@ -36,7 +36,7 @@ import org.opendc.harness.engine.discovery.DiscoverySelector /** * A [Discovery] implementation that discovers [Experiment] instances on the classpath. */ -internal class DslDiscovery : Discovery { +internal class DslDiscovery(private val classLoader: ClassLoader) : Discovery { /* * Lazily memoize the results of the classpath scan. */ @@ -84,6 +84,7 @@ internal class DslDiscovery : Discovery { */ private fun scan(): ScanResult { return ClassGraph() + .addClassLoader(classLoader) .enableClassInfo() .enableExternalClasses() .ignoreClassVisibility() diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt index 987bc889..6a9bd599 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt @@ -32,5 +32,5 @@ import org.opendc.harness.engine.discovery.DiscoveryProvider public class DslDiscoveryProvider : DiscoveryProvider { override val id: String = "dsl" - override fun create(): Discovery = DslDiscovery() + override fun create(classLoader: ClassLoader): Discovery = DslDiscovery(classLoader) } diff --git a/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt b/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt index 6f2989db..6955f7c5 100644 --- a/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt +++ b/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt @@ -50,7 +50,7 @@ internal class EngineTest { @Test fun discovery() { runBlocking { - val discovery = DiscoveryProvider.findById("dsl")?.create() + val discovery = DiscoveryProvider.findById("dsl")?.create(Thread.currentThread().contextClassLoader) assertNotNull(discovery) val res = mutableListOf<ExperimentDefinition>() discovery?.discover(DiscoveryRequest())?.toList(res) diff --git a/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt b/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt index ab7367b8..7fc97f6d 100644 --- a/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt +++ b/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt @@ -25,6 +25,7 @@ package org.opendc.harness.runner.junit5 import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import mu.KotlinLogging +import org.junit.platform.commons.util.ClassLoaderUtils import org.junit.platform.engine.* import org.junit.platform.engine.discovery.ClassNameFilter import org.junit.platform.engine.discovery.ClassSelector @@ -63,7 +64,7 @@ public class OpenDCTestEngine : TestEngine { val classNames = request.getSelectorsByType(ClassSelector::class.java).map { DiscoverySelector.Meta("class.name", it.className) } val classNameFilters = request.getFiltersByType(ClassNameFilter::class.java).map { DiscoveryFilter.Name(it.toPredicate()) } - val discovery = DiscoveryProvider.createComposite() + val discovery = DiscoveryProvider.createComposite(ClassLoaderUtils.getDefaultClassLoader()) val definitions = discovery.discover(DiscoveryRequest(classNames, classNameFilters)) return ExperimentEngineDescriptor(uniqueId, definitions) |
