Merge pull request #4056 from BennyHill/fix/3042

Introduce CompositeProject
This commit is contained in:
Dale Wijnand 2018-04-09 11:30:17 +01:00 committed by GitHub
commit 4fc45e0155
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 215 additions and 6 deletions

View File

@ -121,7 +121,45 @@ sealed trait ProjectDefinition[PR <: ProjectReference] {
if (ts.isEmpty) Nil else s"$label: $ts" :: Nil
}
sealed trait Project extends ProjectDefinition[ProjectReference] {
trait CompositeProject {
def componentProjects: Seq[Project]
}
private[sbt] object CompositeProject {
/**
* 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 user defined project wins.
* This is necessary for backward compatibility with the idioms:
* {{{
* lazy val foo = crossProject
* 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 expand(compositeProjects: Seq[CompositeProject]): Seq[Project] = {
val userProjects = compositeProjects.collect { case p: Project => p }
for (p <- compositeProjects.flatMap(_.componentProjects)) yield {
userProjects.find(_.id == p.id) match {
case Some(userProject) => userProject
case None => p
}
}
}.distinct
}
sealed trait Project extends ProjectDefinition[ProjectReference] with CompositeProject {
def componentProjects: Seq[Project] = this :: Nil
private[sbt] def copy(
id: String = id,
base: File = base,

View File

@ -17,7 +17,8 @@ import sbt.internal.inc.ReflectUtilities
trait BuildDef {
def projectDefinitions(@deprecated("unused", "") baseDirectory: File): Seq[Project] = projects
def projects: Seq[Project] = ReflectUtilities.allVals[Project](this).values.toSeq
def projects: Seq[Project] =
CompositeProject.expand(ReflectUtilities.allVals[CompositeProject](this).values.toSeq)
// 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

View File

@ -151,10 +151,12 @@ private[sbt] object EvaluateConfigurations {
val allGeneratedFiles = (definitions.generated ++ dslEntries.flatMap(_.generated))
loader =>
{
val projects =
definitions.values(loader).collect {
case p: Project => resolveBase(file.getParentFile, p)
val projects = {
val compositeProjects = definitions.values(loader).collect {
case p: CompositeProject => p
}
CompositeProject.expand(compositeProjects).map(resolveBase(file.getParentFile, _))
}
val (settingsRaw, manipulationsRaw) =
dslEntries map (_.result apply loader) partition {
case DslEntry.ProjectSettings(_) => true
@ -280,7 +282,10 @@ private[sbt] object EvaluateConfigurations {
}
private[this] def extractedValTypes: Seq[String] =
Seq(classOf[Project], classOf[InputKey[_]], classOf[TaskKey[_]], classOf[SettingKey[_]])
Seq(classOf[CompositeProject],
classOf[InputKey[_]],
classOf[TaskKey[_]],
classOf[SettingKey[_]])
.map(_.getName)
private[this] def evaluateDefinitions(eval: Eval,

View File

@ -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][]

View File

@ -0,0 +1,36 @@
import sbt.internal.AddSettings
import sbt.CompositeProject
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")).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
.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.1.0"))
val verFooJvm = (version in fooJVM).?.value
assert (verFooJvm == Some("0.1.0"))
val verJs = (version in foo.js).?.value
assert (verJs == Some("0.1.0"))
val verFooJs = (version in fooJS).?.value
assert (verFooJs == Some("0.1.0"))
}

View File

@ -0,0 +1 @@
lazy val root = (project in file("."))

View File

@ -0,0 +1,36 @@
import sbt.internal.AddSettings
import sbt.CompositeProject
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")).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
.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.1.0"))
val verFooJs = (version in fooJS).?.value
assert (verFooJs == Some("0.1.0"))
}

View File

@ -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"))
}

View File

@ -0,0 +1,2 @@
val h = taskKey[Unit]("A task in project 'js'")
h := println("Hello.")

View File

@ -0,0 +1 @@
object A

View File

@ -0,0 +1,2 @@
val aa = taskKey[Unit]("A task in the 'jvm' project")
aa := println("Hello.")

View File

@ -0,0 +1 @@
val c = project

View File

@ -0,0 +1,40 @@
> g
-> root/compile
> jvm/compile
> jvm/aa
> js/compile
> js/h
> c/compile
> bar/compile
$ copy-file changes/basic.sbt basic.sbt
> reload
> g
> root/compile
> 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
$ copy-file changes/shadowLazy.sbt build.sbt
> reload
> jvm/compile
> jvm/aa
> js/compile
> js/h
> c/compile
> bar/compile
> check