From 67010fa0b295de6a7054584b9d563e60297baf5d Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 25 Feb 2013 09:24:04 -0500 Subject: [PATCH] Split ConsoleOut into its own file, track the global ConsoleOut and use it instead of StandardMain.console --- .../src/main/scala/sbt/ConsoleLogger.scala | 73 +++++-------------- util/log/src/main/scala/sbt/ConsoleOut.scala | 62 ++++++++++++++++ .../src/main/scala/sbt/GlobalLogging.scala | 24 +++++- util/log/src/main/scala/sbt/MainLogging.scala | 11 ++- 4 files changed, 109 insertions(+), 61 deletions(-) create mode 100644 util/log/src/main/scala/sbt/ConsoleOut.scala diff --git a/util/log/src/main/scala/sbt/ConsoleLogger.scala b/util/log/src/main/scala/sbt/ConsoleLogger.scala index 711489c5c..124c61e90 100644 --- a/util/log/src/main/scala/sbt/ConsoleLogger.scala +++ b/util/log/src/main/scala/sbt/ConsoleLogger.scala @@ -7,55 +7,27 @@ package sbt object ConsoleLogger { - def systemOut: ConsoleOut = printStreamOut(System.out) - def overwriteContaining(s: String): (String,String) => Boolean = (cur, prev) => - cur.contains(s) && prev.contains(s) + @deprecated("Moved to ConsoleOut", "0.13.0") + def systemOut: ConsoleOut = ConsoleOut.systemOut - /** ConsoleOut instance that is backed by System.out. It overwrites the previously printed line - * if the function `f(lineToWrite, previousLine)` returns true. - * - * The ConsoleOut returned by this method assumes that the only newlines are from println calls - * and not in the String arguments. */ - def systemOutOverwrite(f: (String,String) => Boolean): ConsoleOut = new ConsoleOut { - val lockObject = System.out - private[this] var last: Option[String] = None - private[this] var current = new java.lang.StringBuffer - def print(s: String): Unit = synchronized { current.append(s) } - def println(s: String): Unit = synchronized { current.append(s); println() } - def println(): Unit = synchronized { - val s = current.toString - if(formatEnabled && last.exists(lmsg => f(s, lmsg))) - System.out.print(OverwriteLine) - System.out.println(s) - last = Some(s) - current = new java.lang.StringBuffer - } - } - def printStreamOut(out: PrintStream): ConsoleOut = new ConsoleOut { - val lockObject = out - def print(s: String) = out.print(s) - def println(s: String) = out.println(s) - def println() = out.println() - } - def printWriterOut(out: PrintWriter): ConsoleOut = new ConsoleOut { - val lockObject = out - def print(s: String) = out.print(s) - def println(s: String) = { out.println(s); out.flush() } - def println() = { out.println(); out.flush() } - } - def bufferedWriterOut(out: BufferedWriter): ConsoleOut = new ConsoleOut { - val lockObject = out - def print(s: String) = out.write(s) - def println(s: String) = { out.write(s); println() } - def println() = { out.newLine(); out.flush() } - } + @deprecated("Moved to ConsoleOut", "0.13.0") + def overwriteContaining(s: String): (String,String) => Boolean = ConsoleOut.overwriteContaining(s) + + @deprecated("Moved to ConsoleOut", "0.13.0") + def systemOutOverwrite(f: (String,String) => Boolean): ConsoleOut = ConsoleOut.systemOutOverwrite(f) + + @deprecated("Moved to ConsoleOut", "0.13.0") + def printStreamOut(out: PrintStream): ConsoleOut = ConsoleOut.printStreamOut(out) + + @deprecated("Moved to ConsoleOut", "0.13.0") + def printWriterOut(out: PrintWriter): ConsoleOut = ConsoleOut.printWriterOut(out) + + @deprecated("Moved to ConsoleOut", "0.13.0") + def bufferedWriterOut(out: BufferedWriter): ConsoleOut = bufferedWriterOut(out) /** Escape character, used to introduce an escape sequence. */ final val ESC = '\u001B' - /** Move to beginning of previous line and clear the line. */ - private[sbt] final val OverwriteLine = "\r\u001BM\u001B[2K" - /** An escape terminator is a character in the range `@` (decimal value 64) to `~` (decimal value 126). * It is the final character in an escape sequence. */ def isEscapeTerminator(c: Char): Boolean = @@ -120,9 +92,9 @@ object ConsoleLogger private[this] def os = System.getProperty("os.name") private[this] def isWindows = os.toLowerCase.indexOf("windows") >= 0 - def apply(out: PrintStream): ConsoleLogger = apply(printStreamOut(out)) - def apply(out: PrintWriter): ConsoleLogger = apply(printWriterOut(out)) - def apply(out: ConsoleOut = systemOut, ansiCodesSupported: Boolean = formatEnabled, + def apply(out: PrintStream): ConsoleLogger = apply(ConsoleOut.printStreamOut(out)) + def apply(out: PrintWriter): ConsoleLogger = apply(ConsoleOut.printWriterOut(out)) + def apply(out: ConsoleOut = ConsoleOut.systemOut, ansiCodesSupported: Boolean = formatEnabled, useColor: Boolean = formatEnabled, suppressedMessage: SuppressedTraceContext => Option[String] = noSuppressedMessage): ConsoleLogger = new ConsoleLogger(out, ansiCodesSupported, useColor, suppressedMessage) @@ -200,10 +172,3 @@ class ConsoleLogger private[ConsoleLogger](val out: ConsoleOut, override val ans { log(labelColor(Level.Info), Level.Info.toString, BLUE, message) } } final class SuppressedTraceContext(val traceLevel: Int, val useColor: Boolean) -sealed trait ConsoleOut -{ - val lockObject: AnyRef - def print(s: String): Unit - def println(s: String): Unit - def println(): Unit -} \ No newline at end of file diff --git a/util/log/src/main/scala/sbt/ConsoleOut.scala b/util/log/src/main/scala/sbt/ConsoleOut.scala new file mode 100644 index 000000000..916c3727e --- /dev/null +++ b/util/log/src/main/scala/sbt/ConsoleOut.scala @@ -0,0 +1,62 @@ +package sbt + + import java.io.{BufferedWriter, PrintStream, PrintWriter} + +sealed trait ConsoleOut +{ + val lockObject: AnyRef + def print(s: String): Unit + def println(s: String): Unit + def println(): Unit +} + +object ConsoleOut +{ + def systemOut: ConsoleOut = printStreamOut(System.out) + + def overwriteContaining(s: String): (String,String) => Boolean = (cur, prev) => + cur.contains(s) && prev.contains(s) + + /** Move to beginning of previous line and clear the line. */ + private[this] final val OverwriteLine = "\r\u001BM\u001B[2K" + + /** ConsoleOut instance that is backed by System.out. It overwrites the previously printed line + * if the function `f(lineToWrite, previousLine)` returns true. + * + * The ConsoleOut returned by this method assumes that the only newlines are from println calls + * and not in the String arguments. */ + def systemOutOverwrite(f: (String,String) => Boolean): ConsoleOut = new ConsoleOut { + val lockObject = System.out + private[this] var last: Option[String] = None + private[this] var current = new java.lang.StringBuffer + def print(s: String): Unit = synchronized { current.append(s) } + def println(s: String): Unit = synchronized { current.append(s); println() } + def println(): Unit = synchronized { + val s = current.toString + if(ConsoleLogger.formatEnabled && last.exists(lmsg => f(s, lmsg))) + System.out.print(OverwriteLine) + System.out.println(s) + last = Some(s) + current = new java.lang.StringBuffer + } + } + + def printStreamOut(out: PrintStream): ConsoleOut = new ConsoleOut { + val lockObject = out + def print(s: String) = out.print(s) + def println(s: String) = out.println(s) + def println() = out.println() + } + def printWriterOut(out: PrintWriter): ConsoleOut = new ConsoleOut { + val lockObject = out + def print(s: String) = out.print(s) + def println(s: String) = { out.println(s); out.flush() } + def println() = { out.println(); out.flush() } + } + def bufferedWriterOut(out: BufferedWriter): ConsoleOut = new ConsoleOut { + val lockObject = out + def print(s: String) = out.write(s) + def println(s: String) = { out.write(s); println() } + def println() = { out.newLine(); out.flush() } + } +} \ No newline at end of file diff --git a/util/log/src/main/scala/sbt/GlobalLogging.scala b/util/log/src/main/scala/sbt/GlobalLogging.scala index f712dd88a..ed7aa9e09 100644 --- a/util/log/src/main/scala/sbt/GlobalLogging.scala +++ b/util/log/src/main/scala/sbt/GlobalLogging.scala @@ -5,11 +5,28 @@ package sbt import java.io.{File, PrintWriter} -final case class GlobalLogging(full: Logger, backed: ConsoleLogger, backing: GlobalLogBacking) +/** Provides the current global logging configuration. +* +* `full` is the current global logger. It should not be set directly because it is generated as needed from `backing.newLogger`. +* `console` is where all logging from all ConsoleLoggers should go. +* `backed` is the ConsoleLogger that other loggers should feed into. +* `backing` tracks the files that persist the global logging. */ +final case class GlobalLogging(full: Logger, console: ConsoleOut, backed: ConsoleLogger, backing: GlobalLogBacking) + +/** Tracks the files that persist the global logging. +* `file` is the current backing file. `last` is the previous backing file, if there is one. +* `newLogger` creates a new global logging configuration from a sink and backing configuration. +* `newBackingFile` creates a new temporary location for the next backing file. */ final case class GlobalLogBacking(file: File, last: Option[File], newLogger: (PrintWriter, GlobalLogBacking) => GlobalLogging, newBackingFile: () => File) { + /** Shifts the current backing file to `last` and sets the current backing to `newFile`. */ def shift(newFile: File) = GlobalLogBacking(newFile, Some(file), newLogger, newBackingFile) + + /** Shifts the current backing file to `last` and sets the current backing to a new temporary file generated by `newBackingFile`. */ def shiftNew() = shift(newBackingFile()) + + /** If there is a previous backing file in `last`, that becomes the current backing file and the previous backing is cleared. + * Otherwise, no changes are made. */ def unshift = GlobalLogBacking(last getOrElse file, None, newLogger, newBackingFile) } object GlobalLogBacking @@ -21,10 +38,11 @@ object GlobalLogging { @deprecated("Explicitly specify standard out.", "0.13.0") def initial(newLogger: (PrintWriter, GlobalLogBacking) => GlobalLogging, newBackingFile: => File): GlobalLogging = - initial(newLogger, newBackingFile, ConsoleLogger.systemOut) + initial(newLogger, newBackingFile, ConsoleOut.systemOut) + def initial(newLogger: (PrintWriter, GlobalLogBacking) => GlobalLogging, newBackingFile: => File, console: ConsoleOut): GlobalLogging = { val log = ConsoleLogger(console) - GlobalLogging(log, log, GlobalLogBacking(newLogger, newBackingFile)) + GlobalLogging(log, console, log, GlobalLogBacking(newLogger, newBackingFile)) } } \ No newline at end of file diff --git a/util/log/src/main/scala/sbt/MainLogging.scala b/util/log/src/main/scala/sbt/MainLogging.scala index 9e024ef28..abed543c7 100644 --- a/util/log/src/main/scala/sbt/MainLogging.scala +++ b/util/log/src/main/scala/sbt/MainLogging.scala @@ -17,18 +17,21 @@ object MainLogging backed setTrace backingTrace multi: Logger } + + @deprecated("Explicitly specify the console output.", "0.13.0") def globalDefault(writer: PrintWriter, backing: GlobalLogBacking): GlobalLogging = - globalDefault(writer, backing, ConsoleLogger.systemOut) + globalDefault(writer, backing, ConsoleOut.systemOut) + def globalDefault(writer: PrintWriter, backing: GlobalLogBacking, console: ConsoleOut): GlobalLogging = { val backed = defaultBacked()(writer) val full = multiLogger(defaultMultiConfig(console, backed ) ) - GlobalLogging(full, backed, backing) + GlobalLogging(full, console, backed, backing) } @deprecated("Explicitly specify the console output.", "0.13.0") def defaultMultiConfig(backing: AbstractLogger): MultiLoggerConfig = - defaultMultiConfig(ConsoleLogger.systemOut, backing) + defaultMultiConfig(ConsoleOut.systemOut, backing) def defaultMultiConfig(console: ConsoleOut, backing: AbstractLogger): MultiLoggerConfig = new MultiLoggerConfig(defaultScreen(console, ConsoleLogger.noSuppressedMessage), backing, Nil, Level.Info, Level.Debug, -1, Int.MaxValue) @@ -43,7 +46,7 @@ object MainLogging ConsoleLogger(console, suppressedMessage = suppressedMessage) def defaultBacked(useColor: Boolean = ConsoleLogger.formatEnabled): PrintWriter => ConsoleLogger = - to => ConsoleLogger(ConsoleLogger.printWriterOut(to), useColor = useColor) + to => ConsoleLogger(ConsoleOut.printWriterOut(to), useColor = useColor) } final case class MultiLoggerConfig(console: AbstractLogger, backed: AbstractLogger, extra: List[AbstractLogger],