2016-05-10 9 views
1

からスカラストリーム+プロセスのインスタンスを取得lineStream(log: ProcessLogger): Stream[String](3つの同様のオプション)スカラ:</p> <p>オプション#1:私は、次のオプションがありProcessBuilderを

オプション#2:run(log: ProcessLogger): Process(及び4つの同様のオプション)

どうすれば両方を取得できますか?Stream[String] + Process

これが可能でない場合、最初のオプション(Stream[String]では、Processインスタンス)を使用することを決定すると、システムプロセスを早期に破棄する方法を教えてください。

Related API Docs Page (ProcessBuilder)

答えて

1

これは私がScalaでは、プロセスのAPIについては好きではないものの一つです - あなたは、通常の両方で取得するかのいずれか、することはできません。私はあなたが望むものがAPIで可能だとは思わない。 ProcessBuilderImpl.lineStream()の実装を見ると、プロセス参照はローカルにのみ保存され、プロセス参照はアクセスできません。

lineStream()がフードの下に実際に書き込まれた方法に触発されて、こうした機能を実装する方法の簡単な例を示します(ProcessBuilderImplBasicIOを参照)。私はそれを磨く時間がなかった(タプルより良い何かを返すような)が、それはあなたにアイデアを与える必要があります。

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()) 
} 
関連する問題