diff --git a/util/log/Logger.scala b/util/log/Logger.scala index 68e1f26d8..0751b72c8 100644 --- a/util/log/Logger.scala +++ b/util/log/Logger.scala @@ -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 diff --git a/util/process/Process.scala b/util/process/Process.scala index 183469516..536d40eea 100644 --- a/util/process/Process.scala +++ b/util/process/Process.scala @@ -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 } \ No newline at end of file diff --git a/util/process/ProcessImpl.scala b/util/process/ProcessImpl.scala index 5f89a4749..c20b23f20 100644 --- a/util/process/ProcessImpl.scala +++ b/util/process/ProcessImpl.scala @@ -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 diff --git a/util/process/src/test/scala/ProcessSpecification.scala b/util/process/src/test/scala/ProcessSpecification.scala index 0d7141635..f2f42d3ca 100644 --- a/util/process/src/test/scala/ProcessSpecification.scala +++ b/util/process/src/test/scala/ProcessSpecification.scala @@ -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))