From 12d2ecfa6294053de525597bf249f83c6e60eaa5 Mon Sep 17 00:00:00 2001 From: jvican Date: Fri, 20 Oct 2017 23:37:55 +0200 Subject: [PATCH] Enable parallel execution of scripted in the plugin The change to enable batched and parallel execution for scripted was done only for the scripted-sbt project. This pull request enables it for scripted-plugin, so that all sbt plugins in 1.x. can benefit from it. By default, it configures a number of parallel instances of 1 and batch execution is disabled. Users can change the number of parallel sbt hosts running scripted tests via the `scriptedParallelInstances` setting. In some plugins scripted tests', batch execution can cause issues because the first time `>` commands are executed they assume sbt starts up. This error can be fixed by doing `reload` before running the `>` command. Note that the current scripted plugin does not allow parallel execution in non-batched mode. --- .../src/main/scala/sbt/ScriptedPlugin.scala | 49 ++++++++++++------- .../main/scala/sbt/test/ScriptedTests.scala | 19 ++++++- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala b/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala index 4788e0186..a7bfdc907 100644 --- a/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala +++ b/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala @@ -26,6 +26,11 @@ object ScriptedPlugin extends AutoPlugin { val scriptedBufferLog = SettingKey[Boolean]("scripted-buffer-log") val scriptedClasspath = TaskKey[PathFinder]("scripted-classpath") val scriptedTests = TaskKey[AnyRef]("scripted-tests") + val scriptedBatchExecution = + settingKey[Boolean]("Enables or disables batch execution for scripted.") + val scriptedParallelInstances = + settingKey[Int]( + "Configures the number of scripted instances for parallel testing, only used in batch mode.") val scriptedRun = TaskKey[Method]("scripted-run") val scriptedLaunchOpts = SettingKey[Seq[String]]( "scripted-launch-opts", @@ -56,6 +61,8 @@ object ScriptedPlugin extends AutoPlugin { scriptedBufferLog := true, scriptedClasspath := getJars(ScriptedConf).value, scriptedTests := scriptedTestsTask.value, + scriptedParallelInstances := 1, + scriptedBatchExecution := false, scriptedRun := scriptedRunTask.value, scriptedDependencies := { def use[A](@deprecated("unused", "") x: A*): Unit = () // avoid unused warnings @@ -73,15 +80,18 @@ object ScriptedPlugin extends AutoPlugin { ModuleUtilities.getObject("sbt.test.ScriptedTests", loader) } - def scriptedRunTask: Initialize[Task[Method]] = Def.task( - scriptedTests.value.getClass.getMethod("run", - classOf[File], - classOf[Boolean], - classOf[Array[String]], - classOf[File], - classOf[Array[String]], - classOf[java.util.List[File]]) - ) + private[this] val fCls = classOf[File] + private[this] val bCls = classOf[Boolean] + private[this] val asCls = classOf[Array[String]] + private[this] val lfCls = classOf[java.util.List[File]] + private[this] val iCls = classOf[Integer] + + def scriptedRunTask: Initialize[Task[Method]] = Def.taskDyn { + val clazz = scriptedTests.value.getClass + if (scriptedBatchExecution.value) + Def.task(clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls)) + else Def.task(clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls)) + } import DefaultParsers._ case class ScriptedTestPage(page: Int, total: Int) @@ -134,15 +144,18 @@ object ScriptedPlugin extends AutoPlugin { val args = scriptedParser(sbtTestDirectory.value).parsed scriptedDependencies.value try { - scriptedRun.value.invoke( - scriptedTests.value, - sbtTestDirectory.value, - scriptedBufferLog.value: java.lang.Boolean, - args.toArray, - sbtLauncher.value, - scriptedLaunchOpts.value.toArray, - new java.util.ArrayList() - ) + val method = scriptedRun.value + val scriptedInstance = scriptedTests.value + val dir = sbtTestDirectory.value + val log: java.lang.Boolean = scriptedBufferLog.value + val launcher = sbtLauncher.value + val opts = scriptedLaunchOpts.value.toArray + val empty = new java.util.ArrayList() + val instances: Integer = scriptedParallelInstances.value + + if (scriptedBatchExecution.value) + method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty, instances) + else method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty) } catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause } } diff --git a/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala b/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala index 3e2798300..7af336a26 100644 --- a/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala +++ b/scripted/sbt/src/main/scala/sbt/test/ScriptedTests.scala @@ -324,8 +324,8 @@ class ScriptedRunner { prescripted.add(f); () }) //new FullLogger(Logger.xlog2Log(log))) } - // This is called by sbt-scripted 0.13.x (the sbt host) when cross-compiling to sbt 0.13.x and 1.0.x - // See https://github.com/sbt/sbt/issues/3245 + + // This is called by sbt-scripted 0.13.x and 1.x (see https://github.com/sbt/sbt/issues/3245) def run(resourceBaseDirectory: File, bufferLog: Boolean, tests: Array[String], @@ -374,6 +374,21 @@ class ScriptedRunner { 1) } + // This is used by sbt-scripted sbt 1.x + def runInParallel( + baseDir: File, + bufferLog: Boolean, + tests: Array[String], + bootProps: File, + launchOpts: Array[String], + prescripted: java.util.List[File], + instances: Integer + ): Unit = { + val logger = ConsoleLogger() + val addTestFile = (f: File) => { prescripted.add(f); () } + runInParallel(baseDir, bufferLog, tests, logger, bootProps, launchOpts, addTestFile, instances) + } + def runInParallel( resourceBaseDirectory: File, bufferLog: Boolean,