Filling in logging and making cross-compile work.

This commit is contained in:
Mark Harrah 2009-09-05 12:19:34 -04:00
parent b094fc3cc8
commit 3aba701b00
8 changed files with 236 additions and 75 deletions

View File

@ -0,0 +1,6 @@
package xsbti;
public abstract class CompileFailed extends RuntimeException
{
public abstract String[] arguments();
}

View File

@ -1,38 +0,0 @@
package xsbti
class TestLogger extends Logger
{
private val buffer = new scala.collection.mutable.ArrayBuffer[F0[Unit]]
def info(msg: F0[String]) = buffer("[info] ", msg)
def warn(msg: F0[String]) = buffer("[warn] ", msg)
def debug(msg: F0[String]) = buffer("[debug] ", msg)
def error(msg: F0[String]) = buffer("[error] ", msg)
def verbose(msg: F0[String]) = buffer("[verbose] ", msg)
def info(msg: => String) = buffer("[info] ", msg)
def warn(msg: => String) = buffer("[warn] ", msg)
def debug(msg: => String) = buffer("[debug] ", msg)
def error(msg: => String) = buffer("[error] ", msg)
def verbose(msg: => String) = buffer("[verbose] ", msg)
def show() { buffer.foreach(_()) }
def clear() { buffer.clear() }
def trace(t: F0[Throwable]) { buffer += f0(t().printStackTrace) }
private def buffer(s: String, msg: F0[String]) { buffer(s, msg()) }
private def buffer(s: String, msg: => String) { buffer += f0(println(s + msg)) }
}
object TestLogger
{
def apply[T](f: Logger => T): T =
{
val log = new TestLogger
try { f(log) }
catch { case e: Exception => log.show(); throw e }
finally { log.clear() }
}
def apply[L <: TestLogger, T](newLogger: => L)(f: L => T): T =
{
val log = newLogger
try { f(log) }
catch { case e: Exception => log.show(); throw e }
finally { log.clear() }
}
}

View File

@ -0,0 +1,15 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah
*/
package xsbt
/** Implements the level-setting methods of Logger.*/
abstract class BasicLogger extends Logger
{
private var traceEnabledVar = true
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
}

View File

@ -0,0 +1,86 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah
*/
package xsbt
import scala.collection.mutable.ListBuffer
/** A logger that can buffer the logging done on it and then can flush the buffer
* to the delegate logger provided in the constructor. Use 'startRecording' to
* start buffering and then 'play' from to flush the buffer to the backing logger.
* The logging level set at the time a message is originally logged is used, not
* the level at the time 'play' is called.
*
* This class assumes that it is the only client of the delegate logger.
* */
class BufferedLogger(delegate: Logger) extends Logger
{
private[this] val buffer = new ListBuffer[LogEvent]
private[this] var recording = false
/** Enables buffering. */
def record() = { recording = true }
def buffer[T](f: => T): T =
{
record()
try { f }
finally { stopQuietly() }
}
def bufferQuietly[T](f: => T): T =
{
record()
try
{
val result = f
clear()
result
}
catch { case e => stopQuietly(); throw e }
}
private def stopQuietly() = try { stop() } catch { case e: Exception => () }
/** Flushes the buffer to the delegate logger. This method calls logAll on the delegate
* so that the messages are written consecutively. The buffer is cleared in the process. */
def play() { delegate.logAll(buffer.readOnly); buffer.clear() }
/** Clears buffered events and disables buffering. */
def clear(): Unit = { buffer.clear(); recording = false }
/** Plays buffered events and disables buffering. */
def stop() { play(); clear() }
def setLevel(newLevel: Level.Value)
{
buffer += new SetLevel(newLevel)
delegate.setLevel(newLevel)
}
def getLevel = delegate.getLevel
def traceEnabled = delegate.traceEnabled
def enableTrace(flag: Boolean)
{
buffer += new SetTrace(flag)
delegate.enableTrace(flag)
}
def trace(t: => Throwable): Unit =
doBufferableIf(traceEnabled, new Trace(t), _.trace(t))
def success(message: => String): Unit =
doBufferable(Level.Info, new Success(message), _.success(message))
def log(level: Level.Value, message: => String): Unit =
doBufferable(level, new Log(level, message), _.log(level, message))
def logAll(events: Seq[LogEvent]): Unit =
if(recording)
buffer ++= events
else
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 =
doBufferableIf(atLevel(level), appendIfBuffered, doUnbuffered)
private def doBufferableIf(condition: => Boolean, appendIfBuffered: => LogEvent, doUnbuffered: Logger => Unit): Unit =
if(condition)
{
if(recording)
buffer += appendIfBuffered
else
doUnbuffered(delegate)
}
}

View File

@ -0,0 +1,76 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah
*/
package xsbt
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. */
class ConsoleLogger extends BasicLogger
{
import 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
{
if(traceEnabled)
t.printStackTrace
}
def log(level: Level.Value, message: => String)
{
if(atLevel(level))
log(labelColor(level), level.toString, messageColor(level), message)
}
private def setColor(color: String)
{
if(formatEnabled)
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) }
}

25
util/log/Level.scala Normal file
View File

@ -0,0 +1,25 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah
*/
package xsbt
/** 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[xsbt] def unapply(s: String) = apply(s)
}

17
util/log/LogEvent.scala Normal file
View File

@ -0,0 +1,17 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah
*/
package xsbt
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 ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent
object ControlEvent extends Enumeration
{
val Start, Header, Finish = Value
}

View File

@ -3,13 +3,14 @@
*/
package xsbt
abstract class Logger extends NotNull
import xsbti.{Logger => xLogger, F0}
abstract class Logger extends xLogger with NotNull
{
def getLevel: Level.Value
def setLevel(newLevel: Level.Value)
def enableTrace(flag: Boolean)
def traceEnabled: Boolean
def atLevel(level: Level.Value) = level.id >= getLevel.id
def trace(t: => Throwable): Unit
final def debug(message: => String): Unit = log(Level.Debug, message)
@ -19,7 +20,7 @@ abstract class Logger extends NotNull
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)
@ -34,38 +35,11 @@ abstract class Logger extends NotNull
case c: ControlEvent => control(c.event, c.msg)
}
}
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)
}
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 ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent
object ControlEvent extends Enumeration
{
val Start, Header, Finish = Value
}
/** 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[xsbt] def unapply(s: String) = apply(s)
}