Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala
package sys
package process
import processInternal._
import java.io.{ BufferedReader, InputStreamReader, FilterInputStream, FilterOutputStream }
import java.util.concurrent.LinkedBlockingQueue
import scala.annotation.tailrec
/**
* This object contains factories for [[scala.sys.process.ProcessIO]],
* which can be used to control the I/O of a [[scala.sys.process.Process]]
* when a [[scala.sys.process.ProcessBuilder]] is started with the `run`
* command.
*
* It also contains some helper methods that can be used to in the creation of
* `ProcessIO`.
*
* It is used by other classes in the package in the implementation of various
* features, but can also be used by client code.
*/
object BasicIO {
/** Size of the buffer used in all the functions that copy data */
final val BufferSize = 8192
/** Used to separate lines in the `processFully` function that takes `Appendable`. */
final val Newline = System.lineSeparator
private[process] final class LazilyListed[T](
val process: T => Unit,
val done: Int => Unit,
val lazyList: LazyList[T]
)
private[process] object LazilyListed {
def apply[T](nonzeroException: Boolean, capacity: Integer): LazilyListed[T] = {
val queue = new LinkedBlockingQueue[Either[Int, T]](capacity)
val ll = LazyList.unfold(queue) { q =>
q.take() match {
case Left(0) => None
case Left(code) => if (nonzeroException) scala.sys.error("Nonzero exit code: " + code) else None
case Right(s) => Some((s, q))
}
}
new LazilyListed((s: T) => queue put Right(s), code => queue put Left(code), ll)
}
}
@deprecated("internal", since = "2.13.4")
private[process] final class Streamed[T](
val process: T => Unit,
val done: Int => Unit,
val stream: () => Stream[T]
)
@deprecated("internal", since = "2.13.4")
private[process] object Streamed {
def apply[T](nonzeroException: Boolean, capacity: Integer): Streamed[T] = {
val q = new LinkedBlockingQueue[Either[Int, T]](capacity)
def next(): Stream[T] = q.take() match {
case Left(0) => Stream.empty
case Left(code) => if (nonzeroException) scala.sys.error("Nonzero exit code: " + code) else Stream.empty
case Right(s) => Stream.cons(s, next())
}
new Streamed((s: T) => q put Right(s), code => q put Left(code), () => next())
}
}
private[process] trait Uncloseable extends Closeable {
final override def close(): Unit = ()
}
private[process] object Uncloseable {
def apply(in: InputStream): InputStream = new FilterInputStream(in) with Uncloseable { }
def apply(out: OutputStream): OutputStream = new FilterOutputStream(out) with Uncloseable { }
def protect(in: InputStream): InputStream = if (in eq stdin) Uncloseable(in) else in
def protect(out: OutputStream): OutputStream = if ((out eq stdout) || (out eq stderr)) Uncloseable(out) else out
}
/** Creates a `ProcessIO` from a function `String => Unit`. It can attach the
* process input to stdin, and it will either send the error stream to
* stderr, or to a `ProcessLogger`.
*
* For example, the `ProcessIO` created below will print all normal output
* while ignoring all error output. No input will be provided.
* {{{
* import scala.sys.process.BasicIO
* val errToDevNull = BasicIO(false, println(_), None)
* }}}
*
* @param withIn True if the process input should be attached to stdin.
* @param output A function that will be called with the process output.
* @param log An optional `ProcessLogger` to which the output should be
* sent. If `None`, output will be sent to stderr.
* @return A `ProcessIO` with the characteristics above.
*/
def apply(withIn: Boolean, output: String => Unit, log: Option[ProcessLogger]) =
new ProcessIO(input(withIn), processFully(output), getErr(log))
/** Creates a `ProcessIO` that appends its output to an `Appendable`. It can
* attach the process input to stdin, and it will either send the error
* stream to stderr, or to a `ProcessLogger`.
*
* For example, the `ProcessIO` created by the function below will store the
* normal output on the buffer provided, and print all error on stderr. The
* input will be read from stdin.
* {{{
* import scala.sys.process.{BasicIO, ProcessLogger}
* val printer = ProcessLogger(println(_))
* def appendToBuffer(b: StringBuffer) = BasicIO(true, b, Some(printer))
* }}}
*
* @param withIn True if the process input should be attached to stdin.
* @param buffer An `Appendable` which will receive the process normal
* output.
* @param log An optional `ProcessLogger` to which the output should be
* sent. If `None`, output will be sent to stderr.
* @return A `ProcessIO` with the characteristics above.
*/
def apply(withIn: Boolean, buffer: Appendable, log: Option[ProcessLogger]) =
new ProcessIO(input(withIn), processFully(buffer), getErr(log))
/** Creates a `ProcessIO` from a `ProcessLogger` . It can attach the
* process input to stdin.
*
* @param withIn True if the process input should be attached to stdin.
* @param log A `ProcessLogger` to receive all output, normal and error.
* @return A `ProcessIO` with the characteristics above.
*/
def apply(withIn: Boolean, log: ProcessLogger) =
new ProcessIO(input(withIn), processOutFully(log), processErrFully(log))
/** Returns a function `InputStream => Unit` given an optional
* `ProcessLogger`. If no logger is passed, the function will send the output
* to stderr. This function can be used to create a
* [[scala.sys.process.ProcessIO]].
*
* @param log An optional `ProcessLogger` to which the contents of
* the `InputStream` will be sent.
* @return A function `InputStream => Unit` (used by
* [[scala.sys.process.ProcessIO]]) which will send the data to
* either the provided `ProcessLogger` or, if `None`, to stderr.
*/
def getErr(log: Option[ProcessLogger]) = log match {
case Some(lg) => processErrFully(lg)
case None => toStdErr
}
private def processErrFully(log: ProcessLogger) = processFully(log err _)
private def processOutFully(log: ProcessLogger) = processFully(log out _)
/** Closes a `Closeable` without throwing an exception */
def close(c: Closeable) = try c.close() catch { case _: IOException => () }
/** Returns a function `InputStream => Unit` that appends all data read to the
* provided `Appendable`. This function can be used to create a
* [[scala.sys.process.ProcessIO]]. The buffer will be appended line by line.
*
* @param buffer An `Appendable` such as `StringBuilder` or `StringBuffer`.
* @return A function `InputStream => Unit` (used by
* [[scala.sys.process.ProcessIO]] which will append all data read
* from the stream to the buffer.
*/
def processFully(buffer: Appendable): InputStream => Unit = processFully(appendLine(buffer))
/** Returns a function `InputStream => Unit` that will call the passed
* function with all data read. This function can be used to create a
* [[scala.sys.process.ProcessIO]]. The `processLine` function will be called
* with each line read, and `Newline` will be appended after each line.
*
* @param processLine A function that will be called with all data read from
* the stream.
* @return A function `InputStream => Unit` (used by
* [[scala.sys.process.ProcessIO]] which will call `processLine`
* with all data read from the stream.
*/
def processFully(processLine: String => Unit): InputStream => Unit = in => {
val reader = new BufferedReader(new InputStreamReader(in))
try processLinesFully(processLine)(() => reader.readLine())
finally reader.close()
}
/** Calls `processLine` with the result of `readLine` until the latter returns
* `null` or the current thread is interrupted.
*/
def processLinesFully(processLine: String => Unit)(readLine: () => String): Unit = {
def working = !Thread.currentThread.isInterrupted
def halting = { Thread.currentThread.interrupt(); null }
@tailrec
def readFully(): Unit =
if (working) {
val line =
try readLine()
catch {
case _: InterruptedException => halting
case _: IOException if !working => halting
}
if (line != null) {
processLine(line)
readFully()
}
}
readFully()
}
/** Copy contents of stdin to the `OutputStream`. */
def connectToIn(o: OutputStream): Unit = transferFully(Uncloseable protect stdin, o)
/** Returns a function `OutputStream => Unit` that either reads the content
* from stdin or does nothing but close the stream. This function can be used by
* [[scala.sys.process.ProcessIO]].
*/
def input(connect: Boolean): OutputStream => Unit = if (connect) connectToStdIn else connectNoOp
/** A sentinel value telling ProcessBuilderImpl to redirect. */
private[process] val connectToStdIn: OutputStream => Unit = _ => ()
/** A sentinel value telling ProcessBuilderImpl not to process. */
private[process] val connectNoOp: OutputStream => Unit = _ => ()
/** Returns a `ProcessIO` connected to stdout and stderr, and, optionally, stdin. */
def standard(connectInput: Boolean): ProcessIO = standard(input(connectInput))
/** Returns a `ProcessIO` connected to stdout, stderr and the provided `in` */
def standard(in: OutputStream => Unit): ProcessIO = new ProcessIO(in, toStdOut, toStdErr)
/** Send all the input from the stream to stderr, and closes the input stream
* afterwards.
*/
def toStdErr = (in: InputStream) => transferFully(in, stderr)
/** Send all the input from the stream to stdout, and closes the input stream
* afterwards.
*/
def toStdOut = (in: InputStream) => transferFully(in, stdout)
/** Copy all input from the input stream to the output stream. Closes the
* input stream once it's all read.
*/
def transferFully(in: InputStream, out: OutputStream): Unit =
try transferFullyImpl(in, out)
catch onIOInterrupt(())
private[this] def appendLine(buffer: Appendable): String => Unit = line => {
buffer append line
buffer append Newline
}
private[this] def transferFullyImpl(in: InputStream, out: OutputStream): Unit = {
val buffer = new Array[Byte](BufferSize)
@tailrec def loop(): Unit = {
val byteCount = in.read(buffer)
if (byteCount > 0) {
out.write(buffer, 0, byteCount)
// flush() will throw an exception once the process has terminated
val available = try { out.flush(); true } catch { case _: IOException => false }
if (available) loop()
}
}
loop()
in.close()
}
}