From 68c005e4b58a968a3c0ead2b342076d3e8054684 Mon Sep 17 00:00:00 2001 From: Alistair Johnson Date: Sat, 7 Apr 2018 01:04:45 +0200 Subject: [PATCH] Ensure precedence of top level Projects over ComponentProjects --- main/src/main/scala/sbt/Project.scala | 28 +++++++++----- .../main/scala/sbt/internal/BuildDef.scala | 9 +++-- .../sbt/internal/EvaluateConfigurations.scala | 15 ++++++-- notes/1.2.0/introduce-CompositeProject.md | 9 +++++ .../project/sbt-composite-projects/build.sbt | 14 ++++--- .../sbt-composite-projects/changes/shadow.sbt | 10 +++-- .../changes/shadowLazy.sbt | 37 +++++++++++++++++++ .../project/sbt-composite-projects/test | 10 +++++ 8 files changed, 107 insertions(+), 25 deletions(-) create mode 100644 notes/1.2.0/introduce-CompositeProject.md create mode 100644 sbt/src/sbt-test/project/sbt-composite-projects/changes/shadowLazy.sbt diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index 1342cce77..789cb709f 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -125,25 +125,35 @@ trait CompositeProject { def componentProjects: Seq[Project] } -object CompositeProject { +private[sbt] 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: + * Expand user defined `projects` with the component projects of `compositeProjects`. + * + * If two projects with the same id appear in the user defined `projects` and + * in `compositeProjects.componentProjects`, the one in `projects` wins. + * This is necessary for backward compatibility with the idioms: + * {{{ * lazy val foo = crossProject - * lazy val fooJVM = foo.jvm.setting + * lazy val fooJS = foo.js.settings(...) + * lazy val fooJVM = foo.jvm.settings(...) + * }}} + * and the rarer: + * {{{ + * lazy val fooJS = foo.js.settings(...) + * lazy val foo = crossProject + * lazy val fooJVM = foo.jvm.settings(...) + * }}} */ - def uniqueId(compositeProjects: Seq[Project]): Seq[Project] = { + def expand(projects: Seq[Project], compositeProjects: Seq[CompositeProject]): Seq[Project] = { for (p <- compositeProjects.flatMap(_.componentProjects)) yield { - compositeProjects.find(_.id == p.id) match { + projects.find(_.id == p.id) match { case Some(overridingProject) => overridingProject case None => p } } - } + } sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeProject { diff --git a/main/src/main/scala/sbt/internal/BuildDef.scala b/main/src/main/scala/sbt/internal/BuildDef.scala index 03c03a40e..5a916acb5 100644 --- a/main/src/main/scala/sbt/internal/BuildDef.scala +++ b/main/src/main/scala/sbt/internal/BuildDef.scala @@ -17,10 +17,11 @@ import sbt.internal.inc.ReflectUtilities trait BuildDef { def projectDefinitions(@deprecated("unused", "") baseDirectory: File): Seq[Project] = projects - def projects: Seq[Project] = - CompositeProject.uniqueId( - ReflectUtilities.allVals[CompositeProject](this).values.toSeq.flatMap(_.componentProjects)) - + def projects: Seq[Project] = { + val projects = ReflectUtilities.allVals[Project](this).values.toSeq + val compositeProjects = ReflectUtilities.allVals[CompositeProject](this).values.toSeq + CompositeProject.expand(projects, compositeProjects) + } // 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 c7e6781e9..241b8c6b1 100644 --- a/main/src/main/scala/sbt/internal/EvaluateConfigurations.scala +++ b/main/src/main/scala/sbt/internal/EvaluateConfigurations.scala @@ -152,11 +152,18 @@ private[sbt] object EvaluateConfigurations { loader => { val projects = { - val compositeProjects = definitions.values(loader).flatMap { - case p: CompositeProject => p.componentProjects.map(resolveBase(file.getParentFile, _)) - case _ => Nil + + val projects = definitions.values(loader).collect { + case p: Project => p } - CompositeProject.uniqueId(compositeProjects) + + val compositeProjects = definitions.values(loader).collect { + case p: CompositeProject => p + } + + CompositeProject + .expand(projects, compositeProjects) + .map(resolveBase(file.getParentFile, _)) } val (settingsRaw, manipulationsRaw) = dslEntries map (_.result apply loader) partition { diff --git a/notes/1.2.0/introduce-CompositeProject.md b/notes/1.2.0/introduce-CompositeProject.md new file mode 100644 index 000000000..759d75a71 --- /dev/null +++ b/notes/1.2.0/introduce-CompositeProject.md @@ -0,0 +1,9 @@ + +[#3042]: https://github.com/sbt/sbt/issues/3042 +[#4056]: https://github.com/sbt/sbt/pull/4056 + +### Introduce CompositeProject + +### Improvements + +- Support for: `lazy val foo = someCompositeProject` (e.g.`CrossProject`) [#3042][]/[#4056][] 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 de8f1c134..1537b2610 100644 --- a/sbt/src/sbt-test/project/sbt-composite-projects/build.sbt +++ b/sbt/src/sbt-test/project/sbt-composite-projects/build.sbt @@ -6,11 +6,12 @@ lazy val check = taskKey[Unit]("check") // Based on sbt-file-projects test lazy val foo = new CompositeProject { - val jvm = Project.apply("jvm", new File("jvm")) - val js = Project.apply("js", new File("js")) + val jvm = Project.apply("jvm", new File("jvm")).settings(version := "0.1.0") // this one needs to win + val js = Project.apply("js", new File("js")).settings(version := "0.1.0") // this one needs to win def componentProjects: Seq[Project] = Seq(jvm, js) } +lazy val fooJS = foo.js lazy val fooJVM = foo.jvm lazy val bar = project @@ -22,11 +23,14 @@ g := println("Hello.") check := { val verJvm = (version in foo.jvm).?.value - assert (verJvm == Some("0.1.0-SNAPSHOT")) + assert (verJvm == Some("0.1.0")) val verFooJvm = (version in fooJVM).?.value - assert (verFooJvm == Some("0.1.0-SNAPSHOT")) + assert (verFooJvm == Some("0.1.0")) val verJs = (version in foo.js).?.value - assert (verJs == Some("0.1.0-SNAPSHOT")) + assert (verJs == Some("0.1.0")) + + val verFooJs = (version in fooJS).?.value + assert (verFooJs == Some("0.1.0")) } 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 47334ba0f..0713e7f4b 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 @@ -6,11 +6,12 @@ lazy val check = taskKey[Unit]("check") // Based on sbt-file-projects test lazy val foo = new CompositeProject { - val jvm = Project.apply("jvm", new File("jvm")) - val js = Project.apply("js", new File("js")) + val jvm = Project.apply("jvm", new File("jvm")).settings(version := "0.1.0") + val js = Project.apply("js", new File("js")).settings(version := "0.1.0") // this one needs to win def componentProjects: Seq[Project] = Seq(jvm, js) } +lazy val fooJS = foo.js lazy val fooJVM = foo.jvm.settings(version := "0.2.0") // this one needs to win lazy val bar = project @@ -28,5 +29,8 @@ check := { assert (verFooJvm == Some("0.2.0")) val verJs = (version in foo.js).?.value - assert (verJs == Some("0.1.0-SNAPSHOT")) + assert (verJs == Some("0.1.0")) + + val verFooJs = (version in fooJS).?.value + assert (verFooJs == Some("0.1.0")) } diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadowLazy.sbt b/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadowLazy.sbt new file mode 100644 index 000000000..492fbd621 --- /dev/null +++ b/sbt/src/sbt-test/project/sbt-composite-projects/changes/shadowLazy.sbt @@ -0,0 +1,37 @@ +import sbt.internal.AddSettings +import sbt.CompositeProject + +lazy val check = taskKey[Unit]("check") + +lazy val fooJS = foo.js.settings(version := "0.2.1") // this one needs to win + +// Based on sbt-file-projects test +lazy val foo = new CompositeProject +{ + val jvm = Project.apply("jvm", new File("jvm")).settings(version := "0.1.0") + val js = Project.apply("js", new File("js")).settings(version := "0.1.0") + def componentProjects: Seq[Project] = Seq(jvm, js) +} + +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 verJvm = (version in foo.jvm).?.value + assert (verJvm == Some("0.2.0")) + + val verFooJvm = (version in fooJVM).?.value + assert (verFooJvm == Some("0.2.0")) + + val verJs = (version in foo.js).?.value + assert (verJs == Some("0.2.1")) + + val verFooJs = (version in fooJS).?.value + assert (verFooJs == Some("0.2.1")) +} diff --git a/sbt/src/sbt-test/project/sbt-composite-projects/test b/sbt/src/sbt-test/project/sbt-composite-projects/test index 5bb98d747..34bc8097d 100644 --- a/sbt/src/sbt-test/project/sbt-composite-projects/test +++ b/sbt/src/sbt-test/project/sbt-composite-projects/test @@ -28,3 +28,13 @@ $ copy-file changes/shadow.sbt build.sbt > c/compile > bar/compile > check + +$ copy-file changes/shadowLazy.sbt build.sbt +> reload +> jvm/compile +> jvm/aa +> js/compile +> js/h +> c/compile +> bar/compile +> check \ No newline at end of file