diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 243f10602..186f117b3 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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 diff --git a/main/src/main/scala/sbt/nio/CheckBuildSources.scala b/main/src/main/scala/sbt/nio/CheckBuildSources.scala index 92930f085..7b3bde263 100644 --- a/main/src/main/scala/sbt/nio/CheckBuildSources.scala +++ b/main/src/main/scala/sbt/nio/CheckBuildSources.scala @@ -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 } diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/build.sbt b/sbt-app/src/sbt-test/nio/ignore-source-changes/build.sbt new file mode 100644 index 000000000..c18aacbf4 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/build.sbt @@ -0,0 +1,5 @@ +import scala.concurrent.duration.DurationInt + +ThisBuild / checkBuildSources / pollInterval := 0.seconds + +lazy val sub = project.in(file("sub")) diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/build.1.sbt b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/build.1.sbt new file mode 100644 index 000000000..efaf0ec88 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/build.1.sbt @@ -0,0 +1,7 @@ +import scala.concurrent.duration.DurationInt + +ThisBuild / checkBuildSources / pollInterval := 0.seconds + +lazy val sub = project.in(file("sub")) + +// change 1 diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/build.2.sbt b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/build.2.sbt new file mode 100644 index 000000000..f15752646 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/build.2.sbt @@ -0,0 +1,7 @@ +import scala.concurrent.duration.DurationInt + +ThisBuild / checkBuildSources / pollInterval := 0.seconds + +lazy val sub = project.in(file("sub")) + +// change 2 diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/sub.1.sbt b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/sub.1.sbt new file mode 100644 index 000000000..ac0c8f797 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/sub.1.sbt @@ -0,0 +1 @@ +// subproject, change 1 diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/sub.2.sbt b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/sub.2.sbt new file mode 100644 index 000000000..939d56556 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/changes/sub.2.sbt @@ -0,0 +1 @@ +// subproject, change 2 diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/project/Build.scala b/sbt-app/src/sbt-test/nio/ignore-source-changes/project/Build.scala new file mode 100644 index 000000000..f9405dd53 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/project/Build.scala @@ -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" + ) + } + ) +} diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/sub/build.sbt b/sbt-app/src/sbt-test/nio/ignore-source-changes/sub/build.sbt new file mode 100644 index 000000000..b37ae2bff --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/sub/build.sbt @@ -0,0 +1 @@ +// subproject diff --git a/sbt-app/src/sbt-test/nio/ignore-source-changes/test b/sbt-app/src/sbt-test/nio/ignore-source-changes/test new file mode 100644 index 000000000..c65583311 --- /dev/null +++ b/sbt-app/src/sbt-test/nio/ignore-source-changes/test @@ -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