diff --git a/main-actions/src/main/scala/sbt/ForkTests.scala b/main-actions/src/main/scala/sbt/ForkTests.scala index 80694ce30..ba707d5a2 100755 --- a/main-actions/src/main/scala/sbt/ForkTests.scala +++ b/main-actions/src/main/scala/sbt/ForkTests.scala @@ -18,7 +18,7 @@ import sbt.util.Logger import sbt.ConcurrentRestrictions.Tag import sbt.protocol.testing._ import sbt.internal.util.Util.{ AnyOps, none } -import sbt.internal.util.{ RunningProcesses, Terminal => UTerminal } +import sbt.internal.util.{ Terminal => UTerminal } private[sbt] object ForkTests { def apply( @@ -158,13 +158,7 @@ private[sbt] object ForkTests { classOf[ForkMain].getCanonicalName, server.getLocalPort.toString ) - val p = Fork.java.fork(fork, options) - RunningProcesses.add(p) - val ec = try p.exitValue() - finally { - if (p.isAlive()) p.destroy() - RunningProcesses.remove(p) - } + val ec = Fork.java(fork, options) val result = if (ec != 0) TestOutput( diff --git a/run/src/main/scala/sbt/Fork.scala b/run/src/main/scala/sbt/Fork.scala index b2cb449d0..c7e74c0f7 100644 --- a/run/src/main/scala/sbt/Fork.scala +++ b/run/src/main/scala/sbt/Fork.scala @@ -9,10 +9,9 @@ package sbt import java.io.File import java.lang.ProcessBuilder.Redirect - import scala.sys.process.Process import OutputStrategy._ -import sbt.internal.util.Util +import sbt.internal.util.{ RunningProcesses, Util } import Util.{ AnyOps, none } import java.lang.{ ProcessBuilder => JProcessBuilder } @@ -31,7 +30,15 @@ final class Fork(val commandName: String, val runnerClass: Option[String]) { * It is configured according to `config`. * If `runnerClass` is defined for this Fork instance, it is prepended to `arguments` to define the arguments passed to the forked command. */ - def apply(config: ForkOptions, arguments: Seq[String]): Int = fork(config, arguments).exitValue() + def apply(config: ForkOptions, arguments: Seq[String]): Int = { + val p = fork(config, arguments) + RunningProcesses.add(p) + try p.exitValue() + finally { + if (p.isAlive()) p.destroy() + RunningProcesses.remove(p) + } + } /** * Forks the configured process and returns a `Process` that can be used to wait for completion or to terminate the forked process. diff --git a/run/src/main/scala/sbt/Run.scala b/run/src/main/scala/sbt/Run.scala index 4df43f707..637c1473a 100644 --- a/run/src/main/scala/sbt/Run.scala +++ b/run/src/main/scala/sbt/Run.scala @@ -10,7 +10,6 @@ package sbt import java.io.File import java.lang.reflect.Method import java.lang.reflect.Modifier.{ isPublic, isStatic } - import sbt.internal.inc.ScalaInstance import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil } import sbt.internal.util.MessageOnlyException @@ -34,29 +33,40 @@ class ForkRun(config: ForkOptions) extends ScalaRun { s"""Nonzero exit code returned from $label: $exitCode""".stripMargin ) ) - val process = fork(mainClass, classpath, options, log) - def cancel() = { - log.warn("Run canceled.") - process.destroy() - 1 + + log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}") + val c = configLogged(log) + val scalaOpts = scalaOptions(mainClass, classpath, options) + val exitCode = try Fork.java(c, scalaOpts) + catch { + case _: InterruptedException => + log.warn("Run canceled.") + 1 } - val exitCode = try process.exitValue() - catch { case _: InterruptedException => cancel() } processExitCode(exitCode, "runner") } def fork(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger): Process = { log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}") - val scalaOptions = classpathOption(classpath) ::: mainClass :: options.toList - val configLogged = - if (config.outputStrategy.isDefined) config - else config.withOutputStrategy(OutputStrategy.LoggedOutput(log)) + val c = configLogged(log) + val scalaOpts = scalaOptions(mainClass, classpath, options) + // fork with Java because Scala introduces an extra class loader (#702) - Fork.java.fork(configLogged, scalaOptions) + Fork.java.fork(c, scalaOpts) } - private def classpathOption(classpath: Seq[File]) = - "-classpath" :: Path.makeString(classpath) :: Nil + + private def configLogged(log: Logger): ForkOptions = { + if (config.outputStrategy.isDefined) config + else config.withOutputStrategy(OutputStrategy.LoggedOutput(log)) + } + + private def scalaOptions( + mainClass: String, + classpath: Seq[File], + options: Seq[String] + ): Seq[String] = + "-classpath" :: Path.makeString(classpath) :: mainClass :: options.toList } class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolean)