これは私がScalaでは、プロセスのAPIについては好きではないものの一つです - あなたは、通常の両方で取得するかのいずれか、することはできません。私はあなたが望むものがAPIで可能だとは思わない。 ProcessBuilderImpl.lineStream()
の実装を見ると、プロセス参照はローカルにのみ保存され、プロセス参照はアクセスできません。
lineStream()
がフードの下に実際に書き込まれた方法に触発されて、こうした機能を実装する方法の簡単な例を示します(ProcessBuilderImpl
とBasicIO
を参照)。私はそれを磨く時間がなかった(タプルより良い何かを返すような)が、それはあなたにアイデアを与える必要があります。
object StreamProcessLogger {
private val nonzeroException = true // set it to whatever suits you
def run(processBuilder: ProcessBuilder): (Process, Stream[String]) = {
val logger = new StreamProcessLogger
val process = processBuilder.run(logger)
waitForExitInAnotherThread(process, logger)
(process, logger.stream)
}
private def waitForExitInAnotherThread(process: Process, logger: StreamProcessLogger) = {
val thread = new Thread() {
override def run() = { logger.setExitCode(process.exitValue()) }
}
thread.start()
}
}
private class StreamProcessLogger extends ProcessLogger {
val queue = new LinkedBlockingQueue[Either[Int, String]]
override def buffer[T](f: => T): T = f
override def out(s: => String): Unit = queue.put(Right(s))
override def err(s: => String): Unit = queue.put(Right(s))
def stream = next()
def setExitCode(exitCode: Int) = queue.put(Left(exitCode))
private def next(): Stream[String] = queue.take match {
case Left(0) => Stream.empty
case Left(code) => if (StreamProcessLogger.nonzeroException) scala.sys.error("Nonzero exit code: " + code) else Stream.empty
case Right(s) => Stream.cons(s, next())
}
}
そして、ここでの使用である:
test("returns stream and process") {
val (process, stream) = StreamProcessLogger.run(Process("ls"))
stream.foreach(println)
println(process.exitValue())
}