mirror of https://github.com/sbt/sbt.git
Merge pull request #5615 from eed3si9n/wip/scripted
Resurrect launcher-based scripted for SbtPlugin
This commit is contained in:
commit
c07de68cf5
|
|
@ -4,3 +4,6 @@ $ copy-file changes/Success.scala src/sbt-test/group/demo/changes/Success.scala
|
||||||
$ copy-file changes/fail src/sbt-test/group/fail/test
|
$ copy-file changes/fail src/sbt-test/group/fail/test
|
||||||
> scripted group/demo
|
> scripted group/demo
|
||||||
-> scripted group/fail
|
-> scripted group/fail
|
||||||
|
|
||||||
|
> set scriptedBatchExecution := true
|
||||||
|
> scripted group/demo
|
||||||
|
|
@ -12,10 +12,36 @@ import xsbt.IPC
|
||||||
|
|
||||||
import scala.sys.process.{ BasicIO, Process }
|
import scala.sys.process.{ BasicIO, Process }
|
||||||
|
|
||||||
|
private[sbt] sealed trait RemoteSbtCreatorProp
|
||||||
|
private[sbt] object RemoteSbtCreatorProp {
|
||||||
|
case class LauncherBased(launcherJar: File) extends RemoteSbtCreatorProp
|
||||||
|
case class RunFromSourceBased(scalaVersion: String, sbtVersion: String, classpath: Seq[File])
|
||||||
|
extends RemoteSbtCreatorProp
|
||||||
|
}
|
||||||
|
|
||||||
abstract class RemoteSbtCreator private[sbt] {
|
abstract class RemoteSbtCreator private[sbt] {
|
||||||
def newRemote(server: IPC.Server): Process
|
def newRemote(server: IPC.Server): Process
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class LauncherBasedRemoteSbtCreator(
|
||||||
|
directory: File,
|
||||||
|
launcher: File,
|
||||||
|
log: Logger,
|
||||||
|
launchOpts: Seq[String] = Nil,
|
||||||
|
) extends RemoteSbtCreator {
|
||||||
|
def newRemote(server: IPC.Server) = {
|
||||||
|
val launcherJar = launcher.getAbsolutePath
|
||||||
|
val globalBase = "-Dsbt.global.base=" + (new File(directory, "global")).getAbsolutePath
|
||||||
|
val args = List("<" + server.port)
|
||||||
|
val cmd = "java" :: launchOpts.toList ::: globalBase :: "-jar" :: launcherJar :: args ::: Nil
|
||||||
|
val io = BasicIO(false, log).withInput(_.close())
|
||||||
|
val p = Process(cmd, directory) run (io)
|
||||||
|
val thread = new Thread() { override def run() = { p.exitValue(); server.close() } }
|
||||||
|
thread.start()
|
||||||
|
p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class RunFromSourceBasedRemoteSbtCreator(
|
final class RunFromSourceBasedRemoteSbtCreator(
|
||||||
directory: File,
|
directory: File,
|
||||||
log: Logger,
|
log: Logger,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import java.util.concurrent.ForkJoinPool
|
||||||
|
|
||||||
import sbt.internal.io.Resources
|
import sbt.internal.io.Resources
|
||||||
import sbt.internal.scripted._
|
import sbt.internal.scripted._
|
||||||
|
import RemoteSbtCreatorProp._
|
||||||
|
|
||||||
import scala.collection.parallel.ForkJoinTaskSupport
|
import scala.collection.parallel.ForkJoinTaskSupport
|
||||||
import scala.collection.{ GenSeq, mutable }
|
import scala.collection.{ GenSeq, mutable }
|
||||||
|
|
@ -40,9 +41,7 @@ final class ScriptedTests(
|
||||||
name: String,
|
name: String,
|
||||||
prescripted: File => Unit,
|
prescripted: File => Unit,
|
||||||
log: Logger,
|
log: Logger,
|
||||||
scalaVersion: String,
|
prop: RemoteSbtCreatorProp
|
||||||
sbtVersion: String,
|
|
||||||
classpath: Seq[File]
|
|
||||||
): Seq[TestRunner] = {
|
): Seq[TestRunner] = {
|
||||||
|
|
||||||
// Test group and names may be file filters (like '*')
|
// Test group and names may be file filters (like '*')
|
||||||
|
|
@ -60,7 +59,7 @@ final class ScriptedTests(
|
||||||
val buffer = new BufferedLogger(new FullLogger(log))
|
val buffer = new BufferedLogger(new FullLogger(log))
|
||||||
val singleTestRunner = () => {
|
val singleTestRunner = () => {
|
||||||
val handlers =
|
val handlers =
|
||||||
createScriptedHandlers(testDirectory, buffer, scalaVersion, sbtVersion, classpath)
|
createScriptedHandlers(testDirectory, buffer, prop)
|
||||||
val runner = new BatchScriptRunner
|
val runner = new BatchScriptRunner
|
||||||
val states = new mutable.HashMap[StatementHandler, StatementHandler#State]()
|
val states = new mutable.HashMap[StatementHandler, StatementHandler#State]()
|
||||||
try commonRunTest(label, testDirectory, prescripted, handlers, runner, states, buffer)
|
try commonRunTest(label, testDirectory, prescripted, handlers, runner, states, buffer)
|
||||||
|
|
@ -76,20 +75,23 @@ final class ScriptedTests(
|
||||||
private def createScriptedHandlers(
|
private def createScriptedHandlers(
|
||||||
testDir: File,
|
testDir: File,
|
||||||
buffered: Logger,
|
buffered: Logger,
|
||||||
scalaVersion: String,
|
prop: RemoteSbtCreatorProp
|
||||||
sbtVersion: String,
|
|
||||||
classpath: Seq[File]
|
|
||||||
): Map[Char, StatementHandler] = {
|
): Map[Char, StatementHandler] = {
|
||||||
val fileHandler = new FileCommands(testDir)
|
val fileHandler = new FileCommands(testDir)
|
||||||
val remoteSbtCreator =
|
val remoteSbtCreator =
|
||||||
new RunFromSourceBasedRemoteSbtCreator(
|
prop match {
|
||||||
testDir,
|
case LauncherBased(launcherJar) =>
|
||||||
buffered,
|
new LauncherBasedRemoteSbtCreator(testDir, launcherJar, buffered, launchOpts)
|
||||||
launchOpts,
|
case RunFromSourceBased(scalaVersion, sbtVersion, classpath) =>
|
||||||
scalaVersion,
|
new RunFromSourceBasedRemoteSbtCreator(
|
||||||
sbtVersion,
|
testDir,
|
||||||
classpath
|
buffered,
|
||||||
)
|
launchOpts,
|
||||||
|
scalaVersion,
|
||||||
|
sbtVersion,
|
||||||
|
classpath
|
||||||
|
)
|
||||||
|
}
|
||||||
val sbtHandler = new SbtHandler(remoteSbtCreator)
|
val sbtHandler = new SbtHandler(remoteSbtCreator)
|
||||||
Map('$' -> fileHandler, '>' -> sbtHandler, '#' -> CommentHandler)
|
Map('$' -> fileHandler, '>' -> sbtHandler, '#' -> CommentHandler)
|
||||||
}
|
}
|
||||||
|
|
@ -99,10 +101,8 @@ final class ScriptedTests(
|
||||||
testGroupAndNames: Seq[(String, String)],
|
testGroupAndNames: Seq[(String, String)],
|
||||||
prescripted: File => Unit,
|
prescripted: File => Unit,
|
||||||
sbtInstances: Int,
|
sbtInstances: Int,
|
||||||
log: Logger,
|
prop: RemoteSbtCreatorProp,
|
||||||
scalaVersion: String,
|
log: Logger
|
||||||
sbtVersion: String,
|
|
||||||
classpath: Seq[File]
|
|
||||||
): Seq[TestRunner] = {
|
): Seq[TestRunner] = {
|
||||||
// Test group and names may be file filters (like '*')
|
// Test group and names may be file filters (like '*')
|
||||||
val groupAndNameDirs = {
|
val groupAndNameDirs = {
|
||||||
|
|
@ -145,7 +145,7 @@ final class ScriptedTests(
|
||||||
.grouped(batchSize)
|
.grouped(batchSize)
|
||||||
.map { batch => () =>
|
.map { batch => () =>
|
||||||
IO.withTemporaryDirectory {
|
IO.withTemporaryDirectory {
|
||||||
runBatchedTests(batch, _, prescripted, log, scalaVersion, sbtVersion, classpath)
|
runBatchedTests(batch, _, prescripted, prop, log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toList
|
.toList
|
||||||
|
|
@ -223,15 +223,13 @@ final class ScriptedTests(
|
||||||
groupedTests: Seq[((String, String), File)],
|
groupedTests: Seq[((String, String), File)],
|
||||||
tempTestDir: File,
|
tempTestDir: File,
|
||||||
preHook: File => Unit,
|
preHook: File => Unit,
|
||||||
log: Logger,
|
prop: RemoteSbtCreatorProp,
|
||||||
scalaVersion: String,
|
log: Logger
|
||||||
sbtVersion: String,
|
|
||||||
classpath: Seq[File]
|
|
||||||
): Seq[Option[String]] = {
|
): Seq[Option[String]] = {
|
||||||
|
|
||||||
val runner = new BatchScriptRunner
|
val runner = new BatchScriptRunner
|
||||||
val buffer = new BufferedLogger(new FullLogger(log))
|
val buffer = new BufferedLogger(new FullLogger(log))
|
||||||
val handlers = createScriptedHandlers(tempTestDir, buffer, scalaVersion, sbtVersion, classpath)
|
val handlers = createScriptedHandlers(tempTestDir, buffer, prop)
|
||||||
val states = new BatchScriptRunner.States
|
val states = new BatchScriptRunner.States
|
||||||
val seqHandlers = handlers.values.toList
|
val seqHandlers = handlers.values.toList
|
||||||
runner.initStates(states, seqHandlers)
|
runner.initStates(states, seqHandlers)
|
||||||
|
|
@ -401,9 +399,90 @@ object ScriptedTests extends ScriptedRunner {
|
||||||
|
|
||||||
/** Runner for `scripted`. Not be confused with ScriptRunner. */
|
/** Runner for `scripted`. Not be confused with ScriptRunner. */
|
||||||
class ScriptedRunner {
|
class ScriptedRunner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the entry point used by sbt-scripted 0.13.18.
|
||||||
|
* Removing this method will break sbt plugin cross building.
|
||||||
|
* See https://github.com/sbt/sbt/issues/3245
|
||||||
|
* See https://github.com/sbt/sbt/blob/v0.13.18/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala#L39
|
||||||
|
*/
|
||||||
|
def run(
|
||||||
|
resourceBaseDirectory: File,
|
||||||
|
bufferLog: Boolean,
|
||||||
|
tests: Array[String],
|
||||||
|
launcherJar: File,
|
||||||
|
launchOpts: Array[String],
|
||||||
|
): Unit = {
|
||||||
|
val logger = TestConsoleLogger()
|
||||||
|
runInParallel(
|
||||||
|
resourceBaseDirectory,
|
||||||
|
bufferLog,
|
||||||
|
tests,
|
||||||
|
logger,
|
||||||
|
launchOpts,
|
||||||
|
prescripted = new java.util.ArrayList[File],
|
||||||
|
LauncherBased(launcherJar),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the entry point used by SbtPlugin in sbt 1.2.x, 1.3.x, 1.4.x etc.
|
||||||
|
* Removing this method will break scripted and sbt plugin cross building.
|
||||||
|
* See https://github.com/sbt/sbt/issues/3245
|
||||||
|
* See https://github.com/sbt/sbt/blob/v1.2.8/main/src/main/scala/sbt/ScriptedPlugin.scala#L109-L113
|
||||||
|
*/
|
||||||
|
def run(
|
||||||
|
resourceBaseDirectory: File,
|
||||||
|
bufferLog: Boolean,
|
||||||
|
tests: Array[String],
|
||||||
|
launcherJar: File,
|
||||||
|
launchOpts: Array[String],
|
||||||
|
prescripted: java.util.List[File],
|
||||||
|
): Unit = {
|
||||||
|
val logger = TestConsoleLogger()
|
||||||
|
runInParallel(
|
||||||
|
resourceBaseDirectory,
|
||||||
|
bufferLog,
|
||||||
|
tests,
|
||||||
|
logger,
|
||||||
|
launchOpts,
|
||||||
|
prescripted,
|
||||||
|
LauncherBased(launcherJar),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the entry point used by SbtPlugin in sbt 1.2.x, 1.3.x, 1.4.x etc.
|
||||||
|
* Removing this method will break scripted and sbt plugin cross building.
|
||||||
|
* See https://github.com/sbt/sbt/issues/3245
|
||||||
|
* See https://github.com/sbt/sbt/blob/v1.2.8/main/src/main/scala/sbt/ScriptedPlugin.scala#L109-L113
|
||||||
|
*/
|
||||||
|
def runInParallel(
|
||||||
|
resourceBaseDirectory: File,
|
||||||
|
bufferLog: Boolean,
|
||||||
|
tests: Array[String],
|
||||||
|
launcherJar: File,
|
||||||
|
launchOpts: Array[String],
|
||||||
|
prescripted: java.util.List[File],
|
||||||
|
instance: Int,
|
||||||
|
): Unit = {
|
||||||
|
val logger = TestConsoleLogger()
|
||||||
|
runInParallel(
|
||||||
|
resourceBaseDirectory,
|
||||||
|
bufferLog,
|
||||||
|
tests,
|
||||||
|
logger,
|
||||||
|
launchOpts,
|
||||||
|
prescripted,
|
||||||
|
LauncherBased(launcherJar),
|
||||||
|
instance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// This is called by project/Scripted.scala
|
// This is called by project/Scripted.scala
|
||||||
// Using java.util.List[File] to encode File => Unit
|
// Using java.util.List[File] to encode File => Unit
|
||||||
// This is used by sbt-scripted sbt 1.x
|
|
||||||
def runInParallel(
|
def runInParallel(
|
||||||
baseDir: File,
|
baseDir: File,
|
||||||
bufferLog: Boolean,
|
bufferLog: Boolean,
|
||||||
|
|
@ -415,23 +494,42 @@ class ScriptedRunner {
|
||||||
sbtVersion: String,
|
sbtVersion: String,
|
||||||
classpath: Array[File],
|
classpath: Array[File],
|
||||||
instances: Int
|
instances: Int
|
||||||
|
): Unit =
|
||||||
|
runInParallel(
|
||||||
|
baseDir,
|
||||||
|
bufferLog,
|
||||||
|
tests,
|
||||||
|
logger,
|
||||||
|
launchOpts,
|
||||||
|
prescripted,
|
||||||
|
RunFromSourceBased(scalaVersion, sbtVersion, classpath),
|
||||||
|
instances
|
||||||
|
)
|
||||||
|
|
||||||
|
private[sbt] def runInParallel(
|
||||||
|
baseDir: File,
|
||||||
|
bufferLog: Boolean,
|
||||||
|
tests: Array[String],
|
||||||
|
logger: Logger,
|
||||||
|
launchOpts: Array[String],
|
||||||
|
prescripted: java.util.List[File],
|
||||||
|
prop: RemoteSbtCreatorProp,
|
||||||
|
instances: Int
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val addTestFile = (f: File) => { prescripted.add(f); () }
|
val addTestFile = (f: File) => { prescripted.add(f); () }
|
||||||
val runner = new ScriptedTests(baseDir, bufferLog, launchOpts)
|
val runner = new ScriptedTests(baseDir, bufferLog, launchOpts)
|
||||||
|
val sbtVersion =
|
||||||
|
prop match {
|
||||||
|
case LauncherBased(launcherJar) =>
|
||||||
|
launcherJar.getName.dropWhile(!_.isDigit).dropRight(".jar".length)
|
||||||
|
case RunFromSourceBased(_, sbtVersion, _) => sbtVersion
|
||||||
|
}
|
||||||
val accept = isTestCompatible(baseDir, sbtVersion) _
|
val accept = isTestCompatible(baseDir, sbtVersion) _
|
||||||
// The scripted tests mapped to the inputs that the user wrote after `scripted`.
|
// The scripted tests mapped to the inputs that the user wrote after `scripted`.
|
||||||
val scriptedTests =
|
val scriptedTests =
|
||||||
get(tests, baseDir, accept, logger).map(st => (st.group, st.name))
|
get(tests, baseDir, accept, logger).map(st => (st.group, st.name))
|
||||||
val scriptedRunners =
|
val scriptedRunners =
|
||||||
runner.batchScriptedRunner(
|
runner.batchScriptedRunner(scriptedTests, addTestFile, instances, prop, logger)
|
||||||
scriptedTests,
|
|
||||||
addTestFile,
|
|
||||||
instances,
|
|
||||||
logger,
|
|
||||||
scalaVersion,
|
|
||||||
sbtVersion,
|
|
||||||
classpath
|
|
||||||
)
|
|
||||||
val parallelRunners = scriptedRunners.toParArray
|
val parallelRunners = scriptedRunners.toParArray
|
||||||
parallelRunners.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(instances))
|
parallelRunners.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(instances))
|
||||||
runAll(parallelRunners)
|
runAll(parallelRunners)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue