From d698d6dcdd41b6412baadc84b121f5d636dca050 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Mon, 7 Oct 2019 19:40:17 -0700 Subject: [PATCH] Don't overwrite nio build settings with injected settings The current injection of the new nio keys will overwrite any definitions of those keys in a build source. This is undesirable. The fix is to create a mapping of scoped keys to settings and for each inject setting key, if there is a previous key, put that definition after the injected definition so that it can override it. --- main/src/main/scala/sbt/nio/Settings.scala | 27 ++++++++++++++----- sbt/src/sbt-test/nio/code-formatter/build.sbt | 3 ++- sbt/src/sbt-test/nio/overrides/bar.txt | 0 sbt/src/sbt-test/nio/overrides/baz.txt | 0 sbt/src/sbt-test/nio/overrides/build.sbt | 24 +++++++++++++++++ sbt/src/sbt-test/nio/overrides/foo.txt | 1 + sbt/src/sbt-test/nio/overrides/test | 3 +++ 7 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 sbt/src/sbt-test/nio/overrides/bar.txt create mode 100644 sbt/src/sbt-test/nio/overrides/baz.txt create mode 100644 sbt/src/sbt-test/nio/overrides/build.sbt create mode 100644 sbt/src/sbt-test/nio/overrides/foo.txt create mode 100644 sbt/src/sbt-test/nio/overrides/test diff --git a/main/src/main/scala/sbt/nio/Settings.scala b/main/src/main/scala/sbt/nio/Settings.scala index 6a4fdf12d..5934f2cb1 100644 --- a/main/src/main/scala/sbt/nio/Settings.scala +++ b/main/src/main/scala/sbt/nio/Settings.scala @@ -27,13 +27,26 @@ import scala.collection.immutable.VectorBuilder private[sbt] object Settings { private[sbt] def inject(transformed: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] = { - val fileOutputScopes = transformed.collect { - case s if s.key.key == fileOutputs.key && s.key.scope.task.toOption.isDefined => - s.key.scope + val definedSettings = new java.util.HashMap[Def.ScopedKey[_], VectorBuilder[Def.Setting[_]]] + val fileOutputScopes = transformed.flatMap { s => + val list = new VectorBuilder[Def.Setting[_]] + definedSettings.putIfAbsent(s.key, list) match { + case null => list += s + case l => l += s + } + if (s.key.key == fileOutputs.key && s.key.scope.task.toOption.isDefined) Some(s.key.scope) + else None }.toSet - transformed.flatMap { - case s if s.key.key == fileInputs.key => inputPathSettings(s) - case s => s :: maybeAddOutputsAndFileStamps(s, fileOutputScopes) + transformed.flatMap { s => + val inject = + if (s.key.key == fileInputs.key) inputPathSettings(s) + else maybeAddOutputsAndFileStamps(s, fileOutputScopes) + s +: inject.flatMap { setting => + (definedSettings.get(setting.key) match { + case null => Vector(setting) + case set => setting +: set.result() + }): Seq[Def.Setting[_]] + } } } @@ -126,7 +139,7 @@ private[sbt] object Settings { private[sbt] def inputPathSettings(setting: Def.Setting[_]): Seq[Def.Setting[_]] = { val scopedKey = setting.key val scope = scopedKey.scope - setting :: (Keys.allInputPathsAndAttributes in scope := { + (Keys.allInputPathsAndAttributes in scope := { val view = (fileTreeView in scope).value val inputs = (fileInputs in scope).value val stamper = (inputFileStamper in scope).value diff --git a/sbt/src/sbt-test/nio/code-formatter/build.sbt b/sbt/src/sbt-test/nio/code-formatter/build.sbt index 24fcef683..47a4e61af 100644 --- a/sbt/src/sbt-test/nio/code-formatter/build.sbt +++ b/sbt/src/sbt-test/nio/code-formatter/build.sbt @@ -14,7 +14,7 @@ val compileAndCheckNoClassFileUpdates = taskKey[Unit]("Checks that there are no compileAndCheckNoClassFileUpdates := { val current = (classFiles / outputFileStamps).value.toSet val previous = (classFiles / outputFileStamps).previous.getOrElse(Nil).toSet - assert(current == previous) + assert(current == previous, s"$current did not equal $previous") } val checkLastModified = inputKey[Unit]("Check the last modified time for a file") @@ -25,6 +25,7 @@ checkLastModified := { case (file, (negate, expectedLastModified)) => val sourceFile = baseDirectory.value / "src" / "main" / "scala" / file val lastModified = IO.getModifiedTimeOrZero(sourceFile) + println(s"$lastModified $expectedLastModified") negate match { case Some(_) => assert(lastModified != expectedLastModified) case None => assert(lastModified == expectedLastModified) diff --git a/sbt/src/sbt-test/nio/overrides/bar.txt b/sbt/src/sbt-test/nio/overrides/bar.txt new file mode 100644 index 000000000..e69de29bb diff --git a/sbt/src/sbt-test/nio/overrides/baz.txt b/sbt/src/sbt-test/nio/overrides/baz.txt new file mode 100644 index 000000000..e69de29bb diff --git a/sbt/src/sbt-test/nio/overrides/build.sbt b/sbt/src/sbt-test/nio/overrides/build.sbt new file mode 100644 index 000000000..9696eeea2 --- /dev/null +++ b/sbt/src/sbt-test/nio/overrides/build.sbt @@ -0,0 +1,24 @@ +import java.nio.file.Path + +val foo = taskKey[Path]("foo") +// Check a direct override +foo / outputFileStamps := Nil +foo := baseDirectory.value.toPath / "foo.txt" + +TaskKey[Unit]("checkFoo") := assert((foo / outputFileStamps).value == Nil) + +val bar = taskKey[Path]("bar") +// Check an append +bar / outputFileStamps ++= (baz / outputFileStamps).value +bar / outputFileStamps ++= (baz / outputFileStamps).value +bar := baseDirectory.value.toPath / "bar.txt" + +val baz = taskKey[Path]("baz") +baz := baseDirectory.value.toPath / "baz.txt" + +TaskKey[Unit]("checkBar") := { + val stamps = (bar / outputFileStamps).value + assert(stamps.length == 3) + val fileNames = stamps.map(_._1.getFileName.toString).toSet + assert(fileNames == Set("bar.txt", "baz.txt")) +} diff --git a/sbt/src/sbt-test/nio/overrides/foo.txt b/sbt/src/sbt-test/nio/overrides/foo.txt new file mode 100644 index 000000000..191028156 --- /dev/null +++ b/sbt/src/sbt-test/nio/overrides/foo.txt @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/sbt/src/sbt-test/nio/overrides/test b/sbt/src/sbt-test/nio/overrides/test new file mode 100644 index 000000000..070045158 --- /dev/null +++ b/sbt/src/sbt-test/nio/overrides/test @@ -0,0 +1,3 @@ +> checkBar + +> checkFoo