diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala index 37819881b..2b200a85e 100644 --- a/project/build/XSbt.scala +++ b/project/build/XSbt.scala @@ -18,7 +18,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths val classpathSub = baseProject(utilPath / "classpath", "Classpath") val ivySub = project("ivy", "Ivy", new IvyProject(_), interfaceSub, launchInterfaceSub) - val logSub = baseProject(utilPath / "log", "Logging", interfaceSub) + val logSub = project(utilPath / "log", "Logging", new LogProject(_), interfaceSub) val datatypeSub = baseProject("util" /"datatype", "Datatype Generator", ioSub) val testSub = project("scripted", "Test", new TestProject(_), ioSub) @@ -37,7 +37,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths val sbtSub = project(sbtPath, "Simple Build Tool", new SbtProject(_) {}, compilerSub, launchInterfaceSub) val installerSub = project(sbtPath / "install", "Installer", new InstallerProject(_) {}, sbtSub) - lazy val dist = task { None } dependsOn(launchSub.proguard, sbtSub.publishLocal, installerSub.publishLocal) def baseProject(path: Path, name: String, deps: Project*) = project(path, name, new Base(_), deps : _*) @@ -85,13 +84,17 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths } trait TestDependencies extends Project { - val sc = "org.scala-tools.testing" %% "scalacheck" % "1.6" % "test" + val sc = "org.scala-tools.testing" %% "scalacheck" % "1.7" % "test" val sp = "org.scala-tools.testing" % "specs" % "1.6.0" % "test" } class StandardTaskProject(info: ProjectInfo) extends Base(info) { override def testClasspath = super.testClasspath +++ compilerSub.testClasspath --- compilerInterfaceClasspath } + class LogProject(info: ProjectInfo) extends Base(info) + { + val jline = jlineDep + } class IOProject(info: ProjectInfo) extends Base(info) with TestDependencies class TaskProject(info: ProjectInfo) extends Base(info) with TestDependencies diff --git a/sbt/src/main/scala/sbt/Logger.scala b/sbt/src/main/scala/sbt/Logger.scala index 579bde171..29a938797 100644 --- a/sbt/src/main/scala/sbt/Logger.scala +++ b/sbt/src/main/scala/sbt/Logger.scala @@ -5,140 +5,8 @@ package sbt import scala.collection.mutable.{Buffer, HashMap, ListBuffer} -sealed trait LogEvent extends NotNull -final class Success(val msg: String) extends LogEvent -final class Log(val level: Level.Value, val msg: String) extends LogEvent -final class Trace(val exception: Throwable) extends LogEvent -final class SetLevel(val newLevel: Level.Value) extends LogEvent -final class SetTrace(val level: Int) extends LogEvent -final class ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent -object ControlEvent extends Enumeration -{ - val Start, Header, Finish = Value -} - -abstract class Logger extends xsbt.CompileLogger with IvyLogger -{ - def getLevel: Level.Value - def setLevel(newLevel: Level.Value) - def setTrace(flag: Int) - def getTrace: Int - final def traceEnabled = getTrace >= 0 - def ansiCodesSupported = false - - def atLevel(level: Level.Value) = level.id >= getLevel.id - def trace(t: => Throwable): Unit - final def verbose(message: => String): Unit = debug(message) - final def debug(message: => String): Unit = log(Level.Debug, message) - final def info(message: => String): Unit = log(Level.Info, message) - final def warn(message: => String): Unit = log(Level.Warn, message) - final def error(message: => String): Unit = log(Level.Error, message) - def success(message: => String): Unit - def log(level: Level.Value, message: => String): Unit - def control(event: ControlEvent.Value, message: => String): Unit - - def logAll(events: Seq[LogEvent]): Unit - /** Defined in terms of other methods in Logger and should not be called from them. */ - final def log(event: LogEvent) - { - event match - { - case s: Success => success(s.msg) - case l: Log => log(l.level, l.msg) - case t: Trace => trace(t.exception) - case setL: SetLevel => setLevel(setL.newLevel) - case setT: SetTrace => setTrace(setT.level) - case c: ControlEvent => control(c.event, c.msg) - } - } - - import xsbti.F0 - def debug(msg: F0[String]): Unit = log(Level.Debug, msg) - def warn(msg: F0[String]): Unit = log(Level.Warn, msg) - def info(msg: F0[String]): Unit = log(Level.Info, msg) - def error(msg: F0[String]): Unit = log(Level.Error, msg) - def trace(msg: F0[Throwable]) = trace(msg.apply) - def log(level: Level.Value, msg: F0[String]): Unit = log(level, msg.apply) -} - -/** Implements the level-setting methods of Logger.*/ -abstract class BasicLogger extends Logger -{ - private var traceEnabledVar = java.lang.Integer.MAX_VALUE - private var level: Level.Value = Level.Info - def getLevel = level - def setLevel(newLevel: Level.Value) { level = newLevel } - def setTrace(level: Int) { traceEnabledVar = level } - def getTrace = traceEnabledVar -} - -final class SynchronizedLogger(delegate: Logger) extends Logger -{ - override lazy val ansiCodesSupported = delegate.ansiCodesSupported - def getLevel = { synchronized { delegate.getLevel } } - def setLevel(newLevel: Level.Value) { synchronized { delegate.setLevel(newLevel) } } - def setTrace(level: Int) { synchronized { delegate.setTrace(level) } } - def getTrace: Int = { synchronized { delegate.getTrace } } - - def trace(t: => Throwable) { synchronized { delegate.trace(t) } } - def log(level: Level.Value, message: => String) { synchronized { delegate.log(level, message) } } - def success(message: => String) { synchronized { delegate.success(message) } } - def control(event: ControlEvent.Value, message: => String) { synchronized { delegate.control(event, message) } } - def logAll(events: Seq[LogEvent]) { synchronized { delegate.logAll(events) } } -} - -final class MultiLogger(delegates: List[Logger]) extends BasicLogger -{ - override lazy val ansiCodesSupported = delegates.forall(_.ansiCodesSupported) - override def setLevel(newLevel: Level.Value) - { - super.setLevel(newLevel) - dispatch(new SetLevel(newLevel)) - } - override def setTrace(level: Int) - { - super.setTrace(level) - dispatch(new SetTrace(level)) - } - def trace(t: => Throwable) { dispatch(new Trace(t)) } - def log(level: Level.Value, message: => String) { dispatch(new Log(level, message)) } - def success(message: => String) { dispatch(new Success(message)) } - def logAll(events: Seq[LogEvent]) { delegates.foreach(_.logAll(events)) } - def control(event: ControlEvent.Value, message: => String) { delegates.foreach(_.control(event, message)) } - private def dispatch(event: LogEvent) { delegates.foreach(_.log(event)) } -} - -/** A filter logger is used to delegate messages but not the logging level to another logger. This means -* that messages are logged at the higher of the two levels set by this logger and its delegate. -* */ -final class FilterLogger(delegate: Logger) extends BasicLogger -{ - override lazy val ansiCodesSupported = delegate.ansiCodesSupported - def trace(t: => Throwable) - { - if(traceEnabled) - delegate.trace(t) - } - override def setTrace(level: Int) { delegate.setTrace(level) } - override def getTrace = delegate.getTrace - def log(level: Level.Value, message: => String) - { - if(atLevel(level)) - delegate.log(level, message) - } - def success(message: => String) - { - if(atLevel(Level.Info)) - delegate.success(message) - } - def control(event: ControlEvent.Value, message: => String) - { - if(atLevel(Level.Info)) - delegate.control(event, message) - } - def logAll(events: Seq[LogEvent]): Unit = delegate.logAll(events) -} +trait Logger extends AbstractLogger with xsbt.CompileLogger with IvyLogger /** A logger that can buffer the logging done on it by currently executing Thread and * then can flush the buffer to the delegate logger provided in the constructor. Use @@ -151,7 +19,7 @@ final class FilterLogger(delegate: Logger) extends BasicLogger * * This logger is thread-safe. * */ -final class BufferedLogger(delegate: Logger) extends Logger +final class BufferedLogger(delegate: AbstractLogger) extends Logger { override lazy val ansiCodesSupported = delegate.ansiCodesSupported private[this] val buffers = wrap.Wrappers.weakMap[Thread, Buffer[LogEvent]] @@ -244,9 +112,9 @@ final class BufferedLogger(delegate: Logger) extends Logger } def control(event: ControlEvent.Value, message: => String): Unit = doBufferable(Level.Info, new ControlEvent(event, message), _.control(event, message)) - private def doBufferable(level: Level.Value, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit = + private def doBufferable(level: Level.Value, appendIfBuffered: => LogEvent, doUnbuffered: AbstractLogger => Unit): Unit = doBufferableIf(atLevel(level), appendIfBuffered, doUnbuffered) - private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit = + private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: AbstractLogger => Unit): Unit = synchronized { if(condition) @@ -259,134 +127,3 @@ final class BufferedLogger(delegate: Logger) extends Logger } } } - -object ConsoleLogger -{ - private val formatEnabled = ansiSupported && !formatExplicitlyDisabled - - private[this] def formatExplicitlyDisabled = java.lang.Boolean.getBoolean("sbt.log.noformat") - private[this] def ansiSupported = - try { jline.Terminal.getTerminal.isANSISupported } - catch { case e: Exception => !isWindows } - - private[this] def os = System.getProperty("os.name") - private[this] def isWindows = os.toLowerCase.indexOf("windows") >= 0 -} - -/** A logger that logs to the console. On supported systems, the level labels are -* colored. -* -* This logger is not thread-safe.*/ -class ConsoleLogger extends BasicLogger -{ - override def ansiCodesSupported = ConsoleLogger.formatEnabled - def messageColor(level: Level.Value) = Console.RESET - def labelColor(level: Level.Value) = - level match - { - case Level.Error => Console.RED - case Level.Warn => Console.YELLOW - case _ => Console.RESET - } - def successLabelColor = Console.GREEN - def successMessageColor = Console.RESET - override def success(message: => String) - { - if(atLevel(Level.Info)) - log(successLabelColor, Level.SuccessLabel, successMessageColor, message) - } - def trace(t: => Throwable): Unit = - System.out.synchronized - { - val traceLevel = getTrace - if(traceLevel >= 0) - System.out.synchronized { System.out.print(StackTrace.trimmed(t, traceLevel)) } - } - def log(level: Level.Value, message: => String) - { - if(atLevel(level)) - log(labelColor(level), level.toString, messageColor(level), message) - } - private def setColor(color: String) - { - if(ansiCodesSupported) - System.out.synchronized { System.out.print(color) } - } - private def log(labelColor: String, label: String, messageColor: String, message: String): Unit = - System.out.synchronized - { - for(line <- message.split("""\n""")) - { - setColor(Console.RESET) - System.out.print('[') - setColor(labelColor) - System.out.print(label) - setColor(Console.RESET) - System.out.print("] ") - setColor(messageColor) - System.out.print(line) - setColor(Console.RESET) - System.out.println() - } - } - - def logAll(events: Seq[LogEvent]) = System.out.synchronized { events.foreach(log) } - def control(event: ControlEvent.Value, message: => String) - { log(labelColor(Level.Info), Level.Info.toString, Console.BLUE, message) } -} - -/** An enumeration defining the levels available for logging. A level includes all of the levels -* with id larger than its own id. For example, Warn (id=3) includes Error (id=4).*/ -object Level extends Enumeration with NotNull -{ - val Debug = Value(1, "debug") - val Info = Value(2, "info") - val Warn = Value(3, "warn") - val Error = Value(4, "error") - /** Defines the label to use for success messages. A success message is logged at the info level but - * uses this label. Because the label for levels is defined in this module, the success - * label is also defined here. */ - val SuccessLabel = "success" - - // added because elements was renamed to iterator in 2.8.0 nightly - def levels = Debug :: Info :: Warn :: Error :: Nil - /** Returns the level with the given name wrapped in Some, or None if no level exists for that name. */ - def apply(s: String) = levels.find(s == _.toString) - /** Same as apply, defined for use in pattern matching. */ - private[sbt] def unapply(s: String) = apply(s) -} -/** Provides a `java.io.Writer` interface to a `Logger`. Content is line-buffered and logged at `level`. -* A line is delimited by `nl`, which is by default the platform line separator.*/ -final class LoggerWriter(delegate: Logger, level: Level.Value, nl: String) extends java.io.Writer -{ - def this(delegate: Logger, level: Level.Value) = this(delegate, level, FileUtilities.Newline) - - private[this] val buffer = new StringBuilder - - override def close() = flush() - override def flush(): Unit = - synchronized { - if(buffer.length > 0) - { - log(buffer.toString) - buffer.clear() - } - } - override def write(content: Array[Char], offset: Int, length: Int): Unit = - synchronized { - buffer.append(content, offset, length) - process() - } - - private[this] def process() - { - val i = buffer.indexOf(nl) - if(i >= 0) - { - log(buffer.substring(0, i)) - buffer.delete(0, i + nl.length) - process() - } - } - private[this] def log(s: String): Unit = delegate.log(level, s) -} \ No newline at end of file diff --git a/sbt/src/main/scala/sbt/Main.scala b/sbt/src/main/scala/sbt/Main.scala index 6287c019a..49a93e568 100755 --- a/sbt/src/main/scala/sbt/Main.scala +++ b/sbt/src/main/scala/sbt/Main.scala @@ -416,7 +416,7 @@ class xMain extends xsbti.AppMain val ContinuousCompilePollDelaySeconds = 1 /** The list of logging levels.*/ - private def logLevels: Iterable[String] = TreeSet.empty[String] ++ Level.levels.map(_.toString) + private def logLevels: Iterable[String] = TreeSet.empty[String] ++ Level.values.map(_.toString) /** The list of all interactive commands other than logging level.*/ private def basicCommands: Iterable[String] = TreeSet(ShowProjectsAction, ShowActions, ShowCurrent, HelpAction, RebootCommand, TraceCommand, ContinuousCompileCommand, ProjectConsoleAction, BuilderCommand) ++ @@ -464,7 +464,7 @@ class xMain extends xsbti.AppMain printCmd(RebootCommand, "Reloads sbt, picking up modifications to sbt.version or scala.version and recompiling modified project definitions.") printCmd(HelpAction, "Displays this help message.") printCmd(ShowCurrent, "Shows the current project, Scala version, and logging level.") - printCmd(Level.levels.mkString(", "), "Set logging for the current project to the specified level.") + printCmd(Level.values.mkString(", "), "Set logging for the current project to the specified level.") printCmd(TraceCommand + " " + validTraceArguments, "Configures stack trace logging. " + traceExplanation) printCmd(ProjectAction + " ", "Sets the currently active project.") printCmd(ShowProjectsAction, "Shows all available projects.") diff --git a/sbt/src/test/scala/sbt/LogWriterTest.scala b/sbt/src/test/scala/sbt/LogWriterTest.scala index ec03eeca2..0d4dac14d 100644 --- a/sbt/src/test/scala/sbt/LogWriterTest.scala +++ b/sbt/src/test/scala/sbt/LogWriterTest.scala @@ -93,7 +93,7 @@ object LogWriterTest extends Properties("Log Writer") for(ls <- arbList[List[ToLog]].arbitrary; lv <- genLevel) yield new Output(ls, lv) - def levelsGen: Seq[Gen[Level.Value]] = Level.elements.toList.map(x => value(x)) + def levelsGen: Seq[Gen[Level.Value]] = Level.values.toList.map(x => value(x)) def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "") def addNewline(l: ToLog): ToLog = diff --git a/util/datatype/Generator.scala b/util/datatype/Generator.scala index 2a1d62022..442800776 100644 --- a/util/datatype/Generator.scala +++ b/util/datatype/Generator.scala @@ -1,7 +1,8 @@ /* sbt -- Simple Build Tool * Copyright 2009, 2010 Mark Harrah */ -package xsbt.api +package xsbt +package api import java.io.File import xsbt.FileUtilities diff --git a/util/log/BasicLogger.scala b/util/log/BasicLogger.scala index 23607c8ed..a52d3b433 100644 --- a/util/log/BasicLogger.scala +++ b/util/log/BasicLogger.scala @@ -1,15 +1,15 @@ /* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah + * Copyright 2008, 2009, 2010 Mark Harrah */ - package xsbt +package sbt /** Implements the level-setting methods of Logger.*/ -abstract class BasicLogger extends Logger +abstract class BasicLogger extends AbstractLogger { - private var traceEnabledVar = true + private var traceEnabledVar = java.lang.Integer.MAX_VALUE private var level: Level.Value = Level.Info def getLevel = level def setLevel(newLevel: Level.Value) { level = newLevel } - def enableTrace(flag: Boolean) { traceEnabledVar = flag } - def traceEnabled = traceEnabledVar -} + def setTrace(level: Int) { traceEnabledVar = level } + def getTrace = traceEnabledVar +} \ No newline at end of file diff --git a/util/log/BufferedLogger.scala b/util/log/BufferedLogger.scala index 7e8348f2d..1a72e022d 100644 --- a/util/log/BufferedLogger.scala +++ b/util/log/BufferedLogger.scala @@ -1,8 +1,9 @@ /* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah + * Copyright 2008, 2009, 2010 Mark Harrah */ package xsbt + import sbt.{AbstractLogger, ControlEvent, Level, Log, LogEvent, SetLevel, SetTrace, Success, Trace} import scala.collection.mutable.ListBuffer /** A logger that can buffer the logging done on it and then can flush the buffer @@ -13,7 +14,7 @@ * * This class assumes that it is the only client of the delegate logger. * */ -class BufferedLogger(delegate: Logger) extends Logger +class BufferedLogger(delegate: AbstractLogger) extends AbstractLogger { private[this] val buffer = new ListBuffer[LogEvent] private[this] var recording = false @@ -54,10 +55,10 @@ class BufferedLogger(delegate: Logger) extends Logger } def getLevel = delegate.getLevel def traceEnabled = delegate.traceEnabled - def enableTrace(flag: Boolean) + def setTrace(level: Int) { - buffer += new SetTrace(flag) - delegate.enableTrace(flag) + buffer += new SetTrace(level) + delegate.setTrace(level) } def trace(t: => Throwable): Unit = @@ -73,9 +74,9 @@ class BufferedLogger(delegate: Logger) extends Logger delegate.logAll(events) def control(event: ControlEvent.Value, message: => String): Unit = doBufferable(Level.Info, new ControlEvent(event, message), _.control(event, message)) - private def doBufferable(level: Level.Value, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit = + private def doBufferable(level: Level.Value, appendIfBuffered: => LogEvent, doUnbuffered: AbstractLogger => Unit): Unit = doBufferableIf(atLevel(level), appendIfBuffered, doUnbuffered) - private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit = + private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: AbstractLogger => Unit): Unit = if(condition) { if(recording) diff --git a/util/log/ConsoleLogger.scala b/util/log/ConsoleLogger.scala index a7217f026..49db31b66 100644 --- a/util/log/ConsoleLogger.scala +++ b/util/log/ConsoleLogger.scala @@ -1,7 +1,7 @@ /* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah + * Copyright 2008, 2009, 2010 Mark Harrah */ - package xsbt +package sbt object ConsoleLogger { @@ -17,10 +17,12 @@ object ConsoleLogger } /** A logger that logs to the console. On supported systems, the level labels are -* colored. */ +* colored. +* +* This logger is not thread-safe.*/ class ConsoleLogger extends BasicLogger { - import ConsoleLogger.formatEnabled + override def ansiCodesSupported = ConsoleLogger.formatEnabled def messageColor(level: Level.Value) = Console.RESET def labelColor(level: Level.Value) = level match @@ -39,8 +41,9 @@ class ConsoleLogger extends BasicLogger def trace(t: => Throwable): Unit = System.out.synchronized { - if(traceEnabled) - t.printStackTrace + val traceLevel = getTrace + if(traceLevel >= 0) + System.out.synchronized { System.out.print(StackTrace.trimmed(t, traceLevel)) } } def log(level: Level.Value, message: => String) { @@ -49,7 +52,7 @@ class ConsoleLogger extends BasicLogger } private def setColor(color: String) { - if(formatEnabled) + if(ansiCodesSupported) System.out.synchronized { System.out.print(color) } } private def log(labelColor: String, label: String, messageColor: String, message: String): Unit = diff --git a/util/log/FilterLogger.scala b/util/log/FilterLogger.scala new file mode 100644 index 000000000..152f6bdd5 --- /dev/null +++ b/util/log/FilterLogger.scala @@ -0,0 +1,35 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009, 2010 Mark Harrah + */ +package sbt + +/** A filter logger is used to delegate messages but not the logging level to another logger. This means +* that messages are logged at the higher of the two levels set by this logger and its delegate. +* */ +class FilterLogger(delegate: AbstractLogger) extends BasicLogger +{ + override lazy val ansiCodesSupported = delegate.ansiCodesSupported + def trace(t: => Throwable) + { + if(traceEnabled) + delegate.trace(t) + } + override def setTrace(level: Int) { delegate.setTrace(level) } + override def getTrace = delegate.getTrace + def log(level: Level.Value, message: => String) + { + if(atLevel(level)) + delegate.log(level, message) + } + def success(message: => String) + { + if(atLevel(Level.Info)) + delegate.success(message) + } + def control(event: ControlEvent.Value, message: => String) + { + if(atLevel(Level.Info)) + delegate.control(event, message) + } + def logAll(events: Seq[LogEvent]): Unit = delegate.logAll(events) +} diff --git a/util/log/Level.scala b/util/log/Level.scala index 86abc257d..ad4e51759 100644 --- a/util/log/Level.scala +++ b/util/log/Level.scala @@ -1,11 +1,11 @@ /* sbt -- Simple Build Tool * Copyright 2008, 2009 Mark Harrah */ - package xsbt + package sbt /** An enumeration defining the levels available for logging. A level includes all of the levels * with id larger than its own id. For example, Warn (id=3) includes Error (id=4).*/ -object Level extends Enumeration with NotNull +object Level extends Enumeration { val Debug = Value(1, "debug") val Info = Value(2, "info") @@ -16,10 +16,8 @@ object Level extends Enumeration with NotNull * label is also defined here. */ val SuccessLabel = "success" - // added because elements was renamed to iterator in 2.8.0 nightly - def levels = Debug :: Info :: Warn :: Error :: Nil /** Returns the level with the given name wrapped in Some, or None if no level exists for that name. */ - def apply(s: String) = levels.find(s == _.toString) + def apply(s: String) = values.find(s == _.toString) /** Same as apply, defined for use in pattern matching. */ - private[xsbt] def unapply(s: String) = apply(s) + private[sbt] def unapply(s: String) = apply(s) } \ No newline at end of file diff --git a/util/log/LogEvent.scala b/util/log/LogEvent.scala index 19a5b24db..ffe6049d7 100644 --- a/util/log/LogEvent.scala +++ b/util/log/LogEvent.scala @@ -1,14 +1,14 @@ /* sbt -- Simple Build Tool * Copyright 2008, 2009 Mark Harrah */ - package xsbt + package sbt sealed trait LogEvent extends NotNull final class Success(val msg: String) extends LogEvent final class Log(val level: Level.Value, val msg: String) extends LogEvent final class Trace(val exception: Throwable) extends LogEvent final class SetLevel(val newLevel: Level.Value) extends LogEvent -final class SetTrace(val enabled: Boolean) extends LogEvent +final class SetTrace(val level: Int) extends LogEvent final class ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent object ControlEvent extends Enumeration diff --git a/util/log/Logger.scala b/util/log/Logger.scala index 153596f6f..1be353c4b 100644 --- a/util/log/Logger.scala +++ b/util/log/Logger.scala @@ -1,18 +1,22 @@ /* sbt -- Simple Build Tool * Copyright 2008, 2009 Mark Harrah */ - package xsbt + package sbt import xsbti.{Logger => xLogger, F0} -abstract class Logger extends xLogger with NotNull + +abstract class AbstractLogger extends xLogger with NotNull { def getLevel: Level.Value def setLevel(newLevel: Level.Value) - def enableTrace(flag: Boolean) - def traceEnabled: Boolean + def setTrace(flag: Int) + def getTrace: Int + final def traceEnabled = getTrace >= 0 + def ansiCodesSupported = false def atLevel(level: Level.Value) = level.id >= getLevel.id def trace(t: => Throwable): Unit + final def verbose(message: => String): Unit = debug(message) final def debug(message: => String): Unit = log(Level.Debug, message) final def info(message: => String): Unit = log(Level.Info, message) final def warn(message: => String): Unit = log(Level.Warn, message) @@ -31,7 +35,7 @@ abstract class Logger extends xLogger with NotNull case l: Log => log(l.level, l.msg) case t: Trace => trace(t.exception) case setL: SetLevel => setLevel(setL.newLevel) - case setT: SetTrace => enableTrace(setT.enabled) + case setT: SetTrace => setTrace(setT.level) case c: ControlEvent => control(c.event, c.msg) } } diff --git a/util/log/LoggerWriter.scala b/util/log/LoggerWriter.scala new file mode 100644 index 000000000..b3b2d54d3 --- /dev/null +++ b/util/log/LoggerWriter.scala @@ -0,0 +1,40 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009, 2010 Mark Harrah + */ +package sbt + +/** Provides a `java.io.Writer` interface to a `Logger`. Content is line-buffered and logged at `level`. +* A line is delimited by `nl`, which is by default the platform line separator.*/ +class LoggerWriter(delegate: AbstractLogger, level: Level.Value, nl: String) extends java.io.Writer +{ + def this(delegate: AbstractLogger, level: Level.Value) = this(delegate, level, System.getProperty("line.separator")) + + private[this] val buffer = new StringBuilder + + override def close() = flush() + override def flush(): Unit = + synchronized { + if(buffer.length > 0) + { + log(buffer.toString) + buffer.clear() + } + } + override def write(content: Array[Char], offset: Int, length: Int): Unit = + synchronized { + buffer.append(content, offset, length) + process() + } + + private[this] def process() + { + val i = buffer.indexOf(nl) + if(i >= 0) + { + log(buffer.substring(0, i)) + buffer.delete(0, i + nl.length) + process() + } + } + private[this] def log(s: String): Unit = delegate.log(level, s) +} \ No newline at end of file diff --git a/util/log/MultiLogger.scala b/util/log/MultiLogger.scala new file mode 100644 index 000000000..800d170ed --- /dev/null +++ b/util/log/MultiLogger.scala @@ -0,0 +1,27 @@ + +/* sbt -- Simple Build Tool + * Copyright 2008, 2009, 2010 Mark Harrah + */ +package sbt + + +class MultiLogger(delegates: List[AbstractLogger]) extends BasicLogger +{ + override lazy val ansiCodesSupported = delegates.forall(_.ansiCodesSupported) + override def setLevel(newLevel: Level.Value) + { + super.setLevel(newLevel) + dispatch(new SetLevel(newLevel)) + } + override def setTrace(level: Int) + { + super.setTrace(level) + dispatch(new SetTrace(level)) + } + def trace(t: => Throwable) { dispatch(new Trace(t)) } + def log(level: Level.Value, message: => String) { dispatch(new Log(level, message)) } + def success(message: => String) { dispatch(new Success(message)) } + def logAll(events: Seq[LogEvent]) { delegates.foreach(_.logAll(events)) } + def control(event: ControlEvent.Value, message: => String) { delegates.foreach(_.control(event, message)) } + private def dispatch(event: LogEvent) { delegates.foreach(_.log(event)) } +} \ No newline at end of file