* limit stack trace length: trace 'on' | 'off' | 'nosbt' | 1 | 2 | ...

* updating license/copyright
This commit is contained in:
Mark Harrah 2010-01-14 00:15:21 -05:00
parent 791c7a2a14
commit b6cb89fea4
10 changed files with 144 additions and 82 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2008, 2009 Steven Blundy, Mark Harrah, David MacIver, Mikko Peltonen Copyright (c) 2008, 2009, 2010 Steven Blundy, Josh Cough, Nathan Hamblen, Mark Harrah, David MacIver, Mikko Peltonen, Tony Sloane, Vesa Vilhonen
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

29
NOTICE
View File

@ -1,5 +1,6 @@
Simple Build Tool (sbt) Simple Build Tool (sbt)
Copyright 2008, 2009 Steven Blundy, Mark Harrah, David MacIver, Mikko Peltonen Copyright 2008, 2009, 2010 Steven Blundy, Josh Cough, Nathan Hamblen, Mark Harrah, David MacIver, Mikko Peltonen, Tony Sloane, Vesa Vilhonen
Licensed under BSD-style license (see LICENSE)
Portions based on code by Mike Clark in JDepend Portions based on code by Mike Clark in JDepend
@ -14,30 +15,12 @@ Portions based on code from the Scala compiler
Copyright 2002-2008 EPFL, Lausanne Copyright 2002-2008 EPFL, Lausanne
Licensed under BSD-style license (see licenses/LICENSE_Scala) Licensed under BSD-style license (see licenses/LICENSE_Scala)
Portions based on code from specs JLine is distributed with the sbt launcher.
Copyright 2007-2008 Eric Torreborre It is licensed under a BSD-style license (see licenses/LICENSE_JLine)
Licensed under MIT license (see licenses/LICENSE_specs)
Portions based on code from ScalaTest
Copyright 2001-2008 Artima, Inc.
Licensed under the Apache License, Version 2.0(see licenses/LICENSE_Apache)
Portions based on code from ScalaCheck
Copyright 2007, Rickard Nilsson
Licensed under BSD-style license (see licenses/LICENSE_ScalaCheck)
Jetty is licensed under the Apache License, Version 2.0 (see licenses/LICENSE_Apache).
ScalaTest is distributed with sbt (in the subversion repository)
and requires the following notice:
This product includes software developed by
Artima, Inc. (http://www.artima.com/).
Apache Ivy, licensed under the Apache License, Version 2.0 Apache Ivy, licensed under the Apache License, Version 2.0
(see licenses/LICENSE_Apache) is distributed with sbt and (see licenses/LICENSE_Apache) is distributed with the sbt launcher.
requires the following notice: It requires the following notice:
This product includes software developed by This product includes software developed by
The Apache Software Foundation (http://www.apache.org/). The Apache Software Foundation (http://www.apache.org/).

View File

@ -1,4 +1,4 @@
Copyright (c) 2008 Mark Harrah, David MacIver Copyright (c) 2008, 2009, 2010 Steven Blundy, Josh Cough, Nathan Hamblen, Mark Harrah, David MacIver, Mikko Peltonen, Tony Sloane, Vesa Vilhonen
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -10,7 +10,7 @@ final class Success(val msg: String) extends LogEvent
final class Log(val level: Level.Value, 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 Trace(val exception: Throwable) extends LogEvent
final class SetLevel(val newLevel: Level.Value) 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 final class ControlEvent(val event: ControlEvent.Value, val msg: String) extends LogEvent
object ControlEvent extends Enumeration object ControlEvent extends Enumeration
@ -22,8 +22,9 @@ abstract class Logger extends xsbt.CompileLogger with xsbt.IvyLogger
{ {
def getLevel: Level.Value def getLevel: Level.Value
def setLevel(newLevel: Level.Value) def setLevel(newLevel: Level.Value)
def enableTrace(flag: Boolean) def setTrace(flag: Int)
def traceEnabled: Boolean def getTrace: Int
final def traceEnabled = getTrace >= 0
def ansiCodesSupported = false def ansiCodesSupported = false
def atLevel(level: Level.Value) = level.id >= getLevel.id def atLevel(level: Level.Value) = level.id >= getLevel.id
@ -47,7 +48,7 @@ abstract class Logger extends xsbt.CompileLogger with xsbt.IvyLogger
case l: Log => log(l.level, l.msg) case l: Log => log(l.level, l.msg)
case t: Trace => trace(t.exception) case t: Trace => trace(t.exception)
case setL: SetLevel => setLevel(setL.newLevel) 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) case c: ControlEvent => control(c.event, c.msg)
} }
} }
@ -64,12 +65,12 @@ abstract class Logger extends xsbt.CompileLogger with xsbt.IvyLogger
/** Implements the level-setting methods of Logger.*/ /** Implements the level-setting methods of Logger.*/
abstract class BasicLogger extends Logger abstract class BasicLogger extends Logger
{ {
private var traceEnabledVar = true private var traceEnabledVar = java.lang.Integer.MAX_VALUE
private var level: Level.Value = Level.Info private var level: Level.Value = Level.Info
def getLevel = level def getLevel = level
def setLevel(newLevel: Level.Value) { level = newLevel } def setLevel(newLevel: Level.Value) { level = newLevel }
def enableTrace(flag: Boolean) { traceEnabledVar = flag } def setTrace(level: Int) { traceEnabledVar = level }
def traceEnabled = traceEnabledVar def getTrace = traceEnabledVar
} }
final class SynchronizedLogger(delegate: Logger) extends Logger final class SynchronizedLogger(delegate: Logger) extends Logger
@ -77,8 +78,8 @@ final class SynchronizedLogger(delegate: Logger) extends Logger
override lazy val ansiCodesSupported = delegate.ansiCodesSupported override lazy val ansiCodesSupported = delegate.ansiCodesSupported
def getLevel = { synchronized { delegate.getLevel } } def getLevel = { synchronized { delegate.getLevel } }
def setLevel(newLevel: Level.Value) { synchronized { delegate.setLevel(newLevel) } } def setLevel(newLevel: Level.Value) { synchronized { delegate.setLevel(newLevel) } }
def enableTrace(enabled: Boolean) { synchronized { delegate.enableTrace(enabled) } } def setTrace(level: Int) { synchronized { delegate.setTrace(level) } }
def traceEnabled: Boolean = { synchronized { delegate.traceEnabled } } def getTrace: Int = { synchronized { delegate.getTrace } }
def trace(t: => Throwable) { synchronized { delegate.trace(t) } } def trace(t: => Throwable) { synchronized { delegate.trace(t) } }
def log(level: Level.Value, message: => String) { synchronized { delegate.log(level, message) } } def log(level: Level.Value, message: => String) { synchronized { delegate.log(level, message) } }
@ -95,10 +96,10 @@ final class MultiLogger(delegates: List[Logger]) extends BasicLogger
super.setLevel(newLevel) super.setLevel(newLevel)
dispatch(new SetLevel(newLevel)) dispatch(new SetLevel(newLevel))
} }
override def enableTrace(enabled: Boolean) override def setTrace(level: Int)
{ {
super.enableTrace(enabled) super.setTrace(level)
dispatch(new SetTrace(enabled)) dispatch(new SetTrace(level))
} }
def trace(t: => Throwable) { dispatch(new Trace(t)) } def trace(t: => Throwable) { dispatch(new Trace(t)) }
def log(level: Level.Value, message: => String) { dispatch(new Log(level, message)) } def log(level: Level.Value, message: => String) { dispatch(new Log(level, message)) }
@ -119,6 +120,8 @@ final class FilterLogger(delegate: Logger) extends BasicLogger
if(traceEnabled) if(traceEnabled)
delegate.trace(t) delegate.trace(t)
} }
override def setTrace(level: Int) { delegate.setTrace(level) }
override def getTrace = delegate.getTrace
def log(level: Level.Value, message: => String) def log(level: Level.Value, message: => String)
{ {
if(atLevel(level)) if(atLevel(level))
@ -216,12 +219,12 @@ final class BufferedLogger(delegate: Logger) extends Logger
delegate.setLevel(newLevel) delegate.setLevel(newLevel)
} }
def getLevel = synchronized { delegate.getLevel } def getLevel = synchronized { delegate.getLevel }
def traceEnabled = synchronized { delegate.traceEnabled } def getTrace = synchronized { delegate.getTrace }
def enableTrace(flag: Boolean): Unit = def setTrace(level: Int): Unit =
synchronized synchronized
{ {
buffer.foreach{_ += new SetTrace(flag) } buffer.foreach{_ += new SetTrace(level) }
delegate.enableTrace(flag) delegate.setTrace(level)
} }
def trace(t: => Throwable): Unit = def trace(t: => Throwable): Unit =
@ -295,8 +298,9 @@ class ConsoleLogger extends BasicLogger
def trace(t: => Throwable): Unit = def trace(t: => Throwable): Unit =
System.out.synchronized System.out.synchronized
{ {
if(traceEnabled) val traceLevel = getTrace
t.printStackTrace if(traceLevel >= 0)
System.out.synchronized { System.out.print(StackTrace.trimmed(t, traceLevel)) }
} }
def log(level: Level.Value, message: => String) def log(level: Level.Value, message: => String)
{ {

View File

@ -29,6 +29,7 @@ object Main
val UsageErrorExitCode = 4 val UsageErrorExitCode = 4
val BuildErrorExitCode = 5 val BuildErrorExitCode = 5
val ProgramErrorExitCode = 6 val ProgramErrorExitCode = 6
val MaxInt = java.lang.Integer.MAX_VALUE
} }
import Main._ import Main._
@ -385,6 +386,8 @@ class xMain extends xsbti.AppMain
setProperty(currentProject, action.substring(SetAction.length + 1)) setProperty(currentProject, action.substring(SetAction.length + 1))
else if(action.startsWith(GetAction + " ")) else if(action.startsWith(GetAction + " "))
getProperty(currentProject, action.substring(GetAction.length + 1)) getProperty(currentProject, action.substring(GetAction.length + 1))
else if(action.startsWith(TraceCommand + " "))
setTrace(currentProject, action.substring(TraceCommand.length + 1))
else else
handleCommand(currentProject, action) handleCommand(currentProject, action)
} }
@ -432,6 +435,7 @@ class xMain extends xsbti.AppMain
case GetAction => getArgumentError(project.log) case GetAction => getArgumentError(project.log)
case SetAction => setArgumentError(project.log) case SetAction => setArgumentError(project.log)
case ProjectAction => setProjectError(project.log) case ProjectAction => setProjectError(project.log)
case TraceCommand => setTraceError(project.log); true
case ShowCurrent => case ShowCurrent =>
printProject("Current project is ", project) printProject("Current project is ", project)
Console.println("Current Scala version is " + project.buildScalaVersion) Console.println("Current Scala version is " + project.buildScalaVersion)
@ -439,7 +443,6 @@ class xMain extends xsbti.AppMain
printTraceEnabled(project) printTraceEnabled(project)
true true
case ShowActions => showActions(project); true case ShowActions => showActions(project); true
case TraceCommand => toggleTrace(project); true
case Level(level) => setLevel(project, level); true case Level(level) => setLevel(project, level); true
case ContinuousCompileCommand => compileContinuously(project) case ContinuousCompileCommand => compileContinuously(project)
case action if action.startsWith(ContinuousExecutePrefix) => executeContinuously(project, action.substring(ContinuousExecutePrefix.length).trim) case action if action.startsWith(ContinuousExecutePrefix) => executeContinuously(project, action.substring(ContinuousExecutePrefix.length).trim)
@ -493,15 +496,21 @@ class xMain extends xsbti.AppMain
} }
/** Toggles whether stack traces are enabled.*/ /** Toggles whether stack traces are enabled.*/
private def toggleTrace(project: Project) private def setTrace(project: Project, value: String): Boolean =
{ {
val newValue = !project.log.traceEnabled try
project.projectClosure.foreach(_.log.enableTrace(newValue)) {
printTraceEnabled(project) val newValue = if(value == "on") MaxInt else if(value == "off") -1 else if(value == "nosbt") 0 else value.toInt
project.projectClosure.foreach(_.log.setTrace(newValue))
printTraceEnabled(project)
true
}
catch { case _: NumberFormatException => setTraceError(project.log) }
} }
private def printTraceEnabled(project: Project) private def printTraceEnabled(project: Project)
{ {
Console.println("Stack traces are " + (if(project.log.traceEnabled) "enabled" else "disabled")) def traceLevel(level: Int) = if(level == 0) " (no stack elements)" else if(level == MaxInt) "" else " (maximum " + level + " stack elements per exception)"
Console.println("Stack traces are " + (if(project.log.traceEnabled) "enabled" + traceLevel(project.log.getTrace) else "disabled"))
} }
/** Sets the logging level on the given project.*/ /** Sets the logging level on the given project.*/
private def setLevel(project: Project, level: Level.Value) private def setLevel(project: Project, level: Level.Value)
@ -688,6 +697,7 @@ class xMain extends xsbti.AppMain
} }
private def isTerminateAction(s: String) = TerminateActions.elements.contains(s.toLowerCase) private def isTerminateAction(s: String) = TerminateActions.elements.contains(s.toLowerCase)
private def setTraceError(log: Logger) = logError(log)("Invalid arguments for 'trace': expected 'on', 'off', or integer number of stack elements to show per exception.")
private def setArgumentError(log: Logger) = logError(log)("Invalid arguments for 'set': expected property name and new value.") private def setArgumentError(log: Logger) = logError(log)("Invalid arguments for 'set': expected property name and new value.")
private def getArgumentError(log: Logger) = logError(log)("Invalid arguments for 'get': expected property name.") private def getArgumentError(log: Logger) = logError(log)("Invalid arguments for 'get': expected property name.")
private def setProjectError(log: Logger) = logError(log)("Invalid arguments for 'project': expected project name.") private def setProjectError(log: Logger) = logError(log)("Invalid arguments for 'project': expected project name.")

View File

@ -311,7 +311,6 @@ object Project
{ {
val log = new ConsoleLogger val log = new ConsoleLogger
log.setLevel(Level.Debug) log.setLevel(Level.Debug)
log.enableTrace(true)
log log
} }

View File

@ -82,7 +82,6 @@ class Resources(val baseDirectory: File, additional: ClassLoader, app: AppProvid
{ {
val buffered = new BufferedLogger(log) val buffered = new BufferedLogger(log)
buffered.setLevel(Level.Debug) buffered.setLevel(Level.Debug)
buffered.enableTrace(true)
def error(msg: String) = def error(msg: String) =
{ {
buffered.stopAll() buffered.stopAll()

View File

@ -0,0 +1,63 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Tony Sloane
*/
package sbt
object StackTrace
{
def isSbtClass(name: String) = name.startsWith("sbt") || name.startsWith("xsbt")
/**
* Return a printable representation of the stack trace associated
* with t. Information about t and its Throwable causes is included.
* The number of lines to be included for each Throwable is configured
* via d which should be greater than or equal to zero. If d is zero,
* then all elements are included up to (but not including) the first
* element that comes from sbt. If d is greater than zero, then up to
* that many lines are included, where the line for the Throwable is
* counted plus one line for each stack element. Less lines will be
* included if there are not enough stack elements.
*/
def trimmed(t : Throwable, d : Int) : String = {
require(d >= 0)
val b = new StringBuilder ()
def appendStackTrace (t : Throwable, first : Boolean) {
val include : StackTraceElement => Boolean =
if (d == 0)
element => !isSbtClass(element.getClassName)
else {
var count = d - 1
(_ => { count -= 1; count >= 0 })
}
def appendElement (e : StackTraceElement) {
b.append ("\tat ")
b.append (e)
b.append ('\n')
}
if (!first)
b.append ("Caused by: ")
b.append (t)
b.append ('\n')
val els = t.getStackTrace ()
var i = 0
while ((i < els.size) && include (els (i))) {
appendElement (els (i))
i += 1
}
}
appendStackTrace (t, true)
var c = t
while (c.getCause () != null) {
c = c.getCause ()
appendStackTrace (c, false)
}
b.toString ()
}
}

View File

@ -1,5 +1,5 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008 Mark Harrah * Copyright 2008, 2009, 2010 Mark Harrah
*/ */
package sbt package sbt
@ -82,9 +82,6 @@ private trait JettyRun
} }
sealed trait JettyConfiguration extends NotNull sealed trait JettyConfiguration extends NotNull
{ {
def war: Path
def scanDirectories: Seq[File]
def scanInterval: Int
/** The classpath to get Jetty from. */ /** The classpath to get Jetty from. */
def jettyClasspath: PathFinder def jettyClasspath: PathFinder
def classpathName: String def classpathName: String
@ -92,6 +89,10 @@ sealed trait JettyConfiguration extends NotNull
} }
trait DefaultJettyConfiguration extends JettyConfiguration trait DefaultJettyConfiguration extends JettyConfiguration
{ {
def war: Path
def scanDirectories: Seq[File]
def scanInterval: Int
def contextPath: String def contextPath: String
def port: Int def port: Int
/** The classpath containing the classes, jars, and resources for the web application. */ /** The classpath containing the classes, jars, and resources for the web application. */
@ -129,7 +130,27 @@ private object LazyJettyRun extends JettyRun
Log.setLog(new JettyLogger(configuration.log)) Log.setLog(new JettyLogger(configuration.log))
val server = new Server val server = new Server
val listener = def configureScanner(listener: Scanner.BulkListener, scanDirectories: Seq[File], scanInterval: Int) =
{
if(scanDirectories.isEmpty)
None
else
{
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
val scanner = new Scanner
val list = new java.util.ArrayList[File]
scanDirectories.foreach(x => list.add(x))
scanner.setScanDirs(list)
scanner.setRecursive(true)
scanner.setScanInterval(scanInterval)
scanner.setReportExistingFilesOnStartup(false)
scanner.addListener(listener)
scanner.start()
Some(new WeakReference(scanner))
}
}
val (listener, scanner) =
configuration match configuration match
{ {
case c: DefaultJettyConfiguration => case c: DefaultJettyConfiguration =>
@ -144,43 +165,23 @@ private object LazyJettyRun extends JettyRun
setLoader() setLoader()
server.setHandler(webapp) server.setHandler(webapp)
Some(new Scanner.BulkListener with Reload { val listener = new Scanner.BulkListener with Reload {
def reloadApp() = reload(server, setLoader(), log) def reloadApp() = reload(server, setLoader(), log)
def filesChanged(files: java.util.List[_]) { reloadApp() } def filesChanged(files: java.util.List[_]) { reloadApp() }
}) }
(Some(listener), configureScanner(listener, c.scanDirectories, c.scanInterval))
case c: CustomJettyConfiguration => case c: CustomJettyConfiguration =>
for(x <- c.jettyConfigurationXML) for(x <- c.jettyConfigurationXML)
(new XmlConfiguration(x.toString)).configure(server) (new XmlConfiguration(x.toString)).configure(server)
for(file <- c.jettyConfigurationFiles) for(file <- c.jettyConfigurationFiles)
(new XmlConfiguration(file.toURI.toURL)).configure(server) (new XmlConfiguration(file.toURI.toURL)).configure(server)
None (None, None)
} }
def configureScanner() =
{
val scanDirectories = configuration.scanDirectories
if(listener.isEmpty || scanDirectories.isEmpty)
None
else
{
configuration.log.debug("Scanning for changes to: " + scanDirectories.mkString(", "))
val scanner = new Scanner
val list = new java.util.ArrayList[File]
scanDirectories.foreach(x => list.add(x))
scanner.setScanDirs(list)
scanner.setRecursive(true)
scanner.setScanInterval(configuration.scanInterval)
scanner.setReportExistingFilesOnStartup(false)
scanner.addListener(listener.get)
scanner.start()
Some(new WeakReference(scanner))
}
}
try try
{ {
server.start() server.start()
new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), configureScanner(), oldLog) new StopServer(new WeakReference(server), listener.map(new WeakReference(_)), scanner, oldLog)
} }
catch { case e => server.stop(); throw e } catch { case e => server.stop(); throw e }
} }

View File

@ -0,0 +1,3 @@
import sbt._
class BlankProject(info: ProjectInfo) extends DefaultProject(info)