mirror of https://github.com/sbt/sbt.git
Merge pull request #6673 from kxbmap/scripted-java-home
Make javaHome that forks scripted tests configurable
This commit is contained in:
commit
adc217000b
|
|
@ -8,7 +8,6 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import java.lang.reflect.Method
|
||||
|
||||
import sbt.Def._
|
||||
import sbt.Keys._
|
||||
|
|
@ -47,7 +46,7 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
val scriptedParallelInstances = settingKey[Int](
|
||||
"Configures the number of scripted instances for parallel testing, only used in batch mode."
|
||||
)
|
||||
val scriptedRun = taskKey[Method]("")
|
||||
val scriptedRun = taskKey[ScriptedRun]("")
|
||||
val scriptedLaunchOpts =
|
||||
settingKey[Seq[String]]("options to pass to jvm launching scripted tasks")
|
||||
val scriptedDependencies = taskKey[Unit]("")
|
||||
|
|
@ -114,21 +113,8 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
private[sbt] def scriptedRunTask: Initialize[Task[Method]] = Def.taskDyn {
|
||||
val fCls = classOf[File]
|
||||
val bCls = classOf[Boolean]
|
||||
val asCls = classOf[Array[String]]
|
||||
val lfCls = classOf[java.util.List[File]]
|
||||
val iCls = classOf[Int]
|
||||
|
||||
val clazz = scriptedTests.value.getClass
|
||||
val method =
|
||||
if (scriptedBatchExecution.value)
|
||||
clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls)
|
||||
else
|
||||
clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls)
|
||||
|
||||
Def.task(method)
|
||||
private[sbt] def scriptedRunTask: Initialize[Task[ScriptedRun]] = Def.task {
|
||||
ScriptedRun.of(scriptedTests.value, scriptedBatchExecution.value)
|
||||
}
|
||||
|
||||
private[sbt] final case class ScriptedTestPage(page: Int, total: Int)
|
||||
|
|
@ -191,21 +177,16 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
private[sbt] def scriptedTask: Initialize[InputTask[Unit]] = Def.inputTask {
|
||||
val args = scriptedParser(sbtTestDirectory.value).parsed
|
||||
Def.unit(scriptedDependencies.value)
|
||||
try {
|
||||
val method = scriptedRun.value
|
||||
val scriptedInstance = scriptedTests.value
|
||||
val dir = sbtTestDirectory.value
|
||||
val log = Boolean box scriptedBufferLog.value
|
||||
val launcher = sbtLauncher.value
|
||||
val opts = scriptedLaunchOpts.value.toArray
|
||||
val empty = new java.util.ArrayList[File]()
|
||||
val instances = Int box 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 }
|
||||
scriptedRun.value.run(
|
||||
sbtTestDirectory.value,
|
||||
scriptedBufferLog.value,
|
||||
args,
|
||||
sbtLauncher.value,
|
||||
Fork.javaCommand((scripted / javaHome).value, "java").getAbsolutePath,
|
||||
scriptedLaunchOpts.value,
|
||||
new java.util.ArrayList[File](),
|
||||
scriptedParallelInstances.value
|
||||
)
|
||||
}
|
||||
|
||||
private[this] def getJars(config: Configuration): Initialize[Task[PathFinder]] = Def.task {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import java.lang.reflect.Method
|
||||
import scala.annotation.unused
|
||||
|
||||
sealed trait ScriptedRun {
|
||||
final def run(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Seq[String],
|
||||
launcherJar: File,
|
||||
javaCommand: String,
|
||||
launchOpts: Seq[String],
|
||||
prescripted: java.util.List[File],
|
||||
instances: Int,
|
||||
): Unit = {
|
||||
try {
|
||||
invoke(
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests.toArray,
|
||||
launcherJar,
|
||||
javaCommand,
|
||||
launchOpts.toArray,
|
||||
prescripted,
|
||||
instances,
|
||||
)
|
||||
()
|
||||
} catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause }
|
||||
}
|
||||
|
||||
protected def invoke(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: java.lang.Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
instances: java.lang.Integer,
|
||||
): AnyRef
|
||||
|
||||
}
|
||||
|
||||
object ScriptedRun {
|
||||
|
||||
def of(scriptedTests: AnyRef, batchExecution: Boolean): ScriptedRun = {
|
||||
val fCls = classOf[File]
|
||||
val bCls = classOf[Boolean]
|
||||
val asCls = classOf[Array[String]]
|
||||
val sCls = classOf[String]
|
||||
val lfCls = classOf[java.util.List[File]]
|
||||
val iCls = classOf[Int]
|
||||
|
||||
val clazz = scriptedTests.getClass
|
||||
if (batchExecution)
|
||||
try new RunInParallelV2(
|
||||
scriptedTests,
|
||||
clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, sCls, asCls, lfCls, iCls)
|
||||
)
|
||||
catch {
|
||||
case _: NoSuchMethodException =>
|
||||
new RunInParallelV1(
|
||||
scriptedTests,
|
||||
clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls)
|
||||
)
|
||||
}
|
||||
else
|
||||
try new RunV2(
|
||||
scriptedTests,
|
||||
clazz.getMethod("run", fCls, bCls, asCls, fCls, sCls, asCls, lfCls)
|
||||
)
|
||||
catch {
|
||||
case _: NoSuchMethodException =>
|
||||
new RunV1(scriptedTests, clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls))
|
||||
}
|
||||
}
|
||||
|
||||
private class RunV1(scriptedTests: AnyRef, run: Method) extends ScriptedRun {
|
||||
override protected def invoke(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: java.lang.Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
@unused javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
@unused instances: java.lang.Integer,
|
||||
): AnyRef =
|
||||
run.invoke(
|
||||
scriptedTests,
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
launcherJar,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
)
|
||||
}
|
||||
|
||||
private class RunInParallelV1(scriptedTests: AnyRef, runInParallel: Method) extends ScriptedRun {
|
||||
override protected def invoke(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: java.lang.Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
@unused javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
instances: Integer,
|
||||
): AnyRef =
|
||||
runInParallel.invoke(
|
||||
scriptedTests,
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
launcherJar,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
instances,
|
||||
)
|
||||
}
|
||||
|
||||
private class RunV2(scriptedTests: AnyRef, run: Method) extends ScriptedRun {
|
||||
override protected def invoke(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: java.lang.Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
@unused instances: java.lang.Integer,
|
||||
): AnyRef =
|
||||
run.invoke(
|
||||
scriptedTests,
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
launcherJar,
|
||||
javaCommand,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
)
|
||||
}
|
||||
|
||||
private class RunInParallelV2(scriptedTests: AnyRef, runInParallel: Method) extends ScriptedRun {
|
||||
override protected def invoke(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: java.lang.Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
instances: Integer,
|
||||
): AnyRef =
|
||||
runInParallel.invoke(
|
||||
scriptedTests,
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
launcherJar,
|
||||
javaCommand,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
instances,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
[@kxbmap]: https://github.com/kxbmap
|
||||
|
||||
[#6673]: https://github.com/sbt/sbt/pull/6673
|
||||
|
||||
### Improvements
|
||||
|
||||
- Make javaHome that forks scripted tests configurable. [#6673][] by [@kxbmap][]
|
||||
- Normally scripted tests are forked using the JVM that is running sbt. If set `scripted / javaHome`, forked using it.
|
||||
- Or use `java++` command before scripted.
|
||||
|
||||
### Fixes with compatibility implications
|
||||
|
||||
- Change type of `scriptedRun` task key from `TaskKey[java.lang.reflect.Method]` to `TaskKey[sbt.ScriptedRun]`
|
||||
- `sbt.ScriptedRun` is a new interface for hiding substance of scripted invocation.
|
||||
|
|
@ -114,7 +114,7 @@ object Fork {
|
|||
(classpathOption, newOptions)
|
||||
}
|
||||
|
||||
private def javaCommand(javaHome: Option[File], name: String): File = {
|
||||
private[sbt] def javaCommand(javaHome: Option[File], name: String): File = {
|
||||
val home = javaHome.getOrElse(new File(System.getProperty("java.home")))
|
||||
new File(new File(home, "bin"), name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
lazy val scriptedJavaVersion = settingKey[Long]("")
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.enablePlugins(SbtPlugin)
|
||||
.settings(
|
||||
scriptedJavaVersion := {
|
||||
val versions = discoveredJavaHomes.value
|
||||
.map { case (jv, _) => JavaVersion(jv).numbers }
|
||||
.collect {
|
||||
case Vector(1L, ver, _*) => ver
|
||||
case Vector(ver, _*) => ver
|
||||
}
|
||||
if (versions.isEmpty) sys.error("No Java versions discovered")
|
||||
else versions.max
|
||||
},
|
||||
commands += Command.command("setJavaVersion") { state =>
|
||||
val extracted = Project.extract(state)
|
||||
import extracted._
|
||||
val jv = (currentRef / scriptedJavaVersion).get(structure.data).get
|
||||
s"java++ $jv!" :: state
|
||||
},
|
||||
scriptedLaunchOpts += s"-Dscripted.java.version=${scriptedJavaVersion.value}"
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
lazy val check = taskKey[Unit]("check")
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
check := {
|
||||
val version = sys.props("java.version").stripPrefix("1.").takeWhile(_.isDigit)
|
||||
val expected = sys.props("scripted.java.version")
|
||||
assert(
|
||||
version == expected,
|
||||
s"Expected Java version is '$expected', but actual is '$version'"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
@ -0,0 +1 @@
|
|||
> check
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
$ copy-file changes/build.sbt src/sbt-test/group/name/build.sbt
|
||||
$ copy-file changes/test src/sbt-test/group/name/test
|
||||
|
||||
> setJavaVersion
|
||||
> scripted
|
||||
|
|
@ -27,14 +27,22 @@ final class LauncherBasedRemoteSbtCreator(
|
|||
directory: File,
|
||||
launcher: File,
|
||||
log: Logger,
|
||||
launchOpts: Seq[String] = Nil,
|
||||
javaCommand: String,
|
||||
launchOpts: Seq[String],
|
||||
) extends RemoteSbtCreator {
|
||||
def newRemote(server: IPC.Server) = {
|
||||
def this(
|
||||
directory: File,
|
||||
launcher: File,
|
||||
log: Logger,
|
||||
launchOpts: Seq[String] = Nil,
|
||||
) = this(directory, launcher, log, "java", launchOpts)
|
||||
|
||||
def newRemote(server: IPC.Server): Process = {
|
||||
val launcherJar = launcher.getAbsolutePath
|
||||
val globalBase = "-Dsbt.global.base=" + (new File(directory, "global")).getAbsolutePath
|
||||
val scripted = "-Dsbt.scripted=true"
|
||||
val args = List("<" + server.port)
|
||||
val cmd = "java" :: launchOpts.toList ::: globalBase :: scripted :: "-jar" :: launcherJar :: args ::: Nil
|
||||
val cmd = javaCommand :: launchOpts.toList ::: globalBase :: scripted :: "-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() } }
|
||||
|
|
@ -46,11 +54,21 @@ final class LauncherBasedRemoteSbtCreator(
|
|||
final class RunFromSourceBasedRemoteSbtCreator(
|
||||
directory: File,
|
||||
log: Logger,
|
||||
launchOpts: Seq[String] = Nil,
|
||||
javaCommand: String,
|
||||
launchOpts: Seq[String],
|
||||
scalaVersion: String,
|
||||
sbtVersion: String,
|
||||
classpath: Seq[File],
|
||||
) extends RemoteSbtCreator {
|
||||
def this(
|
||||
directory: File,
|
||||
log: Logger,
|
||||
launchOpts: Seq[String] = Nil,
|
||||
scalaVersion: String,
|
||||
sbtVersion: String,
|
||||
classpath: Seq[File],
|
||||
) = this(directory, log, "java", launchOpts, scalaVersion, sbtVersion, classpath)
|
||||
|
||||
def newRemote(server: IPC.Server): Process = {
|
||||
val globalBase = "-Dsbt.global.base=" + new File(directory, "global").getAbsolutePath
|
||||
val scripted = "-Dsbt.scripted=true"
|
||||
|
|
@ -58,7 +76,7 @@ final class RunFromSourceBasedRemoteSbtCreator(
|
|||
val cpString = classpath.mkString(java.io.File.pathSeparator)
|
||||
val args =
|
||||
List(mainClassName, directory.toString, scalaVersion, sbtVersion, cpString, "<" + server.port)
|
||||
val cmd = "java" :: launchOpts.toList ::: globalBase :: scripted :: "-cp" :: cpString :: args ::: Nil
|
||||
val cmd = javaCommand :: launchOpts.toList ::: globalBase :: scripted :: "-cp" :: cpString :: 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() } }
|
||||
|
|
|
|||
|
|
@ -26,8 +26,15 @@ import scala.util.control.NonFatal
|
|||
final class ScriptedTests(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
javaCommand: String,
|
||||
launchOpts: Seq[String],
|
||||
) {
|
||||
def this(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
launchOpts: Seq[String],
|
||||
) = this(resourceBaseDirectory, bufferLog, "java", launchOpts)
|
||||
|
||||
import ScriptedTests.TestRunner
|
||||
|
||||
private val testResources = new Resources(resourceBaseDirectory)
|
||||
|
|
@ -80,11 +87,12 @@ final class ScriptedTests(
|
|||
val remoteSbtCreator =
|
||||
prop match {
|
||||
case LauncherBased(launcherJar) =>
|
||||
new LauncherBasedRemoteSbtCreator(testDir, launcherJar, buffered, launchOpts)
|
||||
new LauncherBasedRemoteSbtCreator(testDir, launcherJar, buffered, javaCommand, launchOpts)
|
||||
case RunFromSourceBased(scalaVersion, sbtVersion, classpath) =>
|
||||
new RunFromSourceBasedRemoteSbtCreator(
|
||||
testDir,
|
||||
buffered,
|
||||
javaCommand,
|
||||
launchOpts,
|
||||
scalaVersion,
|
||||
sbtVersion,
|
||||
|
|
@ -383,6 +391,7 @@ class ScriptedRunner {
|
|||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand = "java",
|
||||
launchOpts,
|
||||
prescripted = new java.util.ArrayList[File],
|
||||
LauncherBased(launcherJar),
|
||||
|
|
@ -411,6 +420,36 @@ class ScriptedRunner {
|
|||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand = "java",
|
||||
launchOpts,
|
||||
prescripted,
|
||||
LauncherBased(launcherJar),
|
||||
Int.MaxValue,
|
||||
parallelExecution = false,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the entry point used by SbtPlugin in sbt 2.0.x etc.
|
||||
* Removing this method will break scripted and sbt plugin cross building.
|
||||
* See https://github.com/sbt/sbt/issues/3245
|
||||
*/
|
||||
def run(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
): Unit = {
|
||||
val logger = TestConsoleLogger()
|
||||
run(
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
LauncherBased(launcherJar),
|
||||
|
|
@ -440,6 +479,36 @@ class ScriptedRunner {
|
|||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand = "java",
|
||||
launchOpts,
|
||||
prescripted,
|
||||
LauncherBased(launcherJar),
|
||||
instance,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the entry point used by SbtPlugin in sbt 2.0.x etc.
|
||||
* Removing this method will break scripted and sbt plugin cross building.
|
||||
* See https://github.com/sbt/sbt/issues/3245
|
||||
*/
|
||||
def runInParallel(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
launcherJar: File,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
instance: Int,
|
||||
): Unit = {
|
||||
val logger = TestConsoleLogger()
|
||||
runInParallel(
|
||||
resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
LauncherBased(launcherJar),
|
||||
|
|
@ -466,6 +535,7 @@ class ScriptedRunner {
|
|||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand = "java",
|
||||
launchOpts,
|
||||
prescripted,
|
||||
RunFromSourceBased(scalaVersion, sbtVersion, classpath),
|
||||
|
|
@ -477,11 +547,24 @@ class ScriptedRunner {
|
|||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
logger: Logger,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
prop: RemoteSbtCreatorProp,
|
||||
instances: Int
|
||||
) = run(baseDir, bufferLog, tests, logger, launchOpts, prescripted, prop, instances, true)
|
||||
): Unit =
|
||||
run(
|
||||
baseDir,
|
||||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
javaCommand,
|
||||
launchOpts,
|
||||
prescripted,
|
||||
prop,
|
||||
instances,
|
||||
parallelExecution = true
|
||||
)
|
||||
|
||||
@nowarn
|
||||
private[this] def run(
|
||||
|
|
@ -489,6 +572,7 @@ class ScriptedRunner {
|
|||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
logger: Logger,
|
||||
javaCommand: String,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
prop: RemoteSbtCreatorProp,
|
||||
|
|
@ -496,7 +580,7 @@ class ScriptedRunner {
|
|||
parallelExecution: Boolean,
|
||||
): Unit = {
|
||||
val addTestFile = (f: File) => { prescripted.add(f); () }
|
||||
val runner = new ScriptedTests(baseDir, bufferLog, launchOpts)
|
||||
val runner = new ScriptedTests(baseDir, bufferLog, javaCommand, launchOpts)
|
||||
val sbtVersion =
|
||||
prop match {
|
||||
case LauncherBased(launcherJar) =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue