command logging through Streams, 'last' without a key to redisplay it

This commit is contained in:
Mark Harrah 2011-03-21 20:26:04 -04:00
parent f34c3b5837
commit 1de086755b
8 changed files with 48 additions and 21 deletions

View File

@ -86,7 +86,7 @@ object Command
case Right(s) => s() // apply command. command side effects happen here
case Left((msg,pos)) =>
val errMsg = commandError(command, msg, pos)
logger(state).info(errMsg)
logger(state).error(errMsg)
state.fail
}
}

View File

@ -46,10 +46,11 @@ EvalCommand + """ <expression>
val lastGrepBrief = (LastGrepCommand + " <pattern> <key>", "Shows lines from the last output for 'key' that match 'pattern'.")
val lastGrepDetailed =
LastGrepCommand + """ <pattern> <key>
LastGrepCommand + """ <pattern> [key]
<pattern> is a regular expression interpreted by java.util.Pattern.
Lines that match 'pattern' from the last streams output associated with the key are displayed.
If no key is specified, the global streams output is used.
See also """ + LastCommand + "."
val lastBrief = (LastCommand + " <key>", "Prints the last output associated with 'key'.")
@ -57,6 +58,7 @@ LastGrepCommand + """ <pattern> <key>
LastCommand + """ <key>
Redisplays the last streams output associated with the key (typically a task key).
If no key is specified, the global streams output is displayed.
See also """ + LastGrepCommand + "."
val InspectCommand = "inspect"

View File

@ -247,13 +247,14 @@ object BuiltinCommands
s
}
def lastGrep = Command(LastGrepCommand, lastGrepBrief, lastGrepDetailed)(lastGrepParser) { case (s,(pattern,sk)) =>
Output.lastGrep(sk.scope, sk.key, Project.structure(s).streams, pattern)
Output.lastGrep(sk, Project.structure(s).streams, pattern)
s
}
val spacedKeyParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.scopedKeyParser(s))
def lastGrepParser(s: State) = Act.requireSession(s, (token(Space) ~> token(NotSpace, "<pattern>")) ~ spacedKeyParser(s))
def last = Command(LastCommand, lastBrief, lastDetailed)(spacedKeyParser) { (s,sk) =>
Output.last(sk.scope, sk.key, Project.structure(s).streams)
val optSpacedKeyParser = (s: State) => spacedKeyParser(s).?
def lastGrepParser(s: State) = Act.requireSession(s, (token(Space) ~> token(NotSpace, "<pattern>")) ~ optSpacedKeyParser(s))
def last = Command(LastCommand, lastBrief, lastDetailed)(optSpacedKeyParser) { (s,sk) =>
Output.last(sk, Project.structure(s).streams)
s
}
@ -334,6 +335,7 @@ object BuiltinCommands
case _ =>
log.trace(e)
log.error(e.toString)
log.error("Use 'last' for the full log.")
}
s.fail
}

View File

@ -23,14 +23,16 @@ object Output
None
}
def last(scope: Scope, key: AttributeKey[_], mgr: Streams): Unit =
printLines(lastLines(ScopedKey(scope,key), mgr))
def last(key: Option[ScopedKey[_]], mgr: Streams): Unit =
printLines(lastLines(key, mgr))
def printLines(lines: Seq[String]) = lines foreach println
def lastGrep(scope: Scope, key: AttributeKey[_], mgr: Streams, patternString: String)
def lastGrep(key: Option[ScopedKey[_]], mgr: Streams, patternString: String)
{
val pattern = Pattern.compile(patternString)
printLines(lastLines(ScopedKey(scope,key), mgr).flatMap(showMatches(pattern)) )
printLines(lastLines(key, mgr).flatMap(showMatches(pattern)) )
}
def lastLines(key: Option[ScopedKey[_]], mgr: Streams): Seq[String] =
lastLines(key getOrElse Project.globalLoggerKey, mgr)
def lastLines(key: ScopedKey[_], mgr: Streams): Seq[String] =
mgr.use(key) { s => IO.readLines(s.readText( Project.fillTaskAxis(key) )) }
}

View File

@ -6,7 +6,7 @@ package sbt
import java.io.File
import java.net.URI
import Project._
import Keys.{appConfiguration, buildStructure, commands, configuration, historyPath, projectCommand, sessionSettings, shellPrompt, thisProject, thisProjectRef, watch}
import Keys.{appConfiguration, buildStructure, commands, configuration, historyPath, logged, projectCommand, sessionSettings, shellPrompt, streams, thisProject, thisProjectRef, watch}
import Scope.{GlobalScope,ThisScope}
import CommandSupport.logger
@ -88,9 +88,10 @@ object Project extends Init[Scope]
updateCurrent(newState.runExitHooks())
}
def current(state: State): ProjectRef = session(state).current
def updateCurrent(s: State): State =
def updateCurrent(s0: State): State =
{
val structure = Project.structure(s)
val structure = Project.structure(s0)
val s = installGlobalLogger(s0, structure)
val ref = Project.current(s)
val project = Load.getProject(structure.units, ref.build, ref.project)
logger(s).info("Set current project to " + ref.project + " (in build " + ref.build +")")
@ -225,6 +226,13 @@ object Project extends Init[Scope]
val extracted = Project.extract(state)
EvaluateTask.evaluateTask(extracted.structure, taskKey, state, extracted.currentRef, checkCycles, maxWorkers)
}
def globalLoggerKey = fillTaskAxis(ScopedKey(GlobalScope, streams.key))
def installGlobalLogger(s: State, structure: Load.BuildStructure): State =
{
val str = structure.streams(globalLoggerKey)
str.open()
s.put(logged, str.log).addExitHook { str.close() }
}
}
trait ProjectConstructors

View File

@ -41,8 +41,10 @@ trait StateOps {
def + (newCommand: Command): State
def get[T](key: AttributeKey[T]): Option[T]
def put[T](key: AttributeKey[T], value: T): State
def remove(key: AttributeKey[_]): State
def baseDir: File
def runExitHooks(): State
def addExitHook(f: => Unit): State
}
object State
{
@ -63,8 +65,9 @@ object State
def reboot(full: Boolean) = throw new xsbti.FullReload(s.remainingCommands.toArray, full)
def reload = setNext(Next.Reload)
def exit(ok: Boolean) = setNext(if(ok) Next.Done else Next.Fail)
def get[T](key: AttributeKey[T]) = s.attributes.get(key)
def get[T](key: AttributeKey[T]) = s.attributes get key
def put[T](key: AttributeKey[T], value: T) = s.copy(attributes = s.attributes.put(key, value))
def remove(key: AttributeKey[_]) = s.copy(attributes = s.attributes remove key)
def fail =
{
val remaining = s.remainingCommands.dropWhile(_ != FailureWall)
@ -80,6 +83,8 @@ object State
case None => noHandler
}
def addExitHook(act: => Unit): State =
s.copy(exitHooks = s.exitHooks + ExitHook(act))
def runExitHooks(): State = {
ExitHooks.runExitHooks(s.exitHooks.toSeq)
s.copy(exitHooks = Set.empty)

View File

@ -4,13 +4,15 @@
package sbt
/** Defines a function to call as sbt exits.*/
trait ExitHook extends NotNull
trait ExitHook
{
/** Provides a name for this hook to be used to provide feedback to the user. */
def name: String
/** Subclasses should implement this method, which is called when this hook is executed. */
def runBeforeExiting(): Unit
}
object ExitHook
{
def apply(f: => Unit): ExitHook = new ExitHook { def runBeforeExiting() = f }
}
object ExitHooks
{

View File

@ -1,9 +1,9 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009, 2010 Mark Harrah
* Copyright 2008, 2009, 2010, 2011 Mark Harrah
*/
package sbt
import java.io.{PrintStream, PrintWriter}
import java.io.{BufferedWriter, PrintStream, PrintWriter}
object ConsoleLogger
{
@ -17,8 +17,14 @@ object ConsoleLogger
def printWriterOut(out: PrintWriter): 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 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() }
}
val formatEnabled =