mirror of https://github.com/sbt/sbt.git
Use terminal printstream in CheckBuildSources
The build source check is evaluated at times when we can't be completely sure that global logger is pointing at the terminal that initiated the reload (which may be a passive watch client). To work around this, we can inspect the exec to determine which terminal initiated the check and write any output directly to that terminal.
This commit is contained in:
parent
25e83d8fec
commit
9dc3c6b17f
|
|
@ -184,7 +184,8 @@ object MainLoop {
|
|||
/** This is the main function State transfer function of the sbt command processing. */
|
||||
def processCommand(exec: Exec, state: State): State = {
|
||||
val channelName = exec.source map (_.channelName)
|
||||
StandardMain.exchange notifyStatus
|
||||
val exchange = StandardMain.exchange
|
||||
exchange notifyStatus
|
||||
ExecStatusEvent("Processing", channelName, exec.execId, Vector())
|
||||
try {
|
||||
def process(): State = {
|
||||
|
|
@ -197,9 +198,9 @@ object MainLoop {
|
|||
state.put(sbt.Keys.currentTaskProgress, new Keys.TaskProgress(progress))
|
||||
} else state
|
||||
}
|
||||
StandardMain.exchange.setState(progressState)
|
||||
StandardMain.exchange.setExec(Some(exec))
|
||||
StandardMain.exchange.unprompt(ConsoleUnpromptEvent(exec.source), force = false)
|
||||
exchange.setState(progressState)
|
||||
exchange.setExec(Some(exec))
|
||||
exchange.unprompt(ConsoleUnpromptEvent(exec.source), force = false)
|
||||
val newState = Command.process(exec.commandLine, progressState)
|
||||
if (exec.execId.fold(true)(!_.startsWith(networkExecPrefix)) &&
|
||||
!exec.commandLine.startsWith(networkExecPrefix)) {
|
||||
|
|
@ -210,26 +211,25 @@ object MainLoop {
|
|||
newState.remainingCommands.toVector map (_.commandLine),
|
||||
exitCode(newState, state),
|
||||
)
|
||||
StandardMain.exchange.respondStatus(doneEvent)
|
||||
exchange.respondStatus(doneEvent)
|
||||
}
|
||||
StandardMain.exchange.setExec(None)
|
||||
exchange.setExec(None)
|
||||
newState.get(sbt.Keys.currentTaskProgress).foreach(_.progress.stop())
|
||||
newState.remove(sbt.Keys.currentTaskProgress)
|
||||
}
|
||||
state.get(CheckBuildSourcesKey) match {
|
||||
case Some(cbs) =>
|
||||
if (!cbs.needsReload(state, state.globalLogging.full, exec.commandLine)) process()
|
||||
if (!cbs.needsReload(state, exec)) process()
|
||||
else {
|
||||
if (exec.commandLine.startsWith(SetTerminal))
|
||||
exec +: Exec("reload", None, None) +: state.remove(CheckBuildSourcesKey)
|
||||
else
|
||||
Exec("reload", None, None) +: exec +: state.remove(CheckBuildSourcesKey)
|
||||
val isSetTerminal = exec.commandLine.startsWith(SetTerminal)
|
||||
if (isSetTerminal) exec +: Exec("reload", None) +: state.remove(CheckBuildSourcesKey)
|
||||
else Exec("reload", None) +: exec +: state.remove(CheckBuildSourcesKey)
|
||||
}
|
||||
case _ => process()
|
||||
}
|
||||
} catch {
|
||||
case err: JsonRpcResponseError =>
|
||||
StandardMain.exchange.respondError(err, exec.execId, channelName.map(CommandSource(_)))
|
||||
exchange.respondError(err, exec.execId, channelName.map(CommandSource(_)))
|
||||
throw err
|
||||
case err: Throwable =>
|
||||
val errorEvent = ExecStatusEvent(
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
|
|||
val (nextFileEvent, cleanupFileMonitor): (
|
||||
Int => Option[(Watch.Event, Watch.Action)],
|
||||
() => Unit
|
||||
) = getFileEvents(configs, logger, state, commands, fileStampCache)
|
||||
) = getFileEvents(configs, logger, state, commands, fileStampCache, channel.name)
|
||||
val executor = new WatchExecutor(channel.name)
|
||||
val nextEvent: Int => Watch.Action =
|
||||
combineInputAndFileEvents(nextInputEvent, nextFileEvent, message, logger, logger, executor)
|
||||
|
|
@ -420,7 +420,8 @@ private[sbt] object Continuous extends DeprecatedContinuous {
|
|||
logger: Logger,
|
||||
state: State,
|
||||
commands: Seq[String],
|
||||
fileStampCache: FileStamp.Cache
|
||||
fileStampCache: FileStamp.Cache,
|
||||
channel: String,
|
||||
)(implicit extracted: Extracted): (Int => Option[(Watch.Event, Watch.Action)], () => Unit) = {
|
||||
val trackMetaBuild = configs.forall(_.watchSettings.trackMetaBuild)
|
||||
val buildGlobs =
|
||||
|
|
@ -554,7 +555,9 @@ private[sbt] object Continuous extends DeprecatedContinuous {
|
|||
getWatchEvent(forceTrigger = false).flatMap { e =>
|
||||
state.get(CheckBuildSources.CheckBuildSourcesKey) match {
|
||||
case Some(cbs) =>
|
||||
if (cbs.needsReload(state, logger, "")) Some(e -> Watch.Reload) else None
|
||||
if (cbs.needsReload(state, Exec("", Some(CommandSource(channel)))))
|
||||
Some(e -> Watch.Reload)
|
||||
else None
|
||||
case None =>
|
||||
Some(e -> Watch.Reload)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ package internal.nio
|
|||
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||
import sbt.BasicCommandStrings.{ RebootCommand, Shutdown, TerminateAction }
|
||||
import sbt.BasicCommandStrings.{ RebootCommand, SetTerminal, Shutdown, TerminateAction }
|
||||
import sbt.Keys.{ baseDirectory, pollInterval, state }
|
||||
import sbt.Scope.Global
|
||||
import sbt.SlashSyntax0._
|
||||
import sbt.internal.CommandStrings.LoadProject
|
||||
import sbt.internal.SysProp
|
||||
import sbt.internal.util.AttributeKey
|
||||
import sbt.internal.util.{ AttributeKey, Terminal }
|
||||
import sbt.io.syntax._
|
||||
import sbt.nio.FileChanges
|
||||
import sbt.nio.FileStamp
|
||||
|
|
@ -28,6 +28,7 @@ import sbt.util.Logger
|
|||
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.duration.{ Deadline => SDeadline, _ }
|
||||
import scala.io.AnsiColor
|
||||
|
||||
/**
|
||||
* This class is used to determine whether sbt needs to automatically reload
|
||||
|
|
@ -103,7 +104,28 @@ private[sbt] class CheckBuildSources extends AutoCloseable {
|
|||
!resetState
|
||||
}
|
||||
@inline private def forceCheck = fileTreeRepository.isEmpty
|
||||
private[sbt] def needsReload(state: State, logger: Logger, cmd: String) = {
|
||||
private[sbt] def needsReload(
|
||||
state: State,
|
||||
exec: Exec
|
||||
): Boolean = {
|
||||
val isSetTerminal = exec.commandLine.startsWith(SetTerminal)
|
||||
val name =
|
||||
if (isSetTerminal)
|
||||
exec.commandLine.split(s"$SetTerminal ").lastOption.filterNot(_.isEmpty)
|
||||
else exec.source.map(_.channelName)
|
||||
val loggerOrTerminal =
|
||||
name.flatMap(StandardMain.exchange.channelForName(_).map(_.terminal)) match {
|
||||
case Some(t) => Right(t)
|
||||
case _ => Left(state.globalLogging.full)
|
||||
}
|
||||
|
||||
needsReload(state, loggerOrTerminal, exec.commandLine)
|
||||
}
|
||||
private def needsReload(
|
||||
state: State,
|
||||
loggerOrTerminal: Either[Logger, Terminal],
|
||||
cmd: String
|
||||
): Boolean = {
|
||||
(needCheck(state, cmd) && (forceCheck || needUpdate.compareAndSet(true, false))) && {
|
||||
val extracted = Project.extract(state)
|
||||
val onChanges = extracted.get(Global / onChangedBuildSource)
|
||||
|
|
@ -122,14 +144,24 @@ private[sbt] class CheckBuildSources extends AutoCloseable {
|
|||
else "")
|
||||
val prefix = rawPrefix.linesIterator.filterNot(_.trim.isEmpty).mkString("\n")
|
||||
if (onChanges == ReloadOnSourceChanges) {
|
||||
logger.info(s"$prefix\nReloading sbt...")
|
||||
val msg = s"$prefix\nReloading sbt..."
|
||||
loggerOrTerminal match {
|
||||
case Right(t) => msg.linesIterator.foreach(l => t.printStream.println(s"[info] $l"))
|
||||
case Left(l) => l.info(msg)
|
||||
}
|
||||
true
|
||||
} else {
|
||||
val tail = "Apply these changes by running `reload`.\nAutomatically reload the " +
|
||||
"build when source changes are detected by setting " +
|
||||
"`Global / onChangedBuildSource := ReloadOnSourceChanges`.\nDisable this " +
|
||||
"warning by setting `Global / onChangedBuildSource := IgnoreSourceChanges`."
|
||||
logger.warn(s"$prefix\n$tail")
|
||||
val msg = s"$prefix\n$tail"
|
||||
loggerOrTerminal match {
|
||||
case Right(t) =>
|
||||
val prefix = s"[${Def.withColor("warn", Some(AnsiColor.YELLOW), t.isColorEnabled)}]"
|
||||
msg.linesIterator.foreach(l => t.printStream.println(s"$prefix $l"))
|
||||
case Left(l) => l.warn(msg)
|
||||
}
|
||||
false
|
||||
}
|
||||
case _ => false
|
||||
|
|
@ -160,7 +192,7 @@ private[sbt] object CheckBuildSources {
|
|||
private[sbt] def needReloadImpl: Def.Initialize[Task[StateTransform]] = Def.task {
|
||||
val st = state.value
|
||||
st.get(CheckBuildSourcesKey) match {
|
||||
case Some(cbs) if (cbs.needsReload(st, st.globalLogging.full, "")) =>
|
||||
case Some(cbs) if (cbs.needsReload(st, Exec("", None))) =>
|
||||
StateTransform("reload" :: (_: State))
|
||||
case _ => StateTransform(identity)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue