diff --git a/src/main/kotlin/com/beust/kobalt/api/IRunnerContributor.kt b/src/main/kotlin/com/beust/kobalt/api/IRunnerContributor.kt index a0f9befd..24b6e153 100644 --- a/src/main/kotlin/com/beust/kobalt/api/IRunnerContributor.kt +++ b/src/main/kotlin/com/beust/kobalt/api/IRunnerContributor.kt @@ -1,9 +1,10 @@ package com.beust.kobalt.api import com.beust.kobalt.TaskResult +import com.beust.kobalt.maven.IClasspathDependency /** - * Plugins that can run a project (task "run") should implement this interface. + * Plugins that can run a project (task "run" or "test") should implement this interface. */ interface IRunnerContributor : IContributor { companion object { @@ -23,7 +24,7 @@ interface IRunnerContributor : IContributor { /** * Run the project. */ - fun run(project: Project, context: KobaltContext) : TaskResult + fun run(project: Project, context: KobaltContext, classpath: List) : TaskResult } diff --git a/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt b/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt index d4cc447b..46c30284 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/GenericRunner.kt @@ -2,6 +2,9 @@ package com.beust.kobalt.internal import com.beust.kobalt.JavaInfo import com.beust.kobalt.SystemProperties +import com.beust.kobalt.TaskResult +import com.beust.kobalt.api.IRunnerContributor +import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Project import com.beust.kobalt.maven.IClasspathDependency import com.beust.kobalt.misc.KFiles @@ -9,11 +12,15 @@ import com.beust.kobalt.misc.log import java.io.File import java.net.URLClassLoader -abstract class GenericTestRunner(open val project: Project, open val classpath: List) { +abstract class GenericTestRunner : IRunnerContributor { abstract val mainClass: String - abstract val args: List + abstract fun args(project: Project, classpath: List) : List - protected fun findTestClasses(): List { + override fun run(project: Project, context: KobaltContext, classpath: List) + = TaskResult(runTests(project, context, classpath)) + + + protected fun findTestClasses(project: Project, classpath: List): List { val path = KFiles.joinDir(project.directory, project.buildDirectory, KFiles.TEST_CLASSES_DIR) val result = KFiles.findRecursively(File(path), arrayListOf(File(".")), { file -> file.endsWith(".class") @@ -39,9 +46,10 @@ abstract class GenericTestRunner(open val project: Project, open val classpath: /** * @return true if all the tests passed */ - fun runTests() : Boolean { + fun runTests(project: Project, context: KobaltContext, classpath: List) : Boolean { val jvm = JavaInfo.create(File(SystemProperties.javaBase)) val java = jvm.javaExecutable + val args = args(project, classpath) if (args.size > 0) { val allArgs = arrayListOf().apply { add(java!!.absolutePath) diff --git a/src/main/kotlin/com/beust/kobalt/internal/JUnitRunner.kt b/src/main/kotlin/com/beust/kobalt/internal/JUnitRunner.kt index 29c63b10..3c249a81 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/JUnitRunner.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/JUnitRunner.kt @@ -1,12 +1,19 @@ package com.beust.kobalt.internal +import com.beust.kobalt.api.IRunnerContributor +import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Project import com.beust.kobalt.maven.IClasspathDependency -public class JUnitRunner(override val project: Project, override val classpath: List) - : GenericTestRunner(project, classpath) { +public class JUnitRunner() : GenericTestRunner() { override val mainClass = "org.junit.runner.JUnitCore" - override val args = findTestClasses() + + override fun runAffinity(project: Project, context: KobaltContext) = + if (project.testDependencies.any { it.id.contains("junit")}) IRunnerContributor.DEFAULT_POSITIVE_AFFINITY + else 0 + + override fun args(project: Project, classpath: List) = findTestClasses(project, classpath) + } diff --git a/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt b/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt index 732ad3b7..a569cc2a 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/JvmCompilerPlugin.kt @@ -7,7 +7,9 @@ import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Project import com.beust.kobalt.api.annotation.ExportedProjectProperty import com.beust.kobalt.api.annotation.Task -import com.beust.kobalt.maven.* +import com.beust.kobalt.maven.DepFactory +import com.beust.kobalt.maven.DependencyManager +import com.beust.kobalt.maven.LocalRepo import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.log @@ -55,33 +57,18 @@ abstract class JvmCompilerPlugin @Inject constructor( addVariantTasks(project, "compile", runTask = { taskCompile(project) }) } - /** - * @return the test dependencies for this project, including the contributors. - */ - protected fun testDependencies(project: Project) : List { - val result = arrayListOf() - result.add(FileDependency(makeOutputDir(project).absolutePath)) - result.add(FileDependency(makeOutputTestDir(project).absolutePath)) - with(project) { - arrayListOf(compileDependencies, compileProvidedDependencies, testDependencies, - testProvidedDependencies).forEach { - result.addAll(dependencyManager.calculateDependencies(project, context, projects(), it)) - } - } - val result2 = dependencyManager.reorderDependencies(result) - return result2 - } - @Task(name = TASK_TEST, description = "Run the tests", runAfter = arrayOf("compile", "compileTest")) fun taskTest(project: Project) : TaskResult { lp(project, "Running tests") - val success = - if (project.testDependencies.any { it.id.contains("testng")} ) { - TestNgRunner(project, testDependencies(project)).runTests() - } else { - JUnitRunner(project, testDependencies(project)).runTests() - } - return TaskResult(success) + + val runContributor = context.pluginInfo.testRunnerContributors.maxBy { it.runAffinity(project, context)} + if (runContributor != null && runContributor.runAffinity(project, context) > 0) { + return runContributor.run(project, context, dependencyManager.testDependencies(project, context, + projects())) + } else { + log(2, "Couldn't find a test runner for project ${project.name}, not running any tests") + return TaskResult() + } } @Task(name = TASK_CLEAN, description = "Clean the project", runBefore = arrayOf("compile")) @@ -94,14 +81,6 @@ abstract class JvmCompilerPlugin @Inject constructor( return TaskResult() } - protected fun makeOutputDir(project: Project) : File = makeDir(project, KFiles.CLASSES_DIR) - - protected fun makeOutputTestDir(project: Project) : File = makeDir(project, KFiles.TEST_CLASSES_DIR) - - private fun makeDir(project: Project, suffix: String) : File { - return File(project.directory, project.buildDirectory + File.separator + suffix).apply { mkdirs() } - } - /** * Copy the resources from a source directory to the build one */ @@ -120,7 +99,7 @@ abstract class JvmCompilerPlugin @Inject constructor( if (sourceDirs.size > 0) { lp(project, "Copying $sourceSet resources") - val absOutputDir = File(KFiles.joinDir(project.directory, project.buildDirectory!!, outputDir)) + val absOutputDir = File(KFiles.joinDir(project.directory, project.buildDirectory, outputDir)) sourceDirs.map { File(project.directory, it) }.filter { it.exists() } .forEach { diff --git a/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt b/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt index 7d16141f..d84403b3 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt @@ -62,8 +62,11 @@ class KobaltPluginXml { @XmlElement(name = "build-directory-interceptors") @JvmField var buildDirectoryInterceptors: ClassNameXml? = null - @XmlElement(name = "run-contributors") @JvmField - var runContributors: ClassNameXml? = null + @XmlElement(name = "runner-contributors") @JvmField + var runnerContributors: ClassNameXml? = null + + @XmlElement(name = "test-runner-contributors") @JvmField + var testRunnerContributors: ClassNameXml? = null } class ContributorXml { @@ -91,7 +94,8 @@ class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) { val compilerInterceptors = arrayListOf() val sourceDirectoriesInterceptors = arrayListOf() val buildDirectoryInterceptors = arrayListOf() - val runContributors = arrayListOf() + val runnerContributors = arrayListOf() + val testRunnerContributors = arrayListOf() // Future contributors: // source files @@ -165,8 +169,11 @@ class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) { xml.buildDirectoryInterceptors?.className?.forEach { buildDirectoryInterceptors.add(factory.instanceOf(forName(it)) as IBuildDirectoryIncerceptor) } - xml.runContributors?.className?.forEach { - runContributors.add(factory.instanceOf(forName(it)) as IRunnerContributor) + xml.runnerContributors?.className?.forEach { + runnerContributors.add(factory.instanceOf(forName(it)) as IRunnerContributor) + } + xml.testRunnerContributors?.className?.forEach { + testRunnerContributors.add(factory.instanceOf(forName(it)) as IRunnerContributor) } } diff --git a/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt b/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt index 69177fc9..639f4164 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/TestNgRunner.kt @@ -1,16 +1,21 @@ package com.beust.kobalt.internal +import com.beust.kobalt.api.IRunnerContributor +import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Project import com.beust.kobalt.maven.IClasspathDependency import com.beust.kobalt.misc.KFiles import java.io.File -public class TestNgRunner(override val project: Project, override val classpath: List) - : GenericTestRunner(project, classpath) { +public class TestNgRunner() : GenericTestRunner() { + override val mainClass = "org.testng.TestNG" - override val args: List - get() = arrayListOf().apply { + override fun runAffinity(project: Project, context: KobaltContext) = + if (project.testDependencies.any { it.id.contains("testng")}) IRunnerContributor.DEFAULT_POSITIVE_AFFINITY + else 0 + + override fun args(project: Project, classpath: List) = arrayListOf().apply { if (project.testArgs.size > 0) { addAll(project.testArgs) } else { @@ -19,7 +24,7 @@ public class TestNgRunner(override val project: Project, override val classpath: add(testngXml.absolutePath) } else { add("-testclass") - addAll(findTestClasses()) + addAll(findTestClasses(project, classpath)) } } } diff --git a/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt b/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt index c3a9dbac..e2db13fd 100644 --- a/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt +++ b/src/main/kotlin/com/beust/kobalt/maven/DependencyManager.kt @@ -114,4 +114,42 @@ public class DependencyManager @Inject constructor(val executors: KobaltExecutor return result } + + /** + * @return the test dependencies for this project, including the contributors. + */ + fun dependencies(project: Project, context: KobaltContext, + projects: List) : List { + val result = arrayListOf() + result.add(FileDependency(KFiles.makeOutputDir(project).absolutePath)) + result.add(FileDependency(KFiles.makeOutputTestDir(project).absolutePath)) + with(project) { + arrayListOf(compileDependencies, compileProvidedDependencies).forEach { + result.addAll(calculateDependencies(project, context, projects, it)) + } + } + val result2 = reorderDependencies(result) + return result2 + } + + /** + * @return the test dependencies for this project, including the contributors. + */ + fun testDependencies(project: Project, context: KobaltContext, + projects: List) : List { + val result = arrayListOf() + result.add(FileDependency(KFiles.makeOutputDir(project).absolutePath)) + result.add(FileDependency(KFiles.makeOutputTestDir(project).absolutePath)) + with(project) { + arrayListOf(compileDependencies, compileProvidedDependencies, testDependencies, + testProvidedDependencies).forEach { + result.addAll(calculateDependencies(project, context, projects, it)) + } + } + val result2 = reorderDependencies(result) + return result2 + } + + + } diff --git a/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt b/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt index d1c4d00f..9bc2d03f 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/KFiles.kt @@ -2,6 +2,7 @@ package com.beust.kobalt.misc import com.beust.kobalt.SystemProperties import com.beust.kobalt.api.Kobalt +import com.beust.kobalt.api.Project import com.beust.kobalt.homeDir import com.beust.kobalt.internal.build.BuildFile import java.io.File @@ -239,6 +240,14 @@ class KFiles { } fun src(filePath: String): String = KFiles.joinDir(KOBALT_DIR, SRC, filePath) + + fun makeDir(project: Project, suffix: String) : File { + return File(project.directory, project.buildDirectory + File.separator + suffix).apply { mkdirs() } + } + + fun makeOutputDir(project: Project) : File = makeDir(project, KFiles.CLASSES_DIR) + + fun makeOutputTestDir(project: Project) : File = makeDir(project, KFiles.TEST_CLASSES_DIR) } fun findRecursively(directory: File, function: Function1): List { diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt index ea8ecbc4..2fb7c3cc 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt @@ -397,7 +397,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v return if (File(manifest).exists()) IRunnerContributor.DEFAULT_POSITIVE_AFFINITY else 0 } - override fun run(project: Project, context: KobaltContext): TaskResult { + override fun run(project: Project, context: KobaltContext, classpath: List): TaskResult { val manifest = AndroidFiles.manifest(project, context) FileInputStream(File(manifest)).use { ins -> // adb shell am start -n com.package.name/com.package.name.ActivityName diff --git a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt index 9ef1e7ab..0700e105 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt @@ -6,6 +6,7 @@ import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.internal.JvmCompilerPlugin import com.beust.kobalt.maven.DependencyManager +import com.beust.kobalt.maven.IClasspathDependency import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.RunCommand import com.beust.kobalt.misc.warn @@ -48,15 +49,17 @@ class ApplicationPlugin @Inject constructor(val executors: KobaltExecutors, @Task(name = "run", description = "Run the main class", runAfter = arrayOf("install")) fun taskRun(project: Project): TaskResult { - val runContributor = context.pluginInfo.runContributors.maxBy { it.runAffinity(project, context)} + val runContributor = context.pluginInfo.runnerContributors.maxBy { it.runAffinity(project, context)} if (runContributor != null && runContributor.runAffinity(project, context) > 0) { - return runContributor.run(project, context) + return runContributor.run(project, context, dependencyManager.dependencies(project, context, projects())) } else { warn("Couldn't find a runner for project ${project.name}") return TaskResult() } } + private fun projects() = context.pluginInfo.projectContributors.flatMap { it.projects() } + private fun isFatJar(packages: List, jarName: String): Boolean { packages.forEach { pc -> pc.jars.forEach { jar -> @@ -74,7 +77,7 @@ class ApplicationPlugin @Inject constructor(val executors: KobaltExecutors, return if (configurationFor(project) != null) IRunnerContributor.DEFAULT_POSITIVE_AFFINITY else 0 } - override fun run(project: Project, context: KobaltContext): TaskResult { + override fun run(project: Project, context: KobaltContext, classpath: List): TaskResult { var result = TaskResult() configurationFor(project)?.let { config -> if (config.mainClass != null) { diff --git a/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt index 662f822d..894c2cea 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/java/JavaPlugin.kt @@ -81,8 +81,9 @@ class JavaPlugin @Inject constructor( val result = if (sourceFiles.size > 0) { copyResources(project, JvmCompilerPlugin.SOURCE_SET_TEST) - val buildDir = makeOutputTestDir(project) - javaCompiler.compile(project, context, CompilerActionInfo(project.directory, testDependencies(project), + val buildDir = KFiles.makeOutputTestDir(project) + javaCompiler.compile(project, context, CompilerActionInfo(project.directory, + dependencyManager.testDependencies(project, context, projects()), sourceFiles, buildDir, compilerArgsFor(project))) } else { warn("Couldn't find any tests to compile") diff --git a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt index ddd2c43b..fa967508 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/kotlin/KotlinPlugin.kt @@ -69,9 +69,9 @@ class KotlinPlugin @Inject constructor( val result = if (sourceFiles.size > 0) { - compilePrivate(project, testDependencies(project), + compilePrivate(project, dependencyManager.testDependencies(project, context, projects()), sourceFiles, - makeOutputTestDir(project)) + KFiles.makeOutputTestDir(project)) } else { warn("Couldn't find any test files") TaskResult() diff --git a/src/main/resources/META-INF/kobalt-plugin.xml b/src/main/resources/META-INF/kobalt-plugin.xml index 4e11e200..e9435e2d 100644 --- a/src/main/resources/META-INF/kobalt-plugin.xml +++ b/src/main/resources/META-INF/kobalt-plugin.xml @@ -37,8 +37,12 @@ com.beust.kobalt.plugin.android.AndroidPlugin - + com.beust.kobalt.plugin.application.ApplicationPlugin com.beust.kobalt.plugin.android.AndroidPlugin - + + + com.beust.kobalt.internal.JUnitRunner + com.beust.kobalt.internal.TestNgRunner + \ No newline at end of file