Use custom classloader for scripted tests

We had previously used reflection to load the bridge class, but
continued using sbt's default classloader. This was problematic because
the metabuild could have a different classpath from that required by the
scripted tests.

Bonus: scalafmt

Fixes: #4514
This commit is contained in:
Ethan Atkins 2019-01-30 17:25:00 -08:00
parent dc870e19b1
commit b2c9d3e2cf
1 changed files with 35 additions and 26 deletions

View File

@ -17,8 +17,10 @@ object LocalScriptedPlugin extends AutoPlugin {
trait ScriptedKeys { trait ScriptedKeys {
val publishAll = taskKey[Unit]("") val publishAll = taskKey[Unit]("")
val publishLocalBinAll = taskKey[Unit]("") val publishLocalBinAll = taskKey[Unit]("")
val scriptedUnpublished = inputKey[Unit]("Execute scripted without publishing sbt first. " + val scriptedUnpublished = inputKey[Unit](
"Saves you some time when only your test has changed") "Execute scripted without publishing sbt first. " +
"Saves you some time when only your test has changed"
)
val scriptedSource = settingKey[File]("") val scriptedSource = settingKey[File]("")
val scriptedPrescripted = taskKey[File => Unit]("") val scriptedPrescripted = taskKey[File => Unit]("")
} }
@ -107,33 +109,40 @@ object Scripted {
// Interface to cross class loader // Interface to cross class loader
type SbtScriptedRunner = { type SbtScriptedRunner = {
def runInParallel( def runInParallel(
resourceBaseDirectory: File, resourceBaseDirectory: File,
bufferLog: Boolean, bufferLog: Boolean,
tests: Array[String], tests: Array[String],
bootProperties: File, bootProperties: File,
launchOpts: Array[String], launchOpts: Array[String],
prescripted: java.util.List[File], prescripted: java.util.List[File],
): Unit ): Unit
} }
val bridge = bridgeClass.getDeclaredConstructor().newInstance().asInstanceOf[SbtScriptedRunner] val initLoader = Thread.currentThread.getContextClassLoader
try { try {
// Using java.util.List to encode File => Unit. Thread.currentThread.setContextClassLoader(loader)
val callback = new java.util.AbstractList[File] { val bridge =
override def add(x: File): Boolean = { prescripted(x); false } bridgeClass.getDeclaredConstructor().newInstance().asInstanceOf[SbtScriptedRunner]
def get(x: Int): sbt.File = ???
def size(): Int = 0 try {
} // Using java.util.List to encode File => Unit.
import scala.language.reflectiveCalls val callback = new java.util.AbstractList[File] {
bridge.runInParallel( override def add(x: File): Boolean = { prescripted(x); false }
sourcePath, def get(x: Int): sbt.File = ???
bufferLog, def size(): Int = 0
args.toArray, }
launcher, import scala.language.reflectiveCalls
launchOpts.toArray, bridge.runInParallel(
callback, sourcePath,
) bufferLog,
} catch { case ite: InvocationTargetException => throw ite.getCause } args.toArray,
launcher,
launchOpts.toArray,
callback,
)
} catch { case ite: InvocationTargetException => throw ite.getCause }
} finally {
Thread.currentThread.setContextClassLoader(initLoader)
}
} }
} }