From 03fc4ac68640cebdfcc8f7ca8f04efa0aea57e22 Mon Sep 17 00:00:00 2001 From: Alistair Johnson Date: Wed, 4 Apr 2018 21:01:05 +0200 Subject: [PATCH] Ensure unique project Id in composite projects --- main/src/main/scala/sbt/Project.scala | 21 +++++++++++ .../main/scala/sbt/internal/BuildDef.scala | 4 ++- .../sbt/internal/EvaluateConfigurations.scala | 6 ++-- .../project/sbt-composite-projects/a/a.sbt | 2 -- .../sbt-composite-projects/b/build.sbt | 2 -- .../project/sbt-composite-projects/build.sbt | 24 ++++++++----- .../sbt-composite-projects/changes/shadow.sbt | 36 ++++++++----------- .../sbt-composite-projects/js/build.sbt | 2 ++ .../sbt-composite-projects/{a => jvm}/A.scala | 0 .../project/sbt-composite-projects/jvm/a.sbt | 2 ++ .../project/sbt-composite-projects/test | 24 ++++++++----- 11 files changed, 78 insertions(+), 45 deletions(-) delete mode 100644 sbt/src/sbt-test/project/sbt-composite-projects/a/a.sbt delete mode 100644 sbt/src/sbt-test/project/sbt-composite-projects/b/build.sbt create mode 100644 sbt/src/sbt-test/project/sbt-composite-projects/js/build.sbt rename sbt/src/sbt-test/project/sbt-composite-projects/{a => jvm}/A.scala (100%) create mode 100644 sbt/src/sbt-test/project/sbt-composite-projects/jvm/a.sbt diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index 2571b011e..1342cce77 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -125,6 +125,27 @@ trait CompositeProject { def componentProjects: Seq[Project] } +object CompositeProject { + + /** + * If two projects with the same id appear in `compositeProjects` and + * in `compositeProjects.map(_.componentProjects)`, the one in + * `compositeProjects` wins. + * This is necessary for backward compatibility with the idiom: + * lazy val foo = crossProject + * lazy val fooJVM = foo.jvm.setting + */ + def uniqueId(compositeProjects: Seq[Project]): Seq[Project] = { + for (p <- compositeProjects.flatMap(_.componentProjects)) yield { + compositeProjects.find(_.id == p.id) match { + case Some(overridingProject) => overridingProject + case None => p + } + } + + } +} + sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeProject { def componentProjects: Seq[Project] = this :: Nil diff --git a/main/src/main/scala/sbt/internal/BuildDef.scala b/main/src/main/scala/sbt/internal/BuildDef.scala index 52a9059d9..03c03a40e 100644 --- a/main/src/main/scala/sbt/internal/BuildDef.scala +++ b/main/src/main/scala/sbt/internal/BuildDef.scala @@ -18,7 +18,9 @@ import sbt.internal.inc.ReflectUtilities trait BuildDef { def projectDefinitions(@deprecated("unused", "") baseDirectory: File): Seq[Project] = projects def projects: Seq[Project] = - ReflectUtilities.allVals[CompositeProject](this).values.toSeq.flatMap(_.componentProjects) + CompositeProject.uniqueId( + ReflectUtilities.allVals[CompositeProject](this).values.toSeq.flatMap(_.componentProjects)) + // TODO: Should we grab the build core settings here or in a plugin? def settings: Seq[Setting[_]] = Defaults.buildCore def buildLoaders: Seq[BuildLoader.Components] = Nil diff --git a/main/src/main/scala/sbt/internal/EvaluateConfigurations.scala b/main/src/main/scala/sbt/internal/EvaluateConfigurations.scala index cfb599a20..c7e6781e9 100644 --- a/main/src/main/scala/sbt/internal/EvaluateConfigurations.scala +++ b/main/src/main/scala/sbt/internal/EvaluateConfigurations.scala @@ -151,11 +151,13 @@ private[sbt] object EvaluateConfigurations { val allGeneratedFiles = (definitions.generated ++ dslEntries.flatMap(_.generated)) loader => { - val projects = - definitions.values(loader).flatMap { + val projects = { + val compositeProjects = definitions.values(loader).flatMap { case p: CompositeProject => p.componentProjects.map(resolveBase(file.getParentFile, _)) case _ => Nil } + CompositeProject.uniqueId(compositeProjects) + } val (settingsRaw, manipulationsRaw) = dslEntries map (_.result apply loader) partition { case DslEntry.ProjectSettings(_) => true diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/a/a.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/a/a.sbt deleted file mode 100644 index 67966f6d2..000000000 --- a/sbt/src/sbt-test/project/sbt-composite-projects/a/a.sbt +++ /dev/null @@ -1,2 +0,0 @@ -val aa = taskKey[Unit]("A task in the 'a' project") -aa := println("Hello.") diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/b/build.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/b/build.sbt deleted file mode 100644 index 3c7dc5056..000000000 --- a/sbt/src/sbt-test/project/sbt-composite-projects/b/build.sbt +++ /dev/null @@ -1,2 +0,0 @@ -val h = taskKey[Unit]("A task in project 'b'") -h := println("Hello.") diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/build.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/build.sbt index 7bd373aa4..de8f1c134 100644 --- a/sbt/src/sbt-test/project/sbt-composite-projects/build.sbt +++ b/sbt/src/sbt-test/project/sbt-composite-projects/build.sbt @@ -4,21 +4,29 @@ import sbt.CompositeProject lazy val check = taskKey[Unit]("check") // Based on sbt-file-projects test -lazy val cross = new CompositeProject +lazy val foo = new CompositeProject { - val p1 = Project.apply("a", new File("a")) - val p2 = Project.apply("b", new File("b")) - def componentProjects: Seq[Project] = Seq(p1, p2) + val jvm = Project.apply("jvm", new File("jvm")) + val js = Project.apply("js", new File("js")) + def componentProjects: Seq[Project] = Seq(jvm, js) } +lazy val fooJVM = foo.jvm + +lazy val bar = project + .dependsOn(foo.jvm) + val g = taskKey[Unit]("A task in the root project") g := println("Hello.") check := { - val verP1 = (version in cross.p1).?.value - assert (verP1 == Some("0.1.0-SNAPSHOT")) + val verJvm = (version in foo.jvm).?.value + assert (verJvm == Some("0.1.0-SNAPSHOT")) - val verP2 = (version in cross.p2).?.value - assert (verP2 == Some("0.1.0-SNAPSHOT")) + val verFooJvm = (version in fooJVM).?.value + assert (verFooJvm == Some("0.1.0-SNAPSHOT")) + + val verJs = (version in foo.js).?.value + assert (verJs == Some("0.1.0-SNAPSHOT")) } diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadow.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadow.sbt index 9bf54ab9f..47334ba0f 100644 --- a/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadow.sbt +++ b/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadow.sbt @@ -3,38 +3,30 @@ import sbt.CompositeProject lazy val check = taskKey[Unit]("check") -lazy val a = (project in file("a")) - .settings( - version := "0.2.0" - ) - // Based on sbt-file-projects test -lazy val cross = new CompositeProject +lazy val foo = new CompositeProject { - val p1 = Project.apply("a", new File("a")) - val p2 = Project.apply("b", new File("b")) - def componentProjects: Seq[Project] = Seq(p1, p2) + val jvm = Project.apply("jvm", new File("jvm")) + val js = Project.apply("js", new File("js")) + def componentProjects: Seq[Project] = Seq(jvm, js) } -lazy val b = (project in file("b")) - .settings( - version := "0.2.0" - ) +lazy val fooJVM = foo.jvm.settings(version := "0.2.0") // this one needs to win + +lazy val bar = project + .dependsOn(foo.jvm) val g = taskKey[Unit]("A task in the root project") g := println("Hello.") check := { - val verP1 = (version in cross.p1).?.value - assert (verP1 == Some("0.2.0"))//Some("0.1.0-SNAPSHOT")) + val verJvm = (version in foo.jvm).?.value + assert (verJvm == Some("0.2.0")) - val verP2 = (version in cross.p2).?.value - assert (verP2 == Some("0.1.0-SNAPSHOT")) + val verFooJvm = (version in fooJVM).?.value + assert (verFooJvm == Some("0.2.0")) - val verA = (version in a).?.value - assert (verA == Some("0.2.0")) - - val verB = (version in b).?.value - assert (verA == Some("0.2.0")) + val verJs = (version in foo.js).?.value + assert (verJs == Some("0.1.0-SNAPSHOT")) } diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/js/build.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/js/build.sbt new file mode 100644 index 000000000..0ddd49e30 --- /dev/null +++ b/sbt/src/sbt-test/project/sbt-composite-projects/js/build.sbt @@ -0,0 +1,2 @@ +val h = taskKey[Unit]("A task in project 'js'") +h := println("Hello.") diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/a/A.scala b/sbt/src/sbt-test/project/sbt-composite-projects/jvm/A.scala similarity index 100% rename from sbt/src/sbt-test/project/sbt-composite-projects/a/A.scala rename to sbt/src/sbt-test/project/sbt-composite-projects/jvm/A.scala diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/jvm/a.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/jvm/a.sbt new file mode 100644 index 000000000..9b73a55bf --- /dev/null +++ b/sbt/src/sbt-test/project/sbt-composite-projects/jvm/a.sbt @@ -0,0 +1,2 @@ +val aa = taskKey[Unit]("A task in the 'jvm' project") +aa := println("Hello.") diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/test b/sbt/src/sbt-test/project/sbt-composite-projects/test index 868ecac69..5bb98d747 100644 --- a/sbt/src/sbt-test/project/sbt-composite-projects/test +++ b/sbt/src/sbt-test/project/sbt-composite-projects/test @@ -1,22 +1,30 @@ > g -> root/compile -> a/compile -> a/aa -> b/compile -> b/h +> jvm/compile +> jvm/aa +> js/compile +> js/h > c/compile +> bar/compile $ copy-file changes/basic.sbt basic.sbt > reload > g > root/compile -> a/compile -> a/aa -> b/compile -> b/h +> jvm/compile +> jvm/aa +> js/compile +> js/h > c/compile +> bar/compile > check $ copy-file changes/shadow.sbt build.sbt > reload +> jvm/compile +> jvm/aa +> js/compile +> js/h +> c/compile +> bar/compile > check