mirror of https://github.com/sbt/sbt.git
Use java 7 Redirect.INHERIT to inherit subprocess' input stream.
This commit is contained in:
parent
53ee1c5adf
commit
8d123081a2
|
|
@ -0,0 +1,20 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2012 Eugene Vigdorchik
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import java.lang.{ProcessBuilder => JProcessBuilder}
|
||||
|
||||
/** On java 7, inherit System.in for a ProcessBuilder. */
|
||||
private[sbt] object InheritInput {
|
||||
def apply(p: JProcessBuilder): (Boolean, JProcessBuilder) = (redirectInput, inherit) match {
|
||||
case (Some(m), Some(f)) => (true, m.invoke(p, f).asInstanceOf[JProcessBuilder])
|
||||
case _ => (false, p)
|
||||
}
|
||||
|
||||
private[this] val pbClass = Class.forName("java.lang.ProcessBuilder")
|
||||
private[this] val redirectClass = pbClass.getClasses find (_.getSimpleName == "Redirect")
|
||||
|
||||
private[this] val redirectInput = redirectClass map (pbClass.getMethod("redirectInput", _))
|
||||
private[this] val inherit = redirectClass map (_ getField "INHERIT" get null)
|
||||
}
|
||||
|
|
@ -379,40 +379,41 @@ private[sbt] class SimpleProcessBuilder(p: JProcessBuilder) extends AbstractProc
|
|||
{
|
||||
override def run(io: ProcessIO): Process =
|
||||
{
|
||||
val process = p.start() // start the external process
|
||||
val (inherited, pp) = InheritInput(p)
|
||||
val process = pp.start() // start the external process
|
||||
import io.{writeInput, processOutput, processError}
|
||||
// spawn threads that process the input, output, and error streams using the functions defined in `io`
|
||||
val inThread = Spawn(writeInput(process.getOutputStream), true)
|
||||
if(!inherited)
|
||||
Spawn(writeInput(process.getOutputStream), true)
|
||||
|
||||
val outThread = Spawn(processOutput(process.getInputStream))
|
||||
val errorThread =
|
||||
if(!p.redirectErrorStream)
|
||||
Spawn(processError(process.getErrorStream)) :: Nil
|
||||
else
|
||||
Nil
|
||||
new SimpleProcess(process, inThread, outThread :: errorThread)
|
||||
new SimpleProcess(process, outThread :: errorThread)
|
||||
}
|
||||
override def toString = p.command.toString
|
||||
override def canPipeTo = true
|
||||
}
|
||||
/** A thin wrapper around a java.lang.Process. `outputThreads` are the Threads created to read from the
|
||||
* output and error streams of the process. `inputThread` is the Thread created to write to the input stream of
|
||||
* the process.
|
||||
* The implementation of `exitValue` interrupts `inputThread` and then waits until all I/O threads die before
|
||||
* returning. */
|
||||
private class SimpleProcess(p: JProcess, inputThread: Thread, outputThreads: List[Thread]) extends Process
|
||||
|
||||
/** A thin wrapper around a java.lang.Process. `outputThreads` are the Threads created to read from the
|
||||
* output and error streams of the process.
|
||||
* The implementation of `exitValue` wait for the process to finish and then waits until the threads reading output and error streams die before
|
||||
* returning. Note that the thread that reads the input stream cannot be interrupted, see https://github.com/harrah/xsbt/issues/327 and
|
||||
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4514257 */
|
||||
private class SimpleProcess(p: JProcess, outputThreads: List[Thread]) extends Process
|
||||
{
|
||||
override def exitValue() =
|
||||
{
|
||||
try { p.waitFor() }// wait for the process to terminate
|
||||
finally { inputThread.interrupt() } // we interrupt the input thread to notify it that it can terminate
|
||||
def waitDone(): Unit =
|
||||
try { p.waitFor() } catch { case _: InterruptedException => waitDone() }
|
||||
waitDone()
|
||||
outputThreads.foreach(_.join()) // this ensures that all output is complete before returning (waitFor does not ensure this)
|
||||
p.exitValue()
|
||||
}
|
||||
override def destroy() =
|
||||
{
|
||||
try { p.destroy() }
|
||||
finally { inputThread.interrupt() }
|
||||
}
|
||||
override def destroy() = p.destroy()
|
||||
}
|
||||
|
||||
private class FileOutput(file: File, append: Boolean) extends OutputStreamBuilder(new FileOutputStream(file, append), file.getAbsolutePath)
|
||||
|
|
|
|||
Loading…
Reference in New Issue