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.
|
||||
*
|
||||
* @param commandName 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.
|
||||
* @param commandName
|
||||
* 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]) {
|
||||
|
||||
/**
|
||||
* Forks the configured process, waits for it to complete, and returns the exit code.
|
||||
* The command executed is the `commandName` defined for this Fork instance.
|
||||
* 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.
|
||||
* Forks the configured process, waits for it to complete, and returns the exit code. The command
|
||||
* executed is the `commandName` defined for this Fork instance. 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 = {
|
||||
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.
|
||||
* The command executed is the `commandName` defined for this Fork instance.
|
||||
* 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.
|
||||
* Forks the configured process and returns a `Process` that can be used to wait for completion or
|
||||
* to terminate the forked process. The command executed is the `commandName` defined for this
|
||||
* Fork instance. 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 fork(config: ForkOptions, arguments: Seq[String]): Process = {
|
||||
import config.{ envVars => env, _ }
|
||||
|
|
@ -108,7 +111,10 @@ object Fork {
|
|||
private[this] def isClasspathOption(s: String) =
|
||||
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 def fitClasspath(options: Seq[String]): (Option[String], Seq[String]) =
|
||||
|
|
|
|||
|
|
@ -10,21 +10,21 @@ package sbt
|
|||
import sbt.util.Logger
|
||||
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
|
||||
|
||||
object OutputStrategy {
|
||||
|
||||
/**
|
||||
* Configures the forked standard output to go to standard output of this process and
|
||||
* for the forked standard error to go to the standard error of this process.
|
||||
* Configures the forked standard output to go to standard output of this process and for the
|
||||
* forked standard error to go to the standard error of this process.
|
||||
*/
|
||||
case object StdoutOutput extends OutputStrategy
|
||||
|
||||
/**
|
||||
* Logs the forked standard output at the `info` level and the forked standard error at
|
||||
* the `error` level. The output is buffered until the process completes, at which point
|
||||
* the logger flushes it (to the screen, for example).
|
||||
* Logs the forked standard output at the `info` level and the forked standard error at the
|
||||
* `error` level. The output is buffered until the process completes, at which point the logger
|
||||
* flushes it (to the screen, for example).
|
||||
*/
|
||||
final class BufferedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
|
||||
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
|
||||
* the `error` level.
|
||||
* Logs the forked standard output at the `info` level and the forked standard error at the
|
||||
* `error` level.
|
||||
*/
|
||||
final class LoggedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
|
||||
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
|
||||
* to be sent to the standard error of this process.
|
||||
* Configures the forked standard output to be sent to `output` and the forked standard error to
|
||||
* be sent to the standard error of this process.
|
||||
*/
|
||||
final class CustomOutput private (val output: OutputStream)
|
||||
extends OutputStrategy
|
||||
|
|
|
|||
|
|
@ -37,12 +37,13 @@ class ForkRun(config: ForkOptions) extends ScalaRun {
|
|||
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 Fork.java(c, scalaOpts)
|
||||
catch {
|
||||
case _: InterruptedException =>
|
||||
log.warn("Run canceled.")
|
||||
1
|
||||
}
|
||||
processExitCode(exitCode, "runner")
|
||||
}
|
||||
|
||||
|
|
@ -110,18 +111,17 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea
|
|||
}
|
||||
}
|
||||
def directExecute(): Try[Unit] =
|
||||
Try(execute()) recover {
|
||||
case NonFatal(e) =>
|
||||
// bgStop should not print out stack trace
|
||||
// log.trace(e)
|
||||
throw e
|
||||
Try(execute()) recover { case NonFatal(e) =>
|
||||
// bgStop should not print out stack trace
|
||||
// log.trace(e)
|
||||
throw e
|
||||
}
|
||||
|
||||
if (trapExit) Run.executeSuccess(execute())
|
||||
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] = {
|
||||
val loader = newLoader(classpath)
|
||||
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 {
|
||||
def run(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger)(
|
||||
implicit runner: ScalaRun
|
||||
def run(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger)(implicit
|
||||
runner: ScalaRun
|
||||
) =
|
||||
runner.run(mainClass, classpath, options, log)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,7 @@ object SelectMainClass {
|
|||
private def toInt(s: String, size: Int): Option[Int] =
|
||||
try {
|
||||
val i = s.toInt
|
||||
if (i > 0 && i <= size)
|
||||
(i - 1).some
|
||||
if (i > 0 && i <= size) (i - 1).some
|
||||
else {
|
||||
println("Number out of range: was " + i + ", expected number between 1 and " + size)
|
||||
none
|
||||
|
|
|
|||
|
|
@ -10,29 +10,29 @@ package sbt
|
|||
import sbt.util.Logger
|
||||
|
||||
/**
|
||||
* Provides an approximation to isolated execution within a single JVM.
|
||||
* System.exit calls are trapped to prevent the JVM from terminating. This is useful for executing
|
||||
* user code that may call System.exit, but actually exiting is undesirable.
|
||||
* Provides an approximation to isolated execution within a single JVM. System.exit calls are
|
||||
* trapped to prevent the JVM from terminating. This is useful for executing user code that may call
|
||||
* System.exit, but actually exiting is undesirable.
|
||||
*
|
||||
* 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
|
||||
* therefore inappropriate to use this with code that requires shutdown hooks, creates threads that
|
||||
* do not terminate, or if concurrent AWT applications are run.
|
||||
* This category of code should only be called by forking a new JVM.
|
||||
* Threads are not stopped and shutdown hooks are not called. It is therefore inappropriate to use
|
||||
* this with code that requires shutdown hooks, creates threads that do not terminate, or if
|
||||
* concurrent AWT applications are run. This category of code should only be called by forking a new
|
||||
* JVM.
|
||||
*/
|
||||
object TrapExit {
|
||||
|
||||
/**
|
||||
* Run `execute` in a managed context, using `log` for debugging messages.
|
||||
* `installManager` must be called before calling this method.
|
||||
* Run `execute` in a managed context, using `log` for debugging messages. `installManager` must
|
||||
* be called before calling this method.
|
||||
*/
|
||||
@deprecated("TrapExit feature is removed; just call the function instead", "1.6.0")
|
||||
def apply(execute: => Unit, log: Logger): Int =
|
||||
runUnmanaged(execute, log)
|
||||
|
||||
/**
|
||||
* Installs the SecurityManager that implements the isolation and returns the previously installed SecurityManager, which may be null.
|
||||
* This method must be called before using `apply`.
|
||||
* Installs the SecurityManager that implements the isolation and returns the previously installed
|
||||
* 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")
|
||||
def installManager(): Nothing =
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
package sbt
|
||||
|
||||
/**
|
||||
* A custom SecurityException that tries not to be caught. Closely based on a similar class in Nailgun.
|
||||
* The main goal of this exception is that once thrown, it propagates all of the way up the call stack,
|
||||
* terminating the thread's execution.
|
||||
* A custom SecurityException that tries not to be caught. Closely based on a similar class in
|
||||
* Nailgun. The main goal of this exception is that once thrown, it propagates all of the way up the
|
||||
* call stack, terminating the thread's execution.
|
||||
*/
|
||||
private final class TrapExitSecurityException(val exitCode: Int) extends SecurityException {
|
||||
override def printStackTrace = throw this
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ import sbt.internal.util.Util._
|
|||
object ForkTest extends Properties("Fork") {
|
||||
|
||||
/**
|
||||
* Heuristic for limiting the length of the classpath string.
|
||||
* Longer than this will hit hard limits in the total space
|
||||
* allowed for process initialization, which includes environment variables, at least on linux.
|
||||
* Heuristic for limiting the length of the classpath string. Longer than this will hit hard
|
||||
* limits in the total space allowed for process initialization, which includes environment
|
||||
* variables, at least on linux.
|
||||
*/
|
||||
final val MaximumClasspathLength = 100000
|
||||
|
||||
|
|
@ -49,8 +49,9 @@ object ForkTest extends Properties("Fork") {
|
|||
val absClasspath = trimClasspath(Path.makeString(withScala))
|
||||
val args = optionName.map(_ :: absClasspath :: Nil).toList.flatten ++ mainAndArgs
|
||||
val config = ForkOptions().withOutputStrategy(LoggedOutput(log))
|
||||
val exitCode = try Fork.java(config, args)
|
||||
catch { case e: Exception => e.printStackTrace; 1 }
|
||||
val exitCode =
|
||||
try Fork.java(config, args)
|
||||
catch { case e: Exception => e.printStackTrace; 1 }
|
||||
val expectedCode = if (optionName.isEmpty) 1 else 0
|
||||
s"temporary directory: ${dir.getAbsolutePath}" |:
|
||||
s"required classpath: ${requiredEntries.mkString("\n\t", "\n\t", "")}" |:
|
||||
|
|
@ -69,8 +70,7 @@ object ForkTest extends Properties("Fork") {
|
|||
cp.substring(0, lastEntryI)
|
||||
else
|
||||
cp
|
||||
} else
|
||||
cp
|
||||
} else cp
|
||||
}
|
||||
|
||||
// Object used in the tests
|
||||
|
|
|
|||
Loading…
Reference in New Issue