mirror of https://github.com/sbt/sbt.git
Port run
This commit is contained in:
parent
4b928f16c2
commit
320b025993
|
|
@ -21,16 +21,18 @@ import java.util.Locale
|
||||||
/**
|
/**
|
||||||
* Represents a command that can be forked.
|
* Represents a command that can be forked.
|
||||||
*
|
*
|
||||||
* @param commandName The java-like binary to fork. This is expected to exist in bin/ of the Java home directory.
|
* @param commandName
|
||||||
* @param runnerClass If Some, this will be prepended to the `arguments` passed to the `apply` or `fork` methods.
|
* The java-like binary to fork. This is expected to exist in bin/ of the Java home directory.
|
||||||
|
* @param runnerClass
|
||||||
|
* If Some, this will be prepended to the `arguments` passed to the `apply` or `fork` methods.
|
||||||
*/
|
*/
|
||||||
final class Fork(val commandName: String, val runnerClass: Option[String]) {
|
final class Fork(val commandName: String, val runnerClass: Option[String]) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forks the configured process, waits for it to complete, and returns the exit code.
|
* Forks the configured process, waits for it to complete, and returns the exit code. The command
|
||||||
* The command executed is the `commandName` defined for this Fork instance.
|
* executed is the `commandName` defined for this Fork instance. It is configured according to
|
||||||
* It is configured according to `config`.
|
* `config`. If `runnerClass` is defined for this Fork instance, it is prepended to `arguments` to
|
||||||
* If `runnerClass` is defined for this Fork instance, it is prepended to `arguments` to define the arguments passed to the forked command.
|
* define the arguments passed to the forked command.
|
||||||
*/
|
*/
|
||||||
def apply(config: ForkOptions, arguments: Seq[String]): Int = {
|
def apply(config: ForkOptions, arguments: Seq[String]): Int = {
|
||||||
val p = fork(config, arguments)
|
val p = fork(config, arguments)
|
||||||
|
|
@ -43,10 +45,11 @@ final class Fork(val commandName: String, val runnerClass: Option[String]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forks the configured process and returns a `Process` that can be used to wait for completion or to terminate the forked process.
|
* Forks the configured process and returns a `Process` that can be used to wait for completion or
|
||||||
* The command executed is the `commandName` defined for this Fork instance.
|
* to terminate the forked process. The command executed is the `commandName` defined for this
|
||||||
* It is configured according to `config`.
|
* Fork instance. It is configured according to `config`. If `runnerClass` is defined for this
|
||||||
* If `runnerClass` is defined for this Fork instance, it is prepended to `arguments` to define the arguments passed to the forked command.
|
* Fork instance, it is prepended to `arguments` to define the arguments passed to the forked
|
||||||
|
* command.
|
||||||
*/
|
*/
|
||||||
def fork(config: ForkOptions, arguments: Seq[String]): Process = {
|
def fork(config: ForkOptions, arguments: Seq[String]): Process = {
|
||||||
import config.{ envVars => env, _ }
|
import config.{ envVars => env, _ }
|
||||||
|
|
@ -108,7 +111,10 @@ object Fork {
|
||||||
private[this] def isClasspathOption(s: String) =
|
private[this] def isClasspathOption(s: String) =
|
||||||
s == ClasspathOptionLong || s == ClasspathOptionShort
|
s == ClasspathOptionLong || s == ClasspathOptionShort
|
||||||
|
|
||||||
/** Maximum length of classpath string before passing the classpath in an environment variable instead of an option. */
|
/**
|
||||||
|
* Maximum length of classpath string before passing the classpath in an environment variable
|
||||||
|
* instead of an option.
|
||||||
|
*/
|
||||||
private[this] val MaxConcatenatedOptionLength = 5000
|
private[this] val MaxConcatenatedOptionLength = 5000
|
||||||
|
|
||||||
private def fitClasspath(options: Seq[String]): (Option[String], Seq[String]) =
|
private def fitClasspath(options: Seq[String]): (Option[String], Seq[String]) =
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,21 @@ package sbt
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
/** Configures where the standard output and error streams from a forked process go.*/
|
/** Configures where the standard output and error streams from a forked process go. */
|
||||||
sealed abstract class OutputStrategy
|
sealed abstract class OutputStrategy
|
||||||
|
|
||||||
object OutputStrategy {
|
object OutputStrategy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the forked standard output to go to standard output of this process and
|
* Configures the forked standard output to go to standard output of this process and for the
|
||||||
* for the forked standard error to go to the standard error of this process.
|
* forked standard error to go to the standard error of this process.
|
||||||
*/
|
*/
|
||||||
case object StdoutOutput extends OutputStrategy
|
case object StdoutOutput extends OutputStrategy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs the forked standard output at the `info` level and the forked standard error at
|
* Logs the forked standard output at the `info` level and the forked standard error at the
|
||||||
* the `error` level. The output is buffered until the process completes, at which point
|
* `error` level. The output is buffered until the process completes, at which point the logger
|
||||||
* the logger flushes it (to the screen, for example).
|
* flushes it (to the screen, for example).
|
||||||
*/
|
*/
|
||||||
final class BufferedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
|
final class BufferedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
|
||||||
override def equals(o: Any): Boolean = o match {
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
|
@ -49,8 +49,8 @@ object OutputStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs the forked standard output at the `info` level and the forked standard error at
|
* Logs the forked standard output at the `info` level and the forked standard error at the
|
||||||
* the `error` level.
|
* `error` level.
|
||||||
*/
|
*/
|
||||||
final class LoggedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
|
final class LoggedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
|
||||||
override def equals(o: Any): Boolean = o match {
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
|
@ -75,8 +75,8 @@ object OutputStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the forked standard output to be sent to `output` and the forked standard error
|
* Configures the forked standard output to be sent to `output` and the forked standard error to
|
||||||
* to be sent to the standard error of this process.
|
* be sent to the standard error of this process.
|
||||||
*/
|
*/
|
||||||
final class CustomOutput private (val output: OutputStream)
|
final class CustomOutput private (val output: OutputStream)
|
||||||
extends OutputStrategy
|
extends OutputStrategy
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ class ForkRun(config: ForkOptions) extends ScalaRun {
|
||||||
log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}")
|
log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}")
|
||||||
val c = configLogged(log)
|
val c = configLogged(log)
|
||||||
val scalaOpts = scalaOptions(mainClass, classpath, options)
|
val scalaOpts = scalaOptions(mainClass, classpath, options)
|
||||||
val exitCode = try Fork.java(c, scalaOpts)
|
val exitCode =
|
||||||
|
try Fork.java(c, scalaOpts)
|
||||||
catch {
|
catch {
|
||||||
case _: InterruptedException =>
|
case _: InterruptedException =>
|
||||||
log.warn("Run canceled.")
|
log.warn("Run canceled.")
|
||||||
|
|
@ -110,8 +111,7 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def directExecute(): Try[Unit] =
|
def directExecute(): Try[Unit] =
|
||||||
Try(execute()) recover {
|
Try(execute()) recover { case NonFatal(e) =>
|
||||||
case NonFatal(e) =>
|
|
||||||
// bgStop should not print out stack trace
|
// bgStop should not print out stack trace
|
||||||
// log.trace(e)
|
// log.trace(e)
|
||||||
throw e
|
throw e
|
||||||
|
|
@ -121,7 +121,7 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea
|
||||||
else directExecute()
|
else directExecute()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Runs the class 'mainClass' using the given classpath and options using the scala runner.*/
|
/** Runs the class 'mainClass' using the given classpath and options using the scala runner. */
|
||||||
def run(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger): Try[Unit] = {
|
def run(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger): Try[Unit] = {
|
||||||
val loader = newLoader(classpath)
|
val loader = newLoader(classpath)
|
||||||
try runWithLoader(loader, classpath, mainClass, options, log)
|
try runWithLoader(loader, classpath, mainClass, options, log)
|
||||||
|
|
@ -171,10 +171,10 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This module is an interface to starting the scala interpreter or runner.*/
|
/** This module is an interface to starting the scala interpreter or runner. */
|
||||||
object Run {
|
object Run {
|
||||||
def run(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger)(
|
def run(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger)(implicit
|
||||||
implicit runner: ScalaRun
|
runner: ScalaRun
|
||||||
) =
|
) =
|
||||||
runner.run(mainClass, classpath, options, log)
|
runner.run(mainClass, classpath, options, log)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,7 @@ object SelectMainClass {
|
||||||
private def toInt(s: String, size: Int): Option[Int] =
|
private def toInt(s: String, size: Int): Option[Int] =
|
||||||
try {
|
try {
|
||||||
val i = s.toInt
|
val i = s.toInt
|
||||||
if (i > 0 && i <= size)
|
if (i > 0 && i <= size) (i - 1).some
|
||||||
(i - 1).some
|
|
||||||
else {
|
else {
|
||||||
println("Number out of range: was " + i + ", expected number between 1 and " + size)
|
println("Number out of range: was " + i + ", expected number between 1 and " + size)
|
||||||
none
|
none
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,29 @@ package sbt
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an approximation to isolated execution within a single JVM.
|
* Provides an approximation to isolated execution within a single JVM. System.exit calls are
|
||||||
* System.exit calls are trapped to prevent the JVM from terminating. This is useful for executing
|
* trapped to prevent the JVM from terminating. This is useful for executing user code that may call
|
||||||
* user code that may call System.exit, but actually exiting is undesirable.
|
* System.exit, but actually exiting is undesirable.
|
||||||
*
|
*
|
||||||
* Exit is simulated by disposing all top-level windows and interrupting user-started threads.
|
* Exit is simulated by disposing all top-level windows and interrupting user-started threads.
|
||||||
* Threads are not stopped and shutdown hooks are not called. It is
|
* Threads are not stopped and shutdown hooks are not called. It is therefore inappropriate to use
|
||||||
* therefore inappropriate to use this with code that requires shutdown hooks, creates threads that
|
* this with code that requires shutdown hooks, creates threads that do not terminate, or if
|
||||||
* do not terminate, or if concurrent AWT applications are run.
|
* concurrent AWT applications are run. This category of code should only be called by forking a new
|
||||||
* This category of code should only be called by forking a new JVM.
|
* JVM.
|
||||||
*/
|
*/
|
||||||
object TrapExit {
|
object TrapExit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run `execute` in a managed context, using `log` for debugging messages.
|
* Run `execute` in a managed context, using `log` for debugging messages. `installManager` must
|
||||||
* `installManager` must be called before calling this method.
|
* be called before calling this method.
|
||||||
*/
|
*/
|
||||||
@deprecated("TrapExit feature is removed; just call the function instead", "1.6.0")
|
@deprecated("TrapExit feature is removed; just call the function instead", "1.6.0")
|
||||||
def apply(execute: => Unit, log: Logger): Int =
|
def apply(execute: => Unit, log: Logger): Int =
|
||||||
runUnmanaged(execute, log)
|
runUnmanaged(execute, log)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs the SecurityManager that implements the isolation and returns the previously installed SecurityManager, which may be null.
|
* Installs the SecurityManager that implements the isolation and returns the previously installed
|
||||||
* This method must be called before using `apply`.
|
* SecurityManager, which may be null. This method must be called before using `apply`.
|
||||||
*/
|
*/
|
||||||
@deprecated("TrapExit feature is removed; just call the function instead", "1.6.0")
|
@deprecated("TrapExit feature is removed; just call the function instead", "1.6.0")
|
||||||
def installManager(): Nothing =
|
def installManager(): Nothing =
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom SecurityException that tries not to be caught. Closely based on a similar class in Nailgun.
|
* A custom SecurityException that tries not to be caught. Closely based on a similar class in
|
||||||
* The main goal of this exception is that once thrown, it propagates all of the way up the call stack,
|
* Nailgun. The main goal of this exception is that once thrown, it propagates all of the way up the
|
||||||
* terminating the thread's execution.
|
* call stack, terminating the thread's execution.
|
||||||
*/
|
*/
|
||||||
private final class TrapExitSecurityException(val exitCode: Int) extends SecurityException {
|
private final class TrapExitSecurityException(val exitCode: Int) extends SecurityException {
|
||||||
override def printStackTrace = throw this
|
override def printStackTrace = throw this
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ import sbt.internal.util.Util._
|
||||||
object ForkTest extends Properties("Fork") {
|
object ForkTest extends Properties("Fork") {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Heuristic for limiting the length of the classpath string.
|
* Heuristic for limiting the length of the classpath string. Longer than this will hit hard
|
||||||
* Longer than this will hit hard limits in the total space
|
* limits in the total space allowed for process initialization, which includes environment
|
||||||
* allowed for process initialization, which includes environment variables, at least on linux.
|
* variables, at least on linux.
|
||||||
*/
|
*/
|
||||||
final val MaximumClasspathLength = 100000
|
final val MaximumClasspathLength = 100000
|
||||||
|
|
||||||
|
|
@ -49,7 +49,8 @@ object ForkTest extends Properties("Fork") {
|
||||||
val absClasspath = trimClasspath(Path.makeString(withScala))
|
val absClasspath = trimClasspath(Path.makeString(withScala))
|
||||||
val args = optionName.map(_ :: absClasspath :: Nil).toList.flatten ++ mainAndArgs
|
val args = optionName.map(_ :: absClasspath :: Nil).toList.flatten ++ mainAndArgs
|
||||||
val config = ForkOptions().withOutputStrategy(LoggedOutput(log))
|
val config = ForkOptions().withOutputStrategy(LoggedOutput(log))
|
||||||
val exitCode = try Fork.java(config, args)
|
val exitCode =
|
||||||
|
try Fork.java(config, args)
|
||||||
catch { case e: Exception => e.printStackTrace; 1 }
|
catch { case e: Exception => e.printStackTrace; 1 }
|
||||||
val expectedCode = if (optionName.isEmpty) 1 else 0
|
val expectedCode = if (optionName.isEmpty) 1 else 0
|
||||||
s"temporary directory: ${dir.getAbsolutePath}" |:
|
s"temporary directory: ${dir.getAbsolutePath}" |:
|
||||||
|
|
@ -69,8 +70,7 @@ object ForkTest extends Properties("Fork") {
|
||||||
cp.substring(0, lastEntryI)
|
cp.substring(0, lastEntryI)
|
||||||
else
|
else
|
||||||
cp
|
cp
|
||||||
} else
|
} else cp
|
||||||
cp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object used in the tests
|
// Object used in the tests
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue