Cleanup code paths related to "last"

This commit is contained in:
Dale Wijnand 2017-06-20 14:01:40 +01:00
parent c85fbbf215
commit 73b45f6d30
No known key found for this signature in database
GPG Key ID: 4F256E3D151DF5EF
6 changed files with 278 additions and 184 deletions

View File

@ -271,12 +271,14 @@ object Defaults extends BuildCommon {
.toHex(Hash(appConfiguration.value.baseDirectory.toString))
.## % 1000)
))
def defaultTestTasks(key: Scoped): Seq[Setting[_]] =
inTask(key)(
Seq(
tags := Seq(Tags.Test -> 1),
logBuffered := true
))
// TODO: This should be on the new default settings for a project.
def projectCore: Seq[Setting[_]] = Seq(
name := thisProject.value.id,
@ -286,6 +288,7 @@ object Defaults extends BuildCommon {
s"Set current project to ${name.value} (in build ${thisProjectRef.value.build})"
}).value
)
def paths = Seq(
baseDirectory := thisProject.value.base,
target := baseDirectory.value / "target",

View File

@ -285,9 +285,11 @@ object EvaluateTask {
yield runTask(task, state, str, structure.index.triggers, config)(toNode)
}
}
def logIncResult(result: Result[_], state: State, streams: Streams) = result match {
case Inc(i) => logIncomplete(i, state, streams); case _ => ()
}
def logIncomplete(result: Incomplete, state: State, streams: Streams): Unit = {
val all = Incomplete linearize result
val keyed = for (Incomplete(Some(key: ScopedKey[_]), _, msg, _, ex) <- all)
@ -310,13 +312,16 @@ object EvaluateTask {
log.error("(" + display.show(key) + ") " + msgString)
}
}
private[this] def contextDisplay(state: State, highlight: Boolean) =
Project.showContextKey(state, if (highlight) Some(RED) else None)
def suppressedMessage(key: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
"Stack trace suppressed. Run 'last %s' for the full log.".format(display.show(key))
def getStreams(key: ScopedKey[_], streams: Streams): TaskStreams =
streams(ScopedKey(Project.fillTaskAxis(key).scope, Keys.streams.key))
def withStreams[T](structure: BuildStructure, state: State)(f: Streams => T): T = {
val str = std.Streams.closeable(structure.streams(state))
try { f(str) } finally { str.close() }

View File

@ -10,20 +10,20 @@ import sbt.internal.{
BuildUnit,
CommandExchange,
CommandStrings,
DefaultBackgroundJobService,
EvaluateConfigurations,
Inspect,
IvyConsole,
Load,
LoadedBuildUnit,
LogManager,
Output,
PluginsDebug,
ProjectNavigation,
Script,
SessionSettings,
SetResult,
SettingCompletions,
LogManager,
DefaultBackgroundJobService
SettingCompletions
}
import sbt.internal.util.{
AttributeKey,
@ -35,7 +35,7 @@ import sbt.internal.util.{
SimpleReader,
Types
}
import sbt.util.{ Level, Logger }
import sbt.util.{ Level, Logger, Show }
import sbt.internal.util.complete.{ DefaultParsers, Parser }
import sbt.internal.inc.ScalaInstance
@ -54,8 +54,7 @@ import java.io.{ File, IOException }
import java.net.URI
import java.util.Locale
import scala.util.control.NonFatal
import BasicCommandStrings.{ Shell, OldShell, TemplateCommand }
import BasicCommandStrings.{ Shell, TemplateCommand }
import CommandStrings.BootCommand
/** This class is the entry point for sbt. */
@ -108,7 +107,8 @@ object StandardMain {
}
/** The common interface to standard output, used for all built-in ConsoleLoggers. */
val console = ConsoleOut.systemOutOverwrite(ConsoleOut.overwriteContaining("Resolving "))
val console: ConsoleOut =
ConsoleOut.systemOutOverwrite(ConsoleOut.overwriteContaining("Resolving "))
def initialGlobalLogging: GlobalLogging =
GlobalLogging.initial(MainAppender.globalDefault(console),
@ -125,16 +125,18 @@ object StandardMain {
Exec(x, None)
}
val initAttrs = BuiltinCommands.initialAttributes
val s = State(configuration,
initialDefinitions,
Set.empty,
None,
commands,
State.newHistory,
initAttrs,
initialGlobalLogging,
None,
State.Continue)
val s = State(
configuration,
initialDefinitions,
Set.empty,
None,
commands,
State.newHistory,
initAttrs,
initialGlobalLogging,
None,
State.Continue
)
s.initializeClassLoaderCache
}
}
@ -435,10 +437,12 @@ object BuiltinCommands {
reapply(setResult.session, structure, s)
}
def setThis(s: State,
extracted: Extracted,
settings: Seq[Def.Setting[_]],
arg: String): SetResult =
def setThis(
s: State,
extracted: Extracted,
settings: Seq[Def.Setting[_]],
arg: String
): SetResult =
SettingCompletions.setThis(s, extracted, settings, arg)
def inspect: Command = Command(InspectCommand, inspectBrief, inspectDetailed)(Inspect.parser) {
@ -457,7 +461,8 @@ object BuiltinCommands {
for (logFile <- lastLogFile(s)) yield Output.lastGrep(logFile, pattern, printLast(s))
keepLastLog(s)
}
def extractLast(s: State) = {
def extractLast(s: State): (BuildStructure, Select[ProjectRef], Show[Def.ScopedKey[_]]) = {
val ext = Project.extract(s)
(ext.structure, Select(ext.currentRef), ext.showKey)
}
@ -469,21 +474,28 @@ object BuiltinCommands {
SettingCompletions.settingParser(structure.data, structure.index.keyMap, currentProject)
}
val spacedAggregatedParser = (s: State) =>
import Def.ScopedKey
type KeysParser = Parser[Seq[ScopedKey[T]] forSome { type T }]
val spacedAggregatedParser: State => KeysParser = (s: State) =>
Act.requireSession(s, token(Space) ~> Act.aggregatedKeyParser(s))
val aggregatedKeyValueParser: State => Parser[Option[AnyKeys]] = (s: State) =>
spacedAggregatedParser(s).map(x => Act.keyValues(s)(x)).?
val exportParser: State => Parser[() => State] = (s: State) =>
Act.requireSession(s, token(Space) ~> exportParser0(s))
private[sbt] def exportParser0(s: State): Parser[() => State] = {
val extracted = Project extract s
import extracted.{ showKey, structure }
val keysParser = token(flag("--last" <~ Space)) ~ Act.aggregatedKeyParser(extracted)
val show = Aggregation.ShowConfig(settingValues = true,
taskValues = false,
print = println(_),
success = false)
val show = Aggregation.ShowConfig(
settingValues = true,
taskValues = false,
print = println(_),
success = false
)
for {
lastOnly_keys <- keysParser
kvs = Act.keyValues(structure)(lastOnly_keys._2)
@ -502,17 +514,21 @@ object BuiltinCommands {
}
}
def lastGrepParser(s: State) =
def lastGrepParser(s: State): Parser[(String, Option[AnyKeys])] =
Act.requireSession(
s,
(token(Space) ~> token(NotSpace, "<pattern>")) ~ aggregatedKeyValueParser(s))
def last = Command(LastCommand, lastBrief, lastDetailed)(aggregatedKeyValueParser) {
(token(Space) ~> token(NotSpace, "<pattern>")) ~ aggregatedKeyValueParser(s)
)
def last: Command = Command(LastCommand, lastBrief, lastDetailed)(aggregatedKeyValueParser) {
case (s, Some(sks)) => lastImpl(s, sks, None)
case (s, None) =>
for (logFile <- lastLogFile(s)) yield Output.last(logFile, printLast(s))
keepLastLog(s)
}
def export = Command(ExportCommand, exportBrief, exportDetailed)(exportParser)((s, f) => f())
def export: Command =
Command(ExportCommand, exportBrief, exportDetailed)(exportParser)((_, f) => f())
private[this] def lastImpl(s: State, sks: AnyKeys, sid: Option[String]): State = {
val (str, _, display) = extractLast(s)
@ -521,7 +537,7 @@ object BuiltinCommands {
}
/** Determines the log file that last* commands should operate on. See also isLastOnly. */
def lastLogFile(s: State) = {
def lastLogFile(s: State): Option[File] = {
val backing = s.globalLogging.backing
if (isLastOnly(s)) backing.last else Some(backing.file)
}
@ -545,22 +561,26 @@ object BuiltinCommands {
def autoImports(extracted: Extracted): EvalImports =
new EvalImports(imports(extracted), "<auto-imports>")
def imports(extracted: Extracted): Seq[(String, Int)] = {
val curi = extracted.currentRef.build
extracted.structure.units(curi).imports.map(s => (s, -1))
}
def listBuild(uri: URI,
build: LoadedBuildUnit,
current: Boolean,
currentID: String,
log: Logger) = {
log.info("In " + uri)
def listBuild(
uri: URI,
build: LoadedBuildUnit,
current: Boolean,
currentID: String,
log: Logger
): Unit = {
log.info(s"In $uri")
def prefix(id: String) = if (currentID != id) " " else if (current) " * " else "(*)"
for (id <- build.defined.keys.toSeq.sorted) log.info("\t" + prefix(id) + id)
}
def act: Command = Command.customHelp(Act.actParser, actHelp)
def actHelp: State => Help =
s => CommandStrings.showHelp ++ CommandStrings.multiTaskHelp ++ keysHelp(s)
@ -659,6 +679,7 @@ object BuiltinCommands {
private[this] def loadProjectParser: State => Parser[String] =
_ => matched(Project.loadActionParser)
private[this] def loadProjectCommand(command: String, arg: String): String =
s"$command $arg".trim

View File

@ -4,56 +4,68 @@
package sbt
package internal
import java.text.DateFormat
import Def.ScopedKey
import Keys.{ showSuccess, showTiming, timingFormat }
import sbt.internal.util.complete.Parser
import sbt.internal.util.{ Dag, HList, Settings, Util }
import sbt.util.{ Logger, Show }
import Parser.{ seq, failure, success }
import Parser.{ failure, seq, success }
import std.Transform.DummyTaskMap
sealed trait Aggregation
object Aggregation {
final case class ShowConfig(settingValues: Boolean,
taskValues: Boolean,
print: String => Unit,
success: Boolean)
final case class Complete[T](start: Long,
stop: Long,
results: sbt.Result[Seq[KeyValue[T]]],
state: State)
final case class ShowConfig(
settingValues: Boolean,
taskValues: Boolean,
print: String => Unit,
success: Boolean
)
final case class Complete[T](
start: Long,
stop: Long,
results: sbt.Result[Seq[KeyValue[T]]],
state: State
)
final case class KeyValue[+T](key: ScopedKey[_], value: T)
def defaultShow(state: State, showTasks: Boolean): ShowConfig =
ShowConfig(settingValues = true,
taskValues = showTasks,
s => state.log.info(s),
success = true)
ShowConfig(
settingValues = true,
taskValues = showTasks,
s => state.log.info(s),
success = true
)
def printSettings(xs: Seq[KeyValue[_]], print: String => Unit)(
implicit display: Show[ScopedKey[_]]) =
implicit display: Show[ScopedKey[_]]
): Unit =
xs match {
case KeyValue(_, x: Seq[_]) :: Nil => print(x.mkString("* ", "\n* ", ""))
case KeyValue(_, x) :: Nil => print(x.toString)
case _ =>
xs foreach {
case KeyValue(key, value) => print(display.show(key) + "\n\t" + value.toString)
}
xs foreach (kv => print(display.show(kv.key) + "\n\t" + kv.value.toString))
}
type Values[T] = Seq[KeyValue[T]]
type AnyKeys = Values[_]
def seqParser[T](ps: Values[Parser[T]]): Parser[Seq[KeyValue[T]]] =
seq(ps.map { case KeyValue(k, p) => p.map(v => KeyValue(k, v)) })
def applyTasks[T](s: State,
structure: BuildStructure,
ps: Values[Parser[Task[T]]],
show: ShowConfig)(implicit display: Show[ScopedKey[_]]): Parser[() => State] =
Command.applyEffect(seqParser(ps)) { ts =>
runTasks(s, structure, ts, DummyTaskMap(Nil), show)
}
def applyTasks[T](
s: State,
structure: BuildStructure,
ps: Values[Parser[Task[T]]],
show: ShowConfig
)(implicit display: Show[ScopedKey[_]]): Parser[() => State] =
Command.applyEffect(seqParser(ps))(ts => runTasks(s, structure, ts, DummyTaskMap(Nil), show))
private def showRun[T](complete: Complete[T], show: ShowConfig)(
implicit display: Show[ScopedKey[_]]): Unit = {
implicit display: Show[ScopedKey[_]]
): Unit = {
import complete._
val log = state.log
val extracted = Project.extract(state)
@ -63,7 +75,12 @@ object Aggregation {
}
if (show.success) printSuccess(start, stop, extracted, success, log)
}
def timedRun[T](s: State, ts: Values[Task[T]], extra: DummyTaskMap): Complete[T] = {
def timedRun[T](
s: State,
ts: Values[Task[T]],
extra: DummyTaskMap
): Complete[T] = {
import EvaluateTask._
import std.TaskExtra._
@ -95,11 +112,13 @@ object Aggregation {
}
}
def printSuccess(start: Long,
stop: Long,
extracted: Extracted,
success: Boolean,
log: Logger): Unit = {
def printSuccess(
start: Long,
stop: Long,
extracted: Extracted,
success: Boolean,
log: Logger
): Unit = {
import extracted._
def get(key: SettingKey[Boolean]): Boolean =
key in currentRef get structure.data getOrElse true
@ -111,25 +130,30 @@ object Aggregation {
log.success("")
}
}
private def timingString(startTime: Long,
endTime: Long,
s: String,
data: Settings[Scope],
currentRef: ProjectRef,
log: Logger): String = {
private def timingString(
startTime: Long,
endTime: Long,
s: String,
data: Settings[Scope],
currentRef: ProjectRef,
log: Logger
): String = {
val format = timingFormat in currentRef get data getOrElse defaultFormat
timing(format, startTime, endTime, "", log)
}
def timing(format: java.text.DateFormat,
startTime: Long,
endTime: Long,
s: String,
log: Logger): String = {
def timing(
format: java.text.DateFormat,
startTime: Long,
endTime: Long,
s: String,
log: Logger
): String = {
val ss = if (s.isEmpty) "" else s + " "
val nowString = format.format(new java.util.Date(endTime))
"Total " + ss + "time: " + (endTime - startTime + 500) / 1000 + " s, completed " + nowString
}
def defaultFormat = {
def defaultFormat: DateFormat = {
import java.text.DateFormat
DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM)
}
@ -138,18 +162,23 @@ object Aggregation {
s: State,
structure: BuildStructure,
inputs: Values[InputTask[I]],
show: ShowConfig)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = {
val parsers = for (KeyValue(k, it) <- inputs) yield it.parser(s).map(v => KeyValue(k, v))
show: ShowConfig
)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = {
val parsers = for (KeyValue(k, it) <- inputs)
yield it.parser(s).map(v => KeyValue(k, v))
Command.applyEffect(seq(parsers)) { roots =>
runTasks(s, structure, roots, DummyTaskMap(Nil), show)
}
}
def evaluatingParser(s: State, structure: BuildStructure, show: ShowConfig)(
keys: Seq[KeyValue[_]])(implicit display: Show[ScopedKey[_]]): Parser[() => State] = {
keys: Seq[KeyValue[_]]
)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = {
// to make the call sites clearer
def separate[L](in: Seq[KeyValue[_]])(
f: KeyValue[_] => Either[KeyValue[L], KeyValue[_]]): (Seq[KeyValue[L]], Seq[KeyValue[_]]) =
f: KeyValue[_] => Either[KeyValue[L], KeyValue[_]]
): (Seq[KeyValue[L]], Seq[KeyValue[_]]) =
Util.separate(in)(f)
val kvs = keys.toList
@ -198,18 +227,22 @@ object Aggregation {
private[this] def maps[T, S](vs: Values[T])(f: T => S): Values[S] =
vs map { case KeyValue(k, v) => KeyValue(k, f(v)) }
def projectAggregates[Proj](proj: Option[Reference],
extra: BuildUtil[Proj],
reverse: Boolean): Seq[ProjectRef] = {
def projectAggregates[Proj](
proj: Option[Reference],
extra: BuildUtil[Proj],
reverse: Boolean
): Seq[ProjectRef] = {
val resRef = proj.map(p => extra.projectRefFor(extra.resolveRef(p)))
resRef.toList.flatMap(ref =>
if (reverse) extra.aggregates.reverse(ref) else extra.aggregates.forward(ref))
}
def aggregate[T, Proj](key: ScopedKey[T],
rawMask: ScopeMask,
extra: BuildUtil[Proj],
reverse: Boolean = false): Seq[ScopedKey[T]] = {
def aggregate[T, Proj](
key: ScopedKey[T],
rawMask: ScopeMask,
extra: BuildUtil[Proj],
reverse: Boolean = false
): Seq[ScopedKey[T]] = {
val mask = rawMask.copy(project = true)
Dag.topologicalSort(key) { k =>
if (reverse)
@ -220,9 +253,11 @@ object Aggregation {
Nil
}
}
def reverseAggregatedKeys[T](key: ScopedKey[T],
extra: BuildUtil[_],
mask: ScopeMask): Seq[ScopedKey[T]] =
def reverseAggregatedKeys[T](
key: ScopedKey[T],
extra: BuildUtil[_],
mask: ScopeMask
): Seq[ScopedKey[T]] =
projectAggregates(key.scope.project.toOption, extra, reverse = true) flatMap { ref =>
val toResolve = key.scope.copy(project = Select(ref))
val resolved = Resolve(extra, Zero, key.key, mask)(toResolve)
@ -230,9 +265,11 @@ object Aggregation {
if (aggregationEnabled(skey, extra.data)) skey :: Nil else Nil
}
def aggregatedKeys[T](key: ScopedKey[T],
extra: BuildUtil[_],
mask: ScopeMask): Seq[ScopedKey[T]] =
def aggregatedKeys[T](
key: ScopedKey[T],
extra: BuildUtil[_],
mask: ScopeMask
): Seq[ScopedKey[T]] =
projectAggregates(key.scope.project.toOption, extra, reverse = false) map { ref =>
val toResolve = key.scope.copy(project = Select(ref))
val resolved = Resolve(extra, Zero, key.key, mask)(toResolve)

View File

@ -22,10 +22,13 @@ import sbt.internal.util.ManagedLogger
import org.apache.logging.log4j.core.Appender
sealed abstract class LogManager {
def apply(data: Settings[Scope],
state: State,
task: ScopedKey[_],
writer: PrintWriter): ManagedLogger
def apply(
data: Settings[Scope],
state: State,
task: ScopedKey[_],
writer: PrintWriter
): ManagedLogger
def backgroundLog(data: Settings[Scope], state: State, task: ScopedKey[_]): ManagedLogger
}
@ -34,37 +37,41 @@ object LogManager {
private val generateId: AtomicInteger = new AtomicInteger
// This is called by mkStreams
def construct(data: Settings[Scope],
state: State): (ScopedKey[_], PrintWriter) => ManagedLogger =
def construct(
data: Settings[Scope],
state: State
): (ScopedKey[_], PrintWriter) => ManagedLogger =
(task: ScopedKey[_], to: PrintWriter) => {
val manager: LogManager = (logManager in task.scope).get(data) getOrElse {
defaultManager(state.globalLogging.console)
}
val manager: LogManager =
(logManager in task.scope).get(data) getOrElse defaultManager(state.globalLogging.console)
manager(data, state, task, to)
}
def constructBackgroundLog(data: Settings[Scope],
state: State): (ScopedKey[_]) => ManagedLogger =
def constructBackgroundLog(
data: Settings[Scope],
state: State
): (ScopedKey[_]) => ManagedLogger =
(task: ScopedKey[_]) => {
val manager: LogManager = (logManager in task.scope).get(data) getOrElse {
defaultManager(state.globalLogging.console)
}
val manager: LogManager =
(logManager in task.scope).get(data) getOrElse defaultManager(state.globalLogging.console)
manager.backgroundLog(data, state, task)
}
def defaultManager(console: ConsoleOut): LogManager =
withLoggers((sk, s) => defaultScreen(console))
withLoggers((_, _) => defaultScreen(console))
// This is called by Defaults.
def defaults(extra: ScopedKey[_] => Seq[Appender], console: ConsoleOut): LogManager =
withLoggers((task, state) => defaultScreen(console, suppressedMessage(task, state)),
extra = extra)
withLoggers(
(task, state) => defaultScreen(console, suppressedMessage(task, state)),
extra = extra
)
def withScreenLogger(mk: (ScopedKey[_], State) => Appender): LogManager =
withLoggers(screen = mk)
def withLoggers(
screen: (ScopedKey[_], State) => Appender = (sk, s) => defaultScreen(s.globalLogging.console),
screen: (ScopedKey[_], State) => Appender = (_, s) => defaultScreen(s.globalLogging.console),
backed: PrintWriter => Appender = defaultBacked,
relay: Unit => Appender = defaultRelay,
extra: ScopedKey[_] => Seq[Appender] = _ => Nil
@ -76,40 +83,41 @@ object LogManager {
relay: Unit => Appender,
extra: ScopedKey[_] => Seq[Appender]
) extends LogManager {
def apply(data: Settings[Scope],
state: State,
task: ScopedKey[_],
to: PrintWriter): ManagedLogger =
defaultLogger(data,
state,
task,
screen(task, state),
backed(to),
relay(()),
extra(task).toList)
def apply(
data: Settings[Scope],
state: State,
task: ScopedKey[_],
to: PrintWriter
): ManagedLogger =
defaultLogger(
data,
state,
task,
screen(task, state),
backed(to),
relay(()),
extra(task).toList
)
def backgroundLog(data: Settings[Scope], state: State, task: ScopedKey[_]): ManagedLogger =
LogManager.backgroundLog(data,
state,
task,
screen(task, state),
relay(()),
extra(task).toList)
def backgroundLog(data: Settings[Scope], state: State, task: ScopedKey[_]): ManagedLogger = {
val console = screen(task, state)
LogManager.backgroundLog(data, state, task, console, relay(()), extra(task).toList)
}
}
// This is the main function that is used to generate the logger for tasks.
def defaultLogger(data: Settings[Scope],
state: State,
task: ScopedKey[_],
console: Appender,
backed: Appender,
relay: Appender,
extra: List[Appender]): ManagedLogger = {
def defaultLogger(
data: Settings[Scope],
state: State,
task: ScopedKey[_],
console: Appender,
backed: Appender,
relay: Appender,
extra: List[Appender]
): ManagedLogger = {
val execOpt = state.currentCommand
val loggerName: String = s"${task.key.label}-${generateId.incrementAndGet}"
val channelName: Option[String] = execOpt flatMap { e =>
e.source map { _.channelName }
}
val channelName: Option[String] = execOpt flatMap (_.source map (_.channelName))
val execId: Option[String] = execOpt flatMap { _.execId }
val log = LogExchange.logger(loggerName, channelName, execId)
val scope = task.scope
@ -122,15 +130,18 @@ object LogManager {
val backingTrace = getOr(persistTraceLevel.key, Int.MaxValue)
val extraBacked = state.globalLogging.backed :: relay :: Nil
val consoleOpt = consoleLocally(state, console)
multiLogger(log,
MainAppender.MainAppenderConfig(consoleOpt,
backed,
extraBacked ::: extra,
screenLevel,
backingLevel,
screenTrace,
backingTrace))
val config = MainAppender.MainAppenderConfig(
consoleOpt,
backed,
extraBacked ::: extra,
screenLevel,
backingLevel,
screenTrace,
backingTrace
)
multiLogger(log, config)
}
// Return None if the exec is not from console origin.
def consoleLocally(state: State, console: Appender): Option[Appender] =
state.currentCommand match {
@ -138,37 +149,44 @@ object LogManager {
x.source match {
// TODO: Fix this stringliness
case Some(x: CommandSource) if x.channelName == "console0" => Option(console)
case Some(x: CommandSource) => None
case Some(_: CommandSource) => None
case _ => Option(console)
}
case _ => Option(console)
}
def defaultTraceLevel(state: State): Int =
if (state.interactive) -1 else Int.MaxValue
def suppressedMessage(key: ScopedKey[_],
state: State): SuppressedTraceContext => Option[String] = {
def suppressedMessage(
key: ScopedKey[_],
state: State
): SuppressedTraceContext => Option[String] = {
lazy val display = Project.showContextKey(state)
def commandBase = "last " + display.show(unwrapStreamsKey(key))
def command(useColor: Boolean) =
if (useColor) BLUE + commandBase + RESET else "'" + commandBase + "'"
if (useColor) BLUE + commandBase + RESET else s"'$commandBase'"
context =>
Some("Stack trace suppressed: run %s for the full output.".format(command(context.useColor)))
}
def unwrapStreamsKey(key: ScopedKey[_]): ScopedKey[_] = key.scope.task match {
case Select(task) => ScopedKey(key.scope.copy(task = Zero), task)
case _ => key // should never get here
}
def backgroundLog(data: Settings[Scope],
state: State,
task: ScopedKey[_],
console: Appender, /* TODO: backed: Appender,*/ relay: Appender,
extra: List[Appender]): ManagedLogger = {
def backgroundLog(
data: Settings[Scope],
state: State,
task: ScopedKey[_],
console: Appender,
/* TODO: backed: Appender,*/
relay: Appender,
extra: List[Appender]
): ManagedLogger = {
val execOpt = state.currentCommand
val loggerName: String = s"bg-${task.key.label}-${generateId.incrementAndGet}"
val channelName: Option[String] = execOpt flatMap { e =>
e.source map { _.channelName }
}
val channelName: Option[String] = execOpt flatMap (_.source map (_.channelName))
// val execId: Option[String] = execOpt flatMap { _.execId }
val log = LogExchange.logger(loggerName, channelName, None)
LogExchange.unbindLoggerAppenders(loggerName)
@ -199,12 +217,12 @@ object LogManager {
// s
// }
def setGlobalLogLevel(s: State, level: Level.Value): State = {
def setGlobalLogLevel(s: State, level: Level.Value): State =
s.put(BasicKeys.explicitGlobalLogLevels, true).put(Keys.logLevel.key, level)
}
// This is the default implementation for the relay appender
val defaultRelay: Unit => Appender = _ => defaultRelayImpl
private[this] lazy val defaultRelayImpl: RelayAppender = {
val appender = new RelayAppender("Relay0")
appender.start()
@ -217,7 +235,7 @@ object LogManager {
// construct a Logger that delegates to the global logger, but only holds a weak reference
// this is an approximation to the ideal that would invalidate the delegate after loading completes
private[this] def globalWrapper(s: State): Logger = {
private[this] def globalWrapper(s: State): Logger =
new Logger {
private[this] val ref = new java.lang.ref.WeakReference(s.globalLogging.full)
private[this] def slog: Logger =
@ -228,5 +246,4 @@ object LogManager {
override def success(message: => String) = slog.success(message)
override def log(level: Level.Value, message: => String) = slog.log(level, message)
}
}
}

View File

@ -20,33 +20,42 @@ import sbt.io.IO
object Output {
final val DefaultTail = "> "
def last(keys: Values[_],
streams: Streams,
printLines: Seq[String] => Unit,
sid: Option[String])(implicit display: Show[ScopedKey[_]]): Unit =
def last(
keys: Values[_],
streams: Streams,
printLines: Seq[String] => Unit,
sid: Option[String]
)(implicit display: Show[ScopedKey[_]]): Unit =
printLines(flatLines(lastLines(keys, streams, sid))(idFun))
def last(file: File, printLines: Seq[String] => Unit, tailDelim: String = DefaultTail): Unit =
printLines(tailLines(file, tailDelim))
def lastGrep(keys: Values[_],
streams: Streams,
patternString: String,
printLines: Seq[String] => Unit)(implicit display: Show[ScopedKey[_]]): Unit = {
def lastGrep(
keys: Values[_],
streams: Streams,
patternString: String,
printLines: Seq[String] => Unit
)(implicit display: Show[ScopedKey[_]]): Unit = {
val pattern = Pattern compile patternString
val lines = flatLines(lastLines(keys, streams))(_ flatMap showMatches(pattern))
printLines(lines)
}
def lastGrep(file: File,
patternString: String,
printLines: Seq[String] => Unit,
tailDelim: String = DefaultTail): Unit =
def lastGrep(
file: File,
patternString: String,
printLines: Seq[String] => Unit,
tailDelim: String = DefaultTail
): Unit =
printLines(grep(tailLines(file, tailDelim), patternString))
def grep(lines: Seq[String], patternString: String): Seq[String] =
lines flatMap showMatches(Pattern compile patternString)
def flatLines(outputs: Values[Seq[String]])(f: Seq[String] => Seq[String])(
implicit display: Show[ScopedKey[_]]): Seq[String] = {
implicit display: Show[ScopedKey[_]]
): Seq[String] = {
val single = outputs.size == 1
outputs flatMap {
case KeyValue(key, lines) =>
@ -55,9 +64,11 @@ object Output {
}
}
def lastLines(keys: Values[_],
streams: Streams,
sid: Option[String] = None): Values[Seq[String]] = {
def lastLines(
keys: Values[_],
streams: Streams,
sid: Option[String] = None
): Values[Seq[String]] = {
val outputs = keys map { (kv: KeyValue[_]) =>
KeyValue(kv.key, lastLines(kv.key, streams, sid))
}