clean up Process subproject

no longer has any dependencies
small ProcessLogger interface to send buffered out/err to
commented out (but working) implicit conversions from Logger -> ProcessLogger
  for use in an integrating project to get original functionality
This commit is contained in:
Mark Harrah 2010-08-21 22:49:11 -04:00
parent 6d0d3a1e4d
commit 48d5ec5da4
4 changed files with 46 additions and 35 deletions

View File

@ -33,6 +33,14 @@ abstract class AbstractLogger extends Logger
}
}
/*
These need to go in a module that integrates Logger and Process.
object Logger
{
implicit def absLog2PLog(log: AbstractLogger): ProcessLogger = new BufferedLogger(log) with ProcessLogger
implicit def log2PLog(log: Logger): ProcessLogger = absLog2PLog(new FullLogger(log))
}*/
/** This is intended to be the simplest logging interface for use by code that wants to log.
* It does not include configuring the logger. */
trait Logger extends xLogger

View File

@ -103,49 +103,49 @@ trait ProcessBuilder extends SourcePartialBuilder with SinkPartialBuilder
* sent to the console. If the exit code is non-zero, an exception is thrown.*/
def !! : String
/** Starts the process represented by this builder, blocks until it exits, and returns the output as a String. Standard error is
* sent to the provided Logger. If the exit code is non-zero, an exception is thrown.*/
def !!(log: Logger) : String
* sent to the provided ProcessLogger. If the exit code is non-zero, an exception is thrown.*/
def !!(log: ProcessLogger) : String
/** Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the console. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination and then throw an exception. */
def lines: Stream[String]
/** Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the provided Logger. If the process exits with a non-zero value,
* but the process has not completed. Standard error is sent to the provided ProcessLogger. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination but will not throw an exception. */
def lines(log: Logger): Stream[String]
def lines(log: ProcessLogger): Stream[String]
/** Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the console. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination but will not throw an exception. */
def lines_! : Stream[String]
/** Starts the process represented by this builder. The output is returned as a Stream that blocks when lines are not available
* but the process has not completed. Standard error is sent to the provided Logger. If the process exits with a non-zero value,
* but the process has not completed. Standard error is sent to the provided ProcessLogger. If the process exits with a non-zero value,
* the Stream will provide all lines up to termination but will not throw an exception. */
def lines_!(log: Logger): Stream[String]
def lines_!(log: ProcessLogger): Stream[String]
/** Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the console.*/
def ! : Int
/** Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the given Logger.*/
def !(log: Logger): Int
* sent to the given ProcessLogger.*/
def !(log: ProcessLogger): Int
/** Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the console. The newly started process reads from standard input of the current process.*/
def !< : Int
/** Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the given Logger. The newly started process reads from standard input of the current process.*/
def !<(log: Logger) : Int
* sent to the given ProcessLogger. The newly started process reads from standard input of the current process.*/
def !<(log: ProcessLogger) : Int
/** Starts the process represented by this builder. Standard output and error are sent to the console.*/
def run(): Process
/** Starts the process represented by this builder. Standard output and error are sent to the given Logger.*/
def run(log: Logger): Process
/** Starts the process represented by this builder. Standard output and error are sent to the given ProcessLogger.*/
def run(log: ProcessLogger): Process
/** Starts the process represented by this builder. I/O is handled by the given ProcessIO instance.*/
def run(io: ProcessIO): Process
/** Starts the process represented by this builder. Standard output and error are sent to the console.
* The newly started process reads from standard input of the current process if `connectInput` is true.*/
def run(connectInput: Boolean): Process
/** Starts the process represented by this builder, blocks until it exits, and returns the exit code. Standard output and error are
* sent to the given Logger.
* sent to the given ProcessLogger.
* The newly started process reads from standard input of the current process if `connectInput` is true.*/
def run(log: Logger, connectInput: Boolean): Process
def run(log: ProcessLogger, connectInput: Boolean): Process
/** Constructs a command that runs this command first and then `other` if this command succeeds.*/
def #&& (other: ProcessBuilder): ProcessBuilder
@ -164,4 +164,10 @@ final class ProcessIO(val writeInput: OutputStream => Unit, val processOutput: I
def withOutput(process: InputStream => Unit): ProcessIO = new ProcessIO(writeInput, process, processError)
def withError(process: InputStream => Unit): ProcessIO = new ProcessIO(writeInput, processOutput, process)
def withInput(write: OutputStream => Unit): ProcessIO = new ProcessIO(write, processOutput, processError)
}
trait ProcessLogger
{
def info(s: => String): Unit
def error(s: => String): Unit
def buffer[T](f: => T): T
}

View File

@ -43,17 +43,19 @@ private object Future
object BasicIO
{
def apply(buffer: StringBuffer, log: Option[Logger], withIn: Boolean) = new ProcessIO(input(withIn), processFully(buffer), getErr(log))
def apply(log: Logger, withIn: Boolean) = new ProcessIO(input(withIn), processFully(log, Level.Info), processFully(log, Level.Error))
def apply(buffer: StringBuffer, log: Option[ProcessLogger], withIn: Boolean) = new ProcessIO(input(withIn), processFully(buffer), getErr(log))
def apply(log: ProcessLogger, withIn: Boolean) = new ProcessIO(input(withIn), processInfoFully(log), processErrFully(log))
def getErr(log: Option[Logger]) = log match { case Some(lg) => processFully(lg, Level.Error); case None => toStdErr }
def getErr(log: Option[ProcessLogger]) = log match { case Some(lg) => processErrFully(lg); case None => toStdErr }
private def processErrFully(log: ProcessLogger) = processFully(s => log.error(s))
private def processInfoFully(log: ProcessLogger) = processFully(s => log.info(s))
def ignoreOut = (i: OutputStream) => ()
final val BufferSize = 8192
final val Newline = System.getProperty("line.separator")
def close(c: java.io.Closeable) = try { c.close() } catch { case _: java.io.IOException => () }
def processFully(log: Logger, level: Level.Value): InputStream => Unit = processFully(line => log.log(level, line))
def processFully(buffer: Appendable): InputStream => Unit = processFully(appendLine(buffer))
def processFully(processLine: String => Unit): InputStream => Unit =
in =>
@ -128,26 +130,26 @@ private abstract class AbstractProcessBuilder extends ProcessBuilder with SinkPa
def run(): Process = run(false)
def run(connectInput: Boolean): Process = run(BasicIO.standard(connectInput))
def run(log: Logger): Process = run(log, false)
def run(log: Logger, connectInput: Boolean): Process = run(BasicIO(log, connectInput))
def run(log: ProcessLogger): Process = run(log, false)
def run(log: ProcessLogger, connectInput: Boolean): Process = run(BasicIO(log, connectInput))
private[this] def getString(log: Option[Logger], withIn: Boolean): String =
private[this] def getString(log: Option[ProcessLogger], withIn: Boolean): String =
{
val buffer = new StringBuffer
val code = this ! BasicIO(buffer, log, withIn)
if(code == 0) buffer.toString else error("Nonzero exit value: " + code)
}
def !! = getString(None, false)
def !!(log: Logger) = getString(Some(log), false)
def !!(log: ProcessLogger) = getString(Some(log), false)
def !!< = getString(None, true)
def !!<(log: Logger) = getString(Some(log), true)
def !!<(log: ProcessLogger) = getString(Some(log), true)
def lines: Stream[String] = lines(false, true, None)
def lines(log: Logger): Stream[String] = lines(false, true, Some(log))
def lines(log: ProcessLogger): Stream[String] = lines(false, true, Some(log))
def lines_! : Stream[String] = lines(false, false, None)
def lines_!(log: Logger): Stream[String] = lines(false, false, Some(log))
def lines_!(log: ProcessLogger): Stream[String] = lines(false, false, Some(log))
private[this] def lines(withInput: Boolean, nonZeroException: Boolean, log: Option[Logger]): Stream[String] =
private[this] def lines(withInput: Boolean, nonZeroException: Boolean, log: Option[ProcessLogger]): Stream[String] =
{
val streamed = Streamed[String](nonZeroException)
val process = run(new ProcessIO(BasicIO.input(withInput), BasicIO.processFully(streamed.process), BasicIO.getErr(log)))
@ -157,13 +159,10 @@ private abstract class AbstractProcessBuilder extends ProcessBuilder with SinkPa
def ! = run(false).exitValue()
def !< = run(true).exitValue()
def !(log: Logger) = runBuffered(log, false)
def !<(log: Logger) = runBuffered(log, true)
private[this] def runBuffered(log: Logger, connectInput: Boolean) =
{
val log2 = new BufferedLogger(new FullLogger(log))
log2.buffer { run(log2, connectInput).exitValue() }
}
def !(log: ProcessLogger) = runBuffered(log, false)
def !<(log: ProcessLogger) = runBuffered(log, true)
private[this] def runBuffered(log: ProcessLogger, connectInput: Boolean) =
log.buffer { run(log, connectInput).exitValue() }
def !(io: ProcessIO) = run(io).exitValue()
def canPipeTo = false

View File

@ -8,8 +8,6 @@ import Process._
object ProcessSpecification extends Properties("Process I/O")
{
private val log = new ConsoleLogger
implicit val exitCodeArb: Arbitrary[Array[Byte]] = Arbitrary(Gen.choose(0, 10) flatMap { size => Gen.resize(size, Arbitrary.arbArray[Byte].arbitrary) })
/*property("Correct exit code") = forAll( (exitCode: Byte) => checkExit(exitCode))