[2.x] fix: IgnoreSourceChanges now works (#8820) (#8853)

Closes #6773

Co-authored-by: Daniil Sivak <seroperson@gmail.com>
This commit is contained in:
eugene yokota 2026-03-01 05:29:06 -05:00 committed by GitHub
parent 1d6ec91dbc
commit 660e8f92df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 131 additions and 23 deletions

View File

@ -556,7 +556,12 @@ object Defaults extends BuildCommon {
// Adds subproject build.sbt files to the global list of build files to monitor
Scope.Global / checkBuildSources / pollInterval :==
new FiniteDuration(Int.MinValue, TimeUnit.MILLISECONDS),
Scope.Global / checkBuildSources / fileInputs += baseDirectory.value.toGlob / "*.sbt",
Scope.Global / checkBuildSources / fileInputs ++= {
if ((Scope.Global / onChangedBuildSource).value != IgnoreSourceChanges)
Seq(baseDirectory.value.toGlob / "*.sbt")
else
Nil
},
)
lazy val configPaths = sourceConfigPaths ++ resourceConfigPaths ++ outputConfigPaths

View File

@ -50,7 +50,7 @@ private[sbt] class CheckBuildSources extends AutoCloseable {
private val sources = new AtomicReference[Seq[Glob]](Nil)
private val needUpdate = new AtomicBoolean(true)
private val lastPolled = new AtomicReference[SDeadline](SDeadline.now)
private val previousStamps = new AtomicReference[Seq[(Path, FileStamp)]]
private val previousStamps = new AtomicReference[Seq[(Path, FileStamp)]](Nil)
private[sbt] def fileTreeRepository: Option[FileTreeRepository[FileAttributes]] =
Option(repository.get)
private def getStamps(force: Boolean) = {
@ -66,7 +66,7 @@ private[sbt] class CheckBuildSources extends AutoCloseable {
private def reset(state: State): Unit = {
val extracted = Project.extract(state)
val interval = extracted.get(checkBuildSources / pollInterval)
val newSources = extracted.get(Global / checkBuildSources / fileInputs)
val newSources = extracted.get(Global / checkBuildSources / fileInputs).distinct
if (interval >= 0.seconds || "polling" == SysProp.watchMode) {
Option(repository.getAndSet(null)).foreach(_.close())
pollingPeriod.set(interval)
@ -141,26 +141,31 @@ private[sbt] class CheckBuildSources extends AutoCloseable {
s"modified files: ${modified.mkString("\n ", "\n ", "\n")}"
else "")
val prefix = rawPrefix.linesIterator.filterNot(_.trim.isEmpty).mkString("\n")
if (onChanges == ReloadOnSourceChanges) {
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`."
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
onChanges match {
case ReloadOnSourceChanges =>
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
case WarnOnSourceChanges =>
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`."
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 IgnoreSourceChanges =>
false
}
case _ => false
}

View File

@ -0,0 +1,5 @@
import scala.concurrent.duration.DurationInt
ThisBuild / checkBuildSources / pollInterval := 0.seconds
lazy val sub = project.in(file("sub"))

View File

@ -0,0 +1,7 @@
import scala.concurrent.duration.DurationInt
ThisBuild / checkBuildSources / pollInterval := 0.seconds
lazy val sub = project.in(file("sub"))
// change 1

View File

@ -0,0 +1,7 @@
import scala.concurrent.duration.DurationInt
ThisBuild / checkBuildSources / pollInterval := 0.seconds
lazy val sub = project.in(file("sub"))
// change 2

View File

@ -0,0 +1 @@
// subproject, change 1

View File

@ -0,0 +1 @@
// subproject, change 2

View File

@ -0,0 +1,52 @@
package sbt
import sbt.Keys._
import sbt.nio.Keys._
import sbt.internal.util._
import sbt.util.Level
object Build extends AutoPlugin {
val autoImport = Build
override def trigger = allRequirements
val awaitsWarn =
settingKey[Boolean]("Whether we're checking for warn or not")
val checkBuildSourcesWarn =
taskKey[Unit]("Checks whether there was a warning or not")
class CapturingMiniLogger extends MiniLogger {
var warnCaptured = false
override def log[T](level: Level.Value, message: ObjectEvent[T]): Unit = ()
override def log(level: Level.Value, message: => String): Unit =
if (level == Level.Warn && message.contains("build source files have changed"))
warnCaptured = true
}
override def buildSettings: Seq[Setting[?]] = Seq(
awaitsWarn := false,
checkBuildSourcesWarn := Def.uncached {
val st = state.value
val capturing = new CapturingMiniLogger
val originalFull = st.globalLogging.full
val capturingLogger = new ManagedLogger(
originalFull.name,
originalFull.channelName,
originalFull.execId,
capturing
)
val newLogging = st.globalLogging.copy(full = capturingLogger)
val newState = st.copy(globalLogging = newLogging)
val extractedSt = Project.extract(newState)
extractedSt.runTask(checkBuildSources, newState)
val warnCaptured = capturing.warnCaptured
val awaitsWarnValue = extractedSt.get(awaitsWarn)
if (warnCaptured != awaitsWarnValue)
throw new Exception(
s"Warn appeared: ${warnCaptured}; Expected: ${awaitsWarnValue}; See issue #6773"
)
}
)
}

View File

@ -0,0 +1 @@
// subproject

View File

@ -0,0 +1,24 @@
> set awaitsWarn := false
> checkBuildSourcesWarn
> set awaitsWarn := true
> set Global / onChangedBuildSource := WarnOnSourceChanges
$ copy-file changes/build.1.sbt build.sbt
> checkBuildSourcesWarn
> set awaitsWarn := false
> set Global / onChangedBuildSource := IgnoreSourceChanges
$ copy-file changes/build.2.sbt build.sbt
> checkBuildSourcesWarn
# Checking that subproject `.sbt` files are also monitored
> set awaitsWarn := true
> set Global / onChangedBuildSource := WarnOnSourceChanges
$ copy-file changes/sub.1.sbt sub/build.sbt
> checkBuildSourcesWarn
> set awaitsWarn := false
> set Global / onChangedBuildSource := IgnoreSourceChanges
$ copy-file changes/sub.2.sbt sub/build.sbt
> checkBuildSourcesWarn