mirror of https://github.com/sbt/sbt.git
Cleanup code paths related to "last"
This commit is contained in:
parent
c85fbbf215
commit
73b45f6d30
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue