From 9bad462f7ab5490242c68d57d9f72c3d42daf008 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 11 Jan 2017 17:06:05 +0000 Subject: [PATCH 1/6] Fix triggeredBy with := Fixes #1444 --- .../sbt-test/actions/triggeredby/build.sbt | 21 +++++++++++++++++++ sbt/src/sbt-test/actions/triggeredby/test | 7 +++++++ .../src/main/scala/sbt/std/TaskExtra.scala | 8 ++++++- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 sbt/src/sbt-test/actions/triggeredby/build.sbt create mode 100644 sbt/src/sbt-test/actions/triggeredby/test diff --git a/sbt/src/sbt-test/actions/triggeredby/build.sbt b/sbt/src/sbt-test/actions/triggeredby/build.sbt new file mode 100644 index 000000000..08367b448 --- /dev/null +++ b/sbt/src/sbt-test/actions/triggeredby/build.sbt @@ -0,0 +1,21 @@ +val taskA = taskKey[File]("") +val taskB = taskKey[File]("") +val taskC = taskKey[File]("") +val taskD = taskKey[File]("") + +taskA := touch(target.value / "a") +taskB := touch(target.value / "b") +taskC := touch(target.value / "c") +taskD := touch(target.value / "d") + +// a <<= a triggeredBy b +// means "a" will be triggered by "b" +// said differently, invoking "b" will run "b" and then run "a" + +taskA <<= taskA triggeredBy taskB +taskC := (taskC triggeredBy taskD).value + + + +// test utils +def touch(f: File): File = { IO touch f; f } diff --git a/sbt/src/sbt-test/actions/triggeredby/test b/sbt/src/sbt-test/actions/triggeredby/test new file mode 100644 index 000000000..063b1fbb1 --- /dev/null +++ b/sbt/src/sbt-test/actions/triggeredby/test @@ -0,0 +1,7 @@ +> taskB +$ exists target/b +$ exists target/a + +> taskD +$ exists target/d +$ exists target/c diff --git a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala index 10914daee..0d5f4c2df 100644 --- a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala @@ -117,8 +117,14 @@ trait TaskExtra { def failure: Task[Incomplete] = mapFailure(idFun) def result: Task[Result[S]] = mapR(idFun) + private val triggeredByKey = AttributeKey[Seq[Task[_]]]("triggered-by") + private def newInfo[A]: Info[A] = { + val i = Info[A]() + (in.info get triggeredByKey).fold(i)(i.set(triggeredByKey, _)) + } + def flatMapR[T](f: Result[S] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T, K](in, f, ml)) - def mapR[T](f: Result[S] => T): Task[T] = Task(Info(), new Mapped[T, K](in, f, ml)) + def mapR[T](f: Result[S] => T): Task[T] = Task(newInfo, new Mapped[T, K](in, f, ml)) def dependsOn(tasks: Task[_]*): Task[S] = Task(Info(), new DependsOn(in, tasks)) def flatMap[T](f: S => Task[T]): Task[T] = flatMapR(f compose successM) From 2404d609ce3c2e28f0977a1181cd78046ea6137f Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 12 Jan 2017 14:41:12 +0000 Subject: [PATCH 2/6] Fix runBefore with := --- .../actions/{triggeredby => task-map}/build.sbt | 17 +++++++++++++++++ sbt/src/sbt-test/actions/task-map/test | 15 +++++++++++++++ sbt/src/sbt-test/actions/triggeredby/test | 7 ------- .../src/main/scala/sbt/std/TaskExtra.scala | 9 +++++---- 4 files changed, 37 insertions(+), 11 deletions(-) rename sbt/src/sbt-test/actions/{triggeredby => task-map}/build.sbt (53%) create mode 100644 sbt/src/sbt-test/actions/task-map/test delete mode 100644 sbt/src/sbt-test/actions/triggeredby/test diff --git a/sbt/src/sbt-test/actions/triggeredby/build.sbt b/sbt/src/sbt-test/actions/task-map/build.sbt similarity index 53% rename from sbt/src/sbt-test/actions/triggeredby/build.sbt rename to sbt/src/sbt-test/actions/task-map/build.sbt index 08367b448..34c26b3b9 100644 --- a/sbt/src/sbt-test/actions/triggeredby/build.sbt +++ b/sbt/src/sbt-test/actions/task-map/build.sbt @@ -3,11 +3,21 @@ val taskB = taskKey[File]("") val taskC = taskKey[File]("") val taskD = taskKey[File]("") +val taskE = taskKey[File]("") +val taskF = taskKey[File]("") +val taskG = taskKey[File]("") +val taskH = taskKey[File]("") + taskA := touch(target.value / "a") taskB := touch(target.value / "b") taskC := touch(target.value / "c") taskD := touch(target.value / "d") +taskE := touch(target.value / "e") +taskF := touch(target.value / "f") +taskG := touch(target.value / "g") +taskH := touch(target.value / "h") + // a <<= a triggeredBy b // means "a" will be triggered by "b" // said differently, invoking "b" will run "b" and then run "a" @@ -15,6 +25,13 @@ taskD := touch(target.value / "d") taskA <<= taskA triggeredBy taskB taskC := (taskC triggeredBy taskD).value +// e <<= e runBefore f +// means "e" will be run before running "f" +// said differently, invoking "f" will run "e" and then run "f" + +taskE <<= taskE runBefore taskF +taskG := (taskG runBefore taskH).value + // test utils diff --git a/sbt/src/sbt-test/actions/task-map/test b/sbt/src/sbt-test/actions/task-map/test new file mode 100644 index 000000000..0617f3abe --- /dev/null +++ b/sbt/src/sbt-test/actions/task-map/test @@ -0,0 +1,15 @@ +> taskB +$ exists target/b +$ exists target/a + +> taskD +$ exists target/d +$ exists target/c + +> taskF +$ exists target/e +$ exists target/f + +> taskH +$ exists target/g +$ exists target/h diff --git a/sbt/src/sbt-test/actions/triggeredby/test b/sbt/src/sbt-test/actions/triggeredby/test deleted file mode 100644 index 063b1fbb1..000000000 --- a/sbt/src/sbt-test/actions/triggeredby/test +++ /dev/null @@ -1,7 +0,0 @@ -> taskB -$ exists target/b -$ exists target/a - -> taskD -$ exists target/d -$ exists target/c diff --git a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala index 0d5f4c2df..be5a01ca7 100644 --- a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala @@ -118,10 +118,11 @@ trait TaskExtra { def result: Task[Result[S]] = mapR(idFun) private val triggeredByKey = AttributeKey[Seq[Task[_]]]("triggered-by") - private def newInfo[A]: Info[A] = { - val i = Info[A]() - (in.info get triggeredByKey).fold(i)(i.set(triggeredByKey, _)) - } + private val runBeforeKey = AttributeKey[Seq[Task[_]]]("run-before") + private def newInfo[A]: Info[A] = + Seq(triggeredByKey, runBeforeKey) + .flatMap(k => (in.info get k) map (k -> _)) + .foldLeft(Info[A]()) { case (i, (k, v)) => i.set(k, v) } def flatMapR[T](f: Result[S] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T, K](in, f, ml)) def mapR[T](f: Result[S] => T): Task[T] = Task(newInfo, new Mapped[T, K](in, f, ml)) From 936dda6297cba65d5611fb20d696738333697f3e Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 12 Jan 2017 16:00:44 +0000 Subject: [PATCH 3/6] Copy all attributes for all methods in SingleInTask For when := is used over <<= for 'triggeredBy', 'runBefore', etc.. --- tasks/standard/src/main/scala/sbt/std/TaskExtra.scala | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala index be5a01ca7..af09e8b8c 100644 --- a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala @@ -117,16 +117,11 @@ trait TaskExtra { def failure: Task[Incomplete] = mapFailure(idFun) def result: Task[Result[S]] = mapR(idFun) - private val triggeredByKey = AttributeKey[Seq[Task[_]]]("triggered-by") - private val runBeforeKey = AttributeKey[Seq[Task[_]]]("run-before") - private def newInfo[A]: Info[A] = - Seq(triggeredByKey, runBeforeKey) - .flatMap(k => (in.info get k) map (k -> _)) - .foldLeft(Info[A]()) { case (i, (k, v)) => i.set(k, v) } + private def newInfo[A]: Info[A] = Info[A](in.info.attributes) - def flatMapR[T](f: Result[S] => Task[T]): Task[T] = Task(Info(), new FlatMapped[T, K](in, f, ml)) + def flatMapR[T](f: Result[S] => Task[T]): Task[T] = Task(newInfo, new FlatMapped[T, K](in, f, ml)) def mapR[T](f: Result[S] => T): Task[T] = Task(newInfo, new Mapped[T, K](in, f, ml)) - def dependsOn(tasks: Task[_]*): Task[S] = Task(Info(), new DependsOn(in, tasks)) + def dependsOn(tasks: Task[_]*): Task[S] = Task(newInfo, new DependsOn(in, tasks)) def flatMap[T](f: S => Task[T]): Task[T] = flatMapR(f compose successM) def flatFailure[T](f: Incomplete => Task[T]): Task[T] = flatMapR(f compose failM) From 011d0e848928f925f29c3b4fd4c642ef6cdf3d41 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 12 Jan 2017 16:13:51 +0000 Subject: [PATCH 4/6] Remove some code duplication between TaskInstance and MultiInTask --- main/settings/src/main/scala/sbt/std/TaskMacro.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/settings/src/main/scala/sbt/std/TaskMacro.scala b/main/settings/src/main/scala/sbt/std/TaskMacro.scala index 6c48613dd..76392716b 100644 --- a/main/settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main/settings/src/main/scala/sbt/std/TaskMacro.scala @@ -18,7 +18,7 @@ object TaskInstance extends MonadInstance { import TaskExtra._ final type M[x] = Task[x] - def app[K[L[x]], Z](in: K[Task], f: K[Id] => Z)(implicit a: AList[K]): Task[Z] = Task(Info(), new Mapped[Z, K](in, f compose allM, a)) + def app[K[L[x]], Z](in: K[Task], f: K[Id] => Z)(implicit a: AList[K]): Task[Z] = in map f def map[S, T](in: Task[S], f: S => T): Task[T] = in map f def flatten[T](in: Task[Task[T]]): Task[T] = in flatMap idFun[Task[T]] def pure[T](t: () => T): Task[T] = toTask(t) From c6d3bbacfae2bd1d910d877924572ea58bf65aa9 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 13 Jan 2017 12:05:03 +0000 Subject: [PATCH 5/6] Migrate actions/depends-on to fix it Seems following the deprecation warning info and the website documentation and avoiding the BuildCommon inputTask method avoids whatever problem was causing it to fail... Strange.. but ok? --- sbt/src/sbt-test/actions/depends-on/build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt/src/sbt-test/actions/depends-on/build.sbt b/sbt/src/sbt-test/actions/depends-on/build.sbt index c20f79671..8a319ce52 100644 --- a/sbt/src/sbt-test/actions/depends-on/build.sbt +++ b/sbt/src/sbt-test/actions/depends-on/build.sbt @@ -14,7 +14,7 @@ lazy val d = taskKey[Unit]("") lazy val input = (project in file("input")). settings( - f := (inputTask { _ map { args => if (args(0) == "succeed") () else sys.error("fail") } }).evaluated, + f := (if (Def.spaceDelimited().parsed.head == "succeed") () else sys.error("fail")), j := sys.error("j"), g := (f dependsOn(j)).evaluated, h := (f map { _ => IO.touch(file("h")) }).evaluated From 486c3c3167a1d4c7048a5b9ec9fb5dfa374b256b Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 13 Jan 2017 14:22:49 +0000 Subject: [PATCH 6/6] Work-around actions/depends-on failure --- tasks/standard/src/main/scala/sbt/std/TaskExtra.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala index af09e8b8c..716686241 100644 --- a/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks/standard/src/main/scala/sbt/std/TaskExtra.scala @@ -117,7 +117,10 @@ trait TaskExtra { def failure: Task[Incomplete] = mapFailure(idFun) def result: Task[Result[S]] = mapR(idFun) - private def newInfo[A]: Info[A] = Info[A](in.info.attributes) + // The "taskDefinitionKey" is used, at least, by the ".previous" functionality. + // But apparently it *cannot* survive a task map/flatMap/etc. See actions/depends-on. + private def newInfo[A]: Info[A] = + Info[A](AttributeMap(in.info.attributes.entries.filter(_.key.label != "taskDefinitionKey"))) def flatMapR[T](f: Result[S] => Task[T]): Task[T] = Task(newInfo, new FlatMapped[T, K](in, f, ml)) def mapR[T](f: Result[S] => T): Task[T] = Task(newInfo, new Mapped[T, K](in, f, ml))