diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 668d59213..433d9df71 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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", diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index 635072254..968ef1e59 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -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() } diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 0af2d369e..07b04a131 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -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, "")) ~ aggregatedKeyValueParser(s)) - def last = Command(LastCommand, lastBrief, lastDetailed)(aggregatedKeyValueParser) { + (token(Space) ~> token(NotSpace, "")) ~ 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), "") + 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 diff --git a/main/src/main/scala/sbt/internal/Aggregation.scala b/main/src/main/scala/sbt/internal/Aggregation.scala index bd70f8dd8..b7a818857 100644 --- a/main/src/main/scala/sbt/internal/Aggregation.scala +++ b/main/src/main/scala/sbt/internal/Aggregation.scala @@ -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) diff --git a/main/src/main/scala/sbt/internal/LogManager.scala b/main/src/main/scala/sbt/internal/LogManager.scala index ec558847c..16b22b306 100644 --- a/main/src/main/scala/sbt/internal/LogManager.scala +++ b/main/src/main/scala/sbt/internal/LogManager.scala @@ -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) } - } } diff --git a/main/src/main/scala/sbt/internal/Output.scala b/main/src/main/scala/sbt/internal/Output.scala index 42074e34b..207bc5598 100644 --- a/main/src/main/scala/sbt/internal/Output.scala +++ b/main/src/main/scala/sbt/internal/Output.scala @@ -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)) }