From 88fd75bc72c3cfb312f39f821ed263abcb6df371 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 8 Jul 2019 16:15:38 -0400 Subject: [PATCH] implement VirtualAxis Fixes https://github.com/sbt/sbt-projectmatrix/issues/13 Fixes https://github.com/sbt/sbt-projectmatrix/issues/14 This adds the notion of VirutalAxis that allows the matrix to define strong or weak axis. --- README.markdown | 43 ++- src/main/scala/sbt/VirtualAxis.scala | 72 +++++ .../sbt/{ => internal}/ProjectMatrix.scala | 293 +++++++++++++----- .../ProjectMatrixReference.scala | 1 + .../ProjectMatrixPlugin.scala | 1 + src/sbt-test/projectMatrix/crosslib/build.sbt | 35 --- .../crosslib/project/plugins.sbt | 5 - src/sbt-test/projectMatrix/crosslib/test | 5 - .../custom/app/src/main/scala/B.scala | 5 + src/sbt-test/projectMatrix/custom/build.sbt | 31 +- .../custom/core/src/main/scala/A.scala | 5 + .../custom/project/ConfigAxis.scala | 5 + src/sbt-test/projectMatrix/custom/test | 8 +- src/sbt-test/projectMatrix/jvm/build.sbt | 27 +- 14 files changed, 379 insertions(+), 157 deletions(-) create mode 100644 src/main/scala/sbt/VirtualAxis.scala rename src/main/scala/sbt/{ => internal}/ProjectMatrix.scala (53%) rename src/main/scala/sbt/{ => internal}/ProjectMatrixReference.scala (92%) delete mode 100644 src/sbt-test/projectMatrix/crosslib/build.sbt delete mode 100644 src/sbt-test/projectMatrix/crosslib/project/plugins.sbt delete mode 100644 src/sbt-test/projectMatrix/crosslib/test create mode 100644 src/sbt-test/projectMatrix/custom/app/src/main/scala/B.scala create mode 100644 src/sbt-test/projectMatrix/custom/core/src/main/scala/A.scala create mode 100644 src/sbt-test/projectMatrix/custom/project/ConfigAxis.scala diff --git a/README.markdown b/README.markdown index 11d048dc8..a45e2210b 100644 --- a/README.markdown +++ b/README.markdown @@ -107,31 +107,50 @@ This will create subproject `coreNative2_11`. The rows can also be used for parallel cross-library building. For example, if you want to build against Config 1.2 and Config 1.3, you can do something like this: +In `project/ConfigAxis.scala`: + +```scala +import sbt._ + +case class ConfigAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis { +} +``` + +In `build.sbt`: + ```scala ThisBuild / organization := "com.example" ThisBuild / version := "0.1.0-SNAPSHOT" -lazy val core = (projectMatrix in file("core")) +lazy val config12 = ConfigAxis("Config1_2", "config1.2") +lazy val config13 = ConfigAxis("Config1_3", "config1.3") + +lazy val scala212 = "2.12.10" +lazy val scala211 = "2.11.12" + +lazy val app = (projectMatrix in file("app")) .settings( - name := "core" + name := "app" ) - .crossLibrary( - scalaVersions = Seq("2.12.8", "2.11.12"), - suffix = "Config1.2", - settings = Seq( + .customRow( + scalaVersions = Seq(scala212, scala211), + axisValues = Seq(config12, VirtualAxis.jvm), + _.settings( + moduleName := name.value + "_config1.2", libraryDependencies += "com.typesafe" % "config" % "1.2.1" ) ) - .crossLibrary( - scalaVersions = Seq("2.12.8"), - suffix = "Config1.3", - settings = Seq( + .customRow( + scalaVersions = Seq(scala212, scala211), + axisValues = Seq(config13, VirtualAxis.jvm), + _.settings( + moduleName := name.value + "_config1.3", libraryDependencies += "com.typesafe" % "config" % "1.3.3" ) ) ``` -This will create `coreConfig1_22_11`, `coreConfig1_22_12`, and `coreConfig1_32_12` respectively producing `core_config1.3_2.12`, `core_config1.2_2.11`, and `core_config1.2_2.12` artifacts. +This will create `appConfig1_22_11`, `appConfig1_22_12`, and `appConfig1_32_12` respectively producing `app_config1.3_2.12`, `app_config1.2_2.11`, and `app_config1.2_2.12` artifacts. ### referncing the generated subprojects @@ -140,7 +159,7 @@ You might want to reference to one of the projects within `build.sbt`. ```scala lazy val core12 = core.jvm("2.12.8") -// lazy val core12 = core.crossLib("Config1.2")("2.12.8") +lazy val appConfig12_212 = app.finder(config13, VirtualAxis.jvm)("2.12.8") ``` In the above `core12` returns `Project` type. diff --git a/src/main/scala/sbt/VirtualAxis.scala b/src/main/scala/sbt/VirtualAxis.scala new file mode 100644 index 000000000..2b2648909 --- /dev/null +++ b/src/main/scala/sbt/VirtualAxis.scala @@ -0,0 +1,72 @@ +package sbt + +import sbt.librarymanagement.CrossVersion.partialVersion + +/** Virtual Axis represents a parameter to a project matrix row. */ +sealed abstract class VirtualAxis { + def directorySuffix: String + + def idSuffix: String + + /* The order to sort the suffixes if there were multiple axes. */ + def suffixOrder: Int = 50 +} + +object VirtualAxis { + /** + * WeakAxis allows a row to depend on another row with Zero value. + * For example, Scala version can be Zero for Java project, and it's ok. + */ + abstract class WeakAxis extends VirtualAxis + + /** StrongAxis requires a row to depend on another row with the same selected value. */ + abstract class StrongAxis extends VirtualAxis + + + def isMatch(lhs: Seq[VirtualAxis], rhs: Seq[VirtualAxis]): Boolean = { + def isCompatible(v: VirtualAxis, stack: Seq[VirtualAxis]): Boolean = + v match { + case v: WeakAxis => + val clazz = v.getClass + stack.contains(v) || !stack.exists(_.getClass == clazz) + case v: StrongAxis => + stack.contains(v) + } + lhs.forall(isCompatible(_, rhs)) && rhs.forall(isCompatible(_, lhs)) + } + + case class ScalaVersionAxis(scalaVersion: String, value: String) extends WeakAxis { + override def idSuffix: String = directorySuffix.replaceAll("""\W+""", "_") + override val suffixOrder: Int = 100 + override def directorySuffix: String = value + + // use only the scalaVersion field for equality + override def equals(obj: Any): Boolean = { + if (obj.isInstanceOf[AnyRef] && (this eq obj.asInstanceOf[AnyRef])) true + else if (!obj.isInstanceOf[ScalaVersionAxis]) false + else { + val o = obj.asInstanceOf[ScalaVersionAxis] + this.scalaVersion == o.scalaVersion + } + } + override def hashCode: Int = { + 37 * (17 + "sbt.ScalaVersionAxis".hashCode()) + scalaVersion.hashCode() + } + } + + case class PlatformAxis(value: String, idSuffix: String, directorySuffix: String) extends StrongAxis { + override val suffixOrder: Int = 80 + } + + def scalaPartialVersion(scalaVersion: String): ScalaVersionAxis = + partialVersion(scalaVersion) match { + case Some((m, n)) => scalaVersionAxis(scalaVersion, s"$m.$n") + case _ => scalaVersionAxis(scalaVersion, scalaVersion) + } + def scalaVersionAxis(scalaVersion: String, value: String) = + ScalaVersionAxis(scalaVersion, value) + + val jvm: PlatformAxis = PlatformAxis("jvm", "JVM", "jvm") + val js: PlatformAxis = PlatformAxis("js", "JS", "js") + val native: PlatformAxis = PlatformAxis("native", "Native", "native") +} diff --git a/src/main/scala/sbt/ProjectMatrix.scala b/src/main/scala/sbt/internal/ProjectMatrix.scala similarity index 53% rename from src/main/scala/sbt/ProjectMatrix.scala rename to src/main/scala/sbt/internal/ProjectMatrix.scala index b3a945d10..51d031869 100644 --- a/src/main/scala/sbt/ProjectMatrix.scala +++ b/src/main/scala/sbt/internal/ProjectMatrix.scala @@ -1,10 +1,12 @@ package sbt +package internal import java.util.Locale import scala.collection.immutable.ListMap +import scala.collection.mutable import Keys._ -import sbt.librarymanagement.CrossVersion.partialVersion import scala.util.Try +import sbt.internal.inc.ReflectUtilities /** * A project matrix is an implementation of a composite project @@ -46,23 +48,54 @@ sealed trait ProjectMatrix extends CompositeProject { def settings(ss: Def.SettingsDefinition*): ProjectMatrix /** - * Sets the [[AutoPlugin]]s of this project. - * A [[AutoPlugin]] is a common label that is used by plugins to determine what settings, if any, to enable on a project. + * Sets the [[sbt.AutoPlugin]]s of this project. + * An [[sbt.AutoPlugin]] is a common label that is used by plugins to determine what settings, if any, to enable on a project. */ def enablePlugins(ns: Plugins*): ProjectMatrix /** Disable the given plugins on this project. */ def disablePlugins(ps: AutoPlugin*): ProjectMatrix - def custom( - idSuffix: String, - directorySuffix: String, - scalaVersions: Seq[String], - process: Project => Project + + /** + * If autoScalaLibrary is false, add non-Scala row. + * Otherwise, add custom rows for each scalaVersions. + */ + def customRow( + autoScalaLibrary: Boolean, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + process: Project => Project + ): ProjectMatrix + + def customRow( + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + process: Project => Project + ): ProjectMatrix + + def customRow( + autoScalaLibrary: Boolean, + axisValues: Seq[VirtualAxis], + process: Project => Project + ): ProjectMatrix + + def customRow( + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Setting[_]] + ): ProjectMatrix + + def customRow( + autoScalaLibrary: Boolean, + axisValues: Seq[VirtualAxis], + settings: Seq[Setting[_]] ): ProjectMatrix def jvmPlatform(scalaVersions: Seq[String]): ProjectMatrix + def jvmPlatform(autoScalaLibrary: Boolean): ProjectMatrix def jvmPlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix + def jvmPlatform(autoScalaLibrary: Boolean, scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix def jvm: ProjectFinder def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix @@ -73,10 +106,14 @@ sealed trait ProjectMatrix extends CompositeProject { def nativePlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix def native: ProjectFinder - def crossLibrary(scalaVersions: Seq[String], suffix: String, settings: Seq[Setting[_]]): ProjectMatrix - def crossLib(suffix: String): ProjectFinder - def projectRefs: Seq[ProjectReference] + + def filterProjects(axisValues: Seq[VirtualAxis]): Seq[Project] + def filterProjects(autoScalaLibrary: Boolean, axisValues: Seq[VirtualAxis]): Seq[Project] + def finder(axisValues: VirtualAxis*): ProjectFinder + + // resolve to the closest match for the given row + private[sbt] def resolveMatch(thatRow: ProjectMatrix.ProjectRow): ProjectReference } /** Represents a reference to a project matrix with an optional configuration string. @@ -87,6 +124,7 @@ sealed trait MatrixClasspathDep[MR <: ProjectMatrixReference] { trait ProjectFinder { def apply(scalaVersion: String): Project + def apply(autoScalaLibrary: Boolean): Project def get: Seq[Project] } @@ -100,14 +138,27 @@ object ProjectMatrix { val nativeIdSuffix: String = "Native" val nativeDirectorySuffix: String = "-native" - /** A row in the project matrix, typically representing a platform. + private[sbt] val allMatrices: mutable.Map[String, ProjectMatrix] = mutable.Map.empty + + /** A row in the project matrix, typically representing a platform + Scala version. */ final class ProjectRow( - val idSuffix: String, - val directorySuffix: String, - val scalaVersions: Seq[String], + val autoScalaLibrary: Boolean, + val axisValues: Seq[VirtualAxis], val process: Project => Project - ) {} + ) { + def scalaVersionOpt: Option[String] = + if (autoScalaLibrary) + (axisValues collect { + case sv: VirtualAxis.ScalaVersionAxis => sv.scalaVersion + }).headOption + else None + + def isMatch(that: ProjectRow): Boolean = + VirtualAxis.isMatch(this.axisValues, that.axisValues) + + override def toString: String = s"ProjectRow($autoScalaLibrary, $axisValues)" + } final case class MatrixClasspathDependency( matrix: ProjectMatrixReference, @@ -125,23 +176,40 @@ object ProjectMatrix { val configurations: Seq[Configuration], val plugins: Plugins ) extends ProjectMatrix { self => - lazy val projectMatrix: ListMap[(ProjectRow, String), Project] = { + lazy val resolvedMappings: ListMap[ProjectRow, Project] = resolveMappings + private def resolveProjectIds: Map[ProjectRow, String] = { + Map((for { + r <- rows + } yield { + val axes = r.axisValues.sortBy(_.suffixOrder) + val idSuffix = axes.map(_.idSuffix).mkString("") + val childId = self.id + idSuffix + r -> childId + }): _*) + } + + private def resolveMappings: ListMap[ProjectRow, Project] = { + val projectIds = resolveProjectIds + ListMap((for { r <- rows - svs = if (r.scalaVersions.nonEmpty) r.scalaVersions - else if (scalaVersions.nonEmpty) scalaVersions - else sys.error(s"project matrix $id must specify scalaVersions.") - sv <- svs } yield { - val idSuffix = r.idSuffix + scalaVersionIdSuffix(sv) - val svDirSuffix = r.directorySuffix + "-" + scalaVersionDirSuffix(sv) - val childId = self.id + idSuffix - val deps = dependencies map { - case MatrixClasspathDependency(matrix: LocalProjectMatrix, configuration) => - ClasspathDependency(LocalProject(matrix.id + idSuffix), configuration) - } + val axes = r.axisValues.sortBy(_.suffixOrder) + val svDirSuffix = axes.map(_.directorySuffix).mkString("-") + val nonScalaDirSuffix = (axes filter { + case _: VirtualAxis.ScalaVersionAxis => false + case _ => true + }).map(_.directorySuffix).mkString("-") + + val platform = (axes collect { + case pa: VirtualAxis.PlatformAxis => pa + }).headOption.getOrElse(sys.error(s"platform axis is missing in $axes")) + val childId = projectIds(r) + val deps = dependencies map { resolveMatrixDependency(_, r) } val aggs = aggregate map { - case ref: LocalProjectMatrix => LocalProject(ref.id + idSuffix) + case ref: LocalProjectMatrix => + val other = lookupMatrix(ref) + resolveMatrixAggregate(other, r) } val p = Project(childId, new sbt.File(childId).getAbsoluteFile) .dependsOn(deps: _*) @@ -149,21 +217,50 @@ object ProjectMatrix { .setPlugins(plugins) .configs(configurations: _*) .settings( - name := self.id, - Keys.scalaVersion := sv, + name := self.id + ) + .settings( + r.scalaVersionOpt.toList map { sv => + Keys.scalaVersion := sv + } + ) + .settings( target := base.getAbsoluteFile / "target" / svDirSuffix.dropWhile(_ == '-'), crossTarget := Keys.target.value, sourceDirectory := base.getAbsoluteFile / "src", - inConfig(Compile)(makeSources(r.directorySuffix, svDirSuffix)), - inConfig(Test)(makeSources(r.directorySuffix, svDirSuffix)) + inConfig(Compile)(makeSources(nonScalaDirSuffix, svDirSuffix)), + inConfig(Test)(makeSources(nonScalaDirSuffix, svDirSuffix)) ) .settings(self.settings) - (r, sv) -> r.process(p) + r -> r.process(p) }): _*) } - override lazy val componentProjects: Seq[Project] = projectMatrix.values.toList + + override lazy val componentProjects: Seq[Project] = resolvedMappings.values.toList + + private def resolveMatrixAggregate( + other: ProjectMatrix, + thisRow: ProjectRow, + ): ProjectReference = other.resolveMatch(thisRow) + + private def resolveMatrixDependency( + dep: MatrixClasspathDep[ProjectMatrixReference], + thisRow: ProjectRow + ): ClasspathDep[ProjectReference] = + dep match { + case MatrixClasspathDependency(matrix0: LocalProjectMatrix, configuration) => + val other = lookupMatrix(matrix0) + ClasspathDependency(other.resolveMatch(thisRow), configuration) + } + + // resolve to the closest match for the given row + private[sbt] def resolveMatch(thatRow: ProjectRow): ProjectReference = + rows.find(r => r.isMatch(thatRow)) match { + case Some(r) => LocalProject(resolveProjectIds(r)) + case _ => sys.error(s"no rows were found in $id matching $thatRow: $rows") + } private def makeSources(dirSuffix: String, svDirSuffix: String): Setting[_] = { unmanagedSourceDirectories ++= Seq( @@ -172,16 +269,6 @@ object ProjectMatrix { ) } - private def scalaVersionIdSuffix(sv: String): String = { - scalaVersionDirSuffix(sv).toLowerCase(Locale.ENGLISH).replaceAll("""\W+""", "_") - } - - private def scalaVersionDirSuffix(sv: String): String = - partialVersion(sv) match { - case Some((m, n)) => s"$m.$n" - case _ => sv - } - override def withId(id: String): ProjectMatrix = copy(id = id) override def in(dir: sbt.File): ProjectMatrix = copy(base = dir) @@ -209,16 +296,20 @@ object ProjectMatrix { override def jvmPlatform(scalaVersions: Seq[String]): ProjectMatrix = jvmPlatform(scalaVersions, Nil) + override def jvmPlatform(autoScalaLibrary: Boolean): ProjectMatrix = + jvmPlatform(autoScalaLibrary, Nil, Nil) override def jvmPlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = - custom(jvmIdSuffix, jvmDirectorySuffix, scalaVersions, { _.settings(settings) }) + jvmPlatform(true, scalaVersions, settings) + override def jvmPlatform(autoScalaLibrary: Boolean, scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = + customRow(autoScalaLibrary, scalaVersions, Seq(VirtualAxis.jvm), { _.settings(settings) }) - override def jvm: ProjectFinder = new SuffixBaseProjectFinder(jvmIdSuffix) + override def jvm: ProjectFinder = new AxisBaseProjectFinder(Seq(VirtualAxis.jvm)) override def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix = jsPlatform(scalaVersions, Nil) override def jsPlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = - custom(jsIdSuffix, jsDirectorySuffix, scalaVersions, + customRow(true, scalaVersions, Seq(VirtualAxis.js), { _ .enablePlugins(scalajsPlugin(this.getClass.getClassLoader).getOrElse( sys.error("""Scala.js plugin was not found. Add the sbt-scalajs plugin into project/plugins.sbt: @@ -235,17 +326,19 @@ object ProjectMatrix { } } - override def native: ProjectFinder = new SuffixBaseProjectFinder(nativeIdSuffix) + override def js: ProjectFinder = new AxisBaseProjectFinder(Seq(VirtualAxis.js)) + + override def native: ProjectFinder = new AxisBaseProjectFinder(Seq(VirtualAxis.native)) override def nativePlatform(scalaVersions: Seq[String]): ProjectMatrix = nativePlatform(scalaVersions, Nil) override def nativePlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = - custom(nativeIdSuffix, nativeDirectorySuffix, scalaVersions, + customRow(true, scalaVersions, Seq(VirtualAxis.native), { _ .enablePlugins(nativePlugin(this.getClass.getClassLoader).getOrElse( sys.error("""Scala Native plugin was not found. Add the sbt-scala-native plugin into project/plugins.sbt: - | addSbtPlugin("org.scala-native" % "sbt-scala-natiev" % "x.y.z") + | addSbtPlugin("org.scala-native" % "sbt-scala-native" % "x.y.z") |""".stripMargin) )) .settings(settings) @@ -258,39 +351,71 @@ object ProjectMatrix { } } - override def js: ProjectFinder = new SuffixBaseProjectFinder(jsIdSuffix) - - override def crossLibrary(scalaVersions: Seq[String], suffix: String, settings: Seq[Setting[_]]): ProjectMatrix = - custom(suffix.replaceAllLiterally(".", "_"), - "-" + suffix.toLowerCase, - scalaVersions, - { _.settings( - Seq(moduleName := name.value + "_" + suffix.toLowerCase) ++ settings - ) }) - - override def crossLib(suffix: String): ProjectFinder = - new SuffixBaseProjectFinder(suffix.replaceAllLiterally(".", "_")) - override def projectRefs: Seq[ProjectReference] = componentProjects map { case p => (p: ProjectReference) } - private final class SuffixBaseProjectFinder(idSuffix: String) extends ProjectFinder { - def get: Seq[Project] = projectMatrix.toSeq collect { - case ((r, sv), v) if r.idSuffix == idSuffix => v + override def filterProjects(axisValues: Seq[VirtualAxis]): Seq[Project] = + resolvedMappings.toSeq collect { + case (r, p) if axisValues.forall(v => r.axisValues.contains(v)) => p } + override def filterProjects(autoScalaLibrary: Boolean, axisValues: Seq[VirtualAxis]): Seq[Project] = + resolvedMappings.toSeq collect { + case (r, p) if r.autoScalaLibrary == autoScalaLibrary && axisValues.forall(v => r.axisValues.contains(v)) => p + } + + private final class AxisBaseProjectFinder(axisValues: Seq[VirtualAxis]) extends ProjectFinder { + def get: Seq[Project] = filterProjects(axisValues) def apply(sv: String): Project = - (projectMatrix.toSeq collectFirst { - case ((r, `sv`), v) if r.idSuffix == idSuffix => v - }).getOrElse(sys.error(s"$sv was not found")) + filterProjects(true, axisValues ++ Seq(VirtualAxis.scalaPartialVersion(sv))).headOption + .getOrElse(sys.error(s"project matching $axisValues and $sv was not found")) + def apply(autoScalaLibrary: Boolean): Project = + filterProjects(autoScalaLibrary, axisValues).headOption + .getOrElse(sys.error(s"project matching $axisValues and $autoScalaLibrary was not found")) } - override def custom( - idSuffix: String, - directorySuffix: String, - scalaVersions: Seq[String], - process: Project => Project + override def customRow( + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Setting[_]] + ): ProjectMatrix = customRow(true, scalaVersions, axisValues, { _.settings(settings) }) + + override def customRow( + autoScalaLibrary: Boolean, + axisValues: Seq[VirtualAxis], + settings: Seq[Setting[_]] + ): ProjectMatrix = customRow(autoScalaLibrary, Nil, axisValues, { _.settings(settings) }) + + override def customRow( + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + process: Project => Project + ): ProjectMatrix = customRow(true, scalaVersions, axisValues, process) + + override def customRow( + autoScalaLibrary: Boolean, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + process: Project => Project ): ProjectMatrix = - copy(rows = rows :+ new ProjectRow(idSuffix, directorySuffix, scalaVersions, process)) + if (autoScalaLibrary) { + scalaVersions.foldLeft(this: ProjectMatrix) { (acc, sv) => + acc.customRow(autoScalaLibrary, axisValues ++ Seq(VirtualAxis.scalaPartialVersion(sv)), process) + } + } else { + customRow(autoScalaLibrary, Seq(VirtualAxis.jvm), process) + } + + override def customRow( + autoScalaLibrary: Boolean, + axisValues: Seq[VirtualAxis], + process: Project => Project + ): ProjectMatrix = { + val newRow: ProjectRow = new ProjectRow(autoScalaLibrary, axisValues, process) + copy(rows = this.rows :+ newRow) + } + + override def finder(axisValues: VirtualAxis*): ProjectFinder = + new AxisBaseProjectFinder(axisValues.toSeq) def copy( id: String = id, @@ -302,8 +427,8 @@ object ProjectMatrix { settings: Seq[Setting[_]] = settings, configurations: Seq[Configuration] = configurations, plugins: Plugins = plugins - ): ProjectMatrix = - unresolved( + ): ProjectMatrix = { + val matrix = unresolved( id, base, scalaVersions, @@ -314,10 +439,16 @@ object ProjectMatrix { configurations, plugins ) + allMatrices(id) = matrix + matrix + } } + // called by macro def apply(id: String, base: sbt.File): ProjectMatrix = { - unresolved(id, base, Nil, Nil, Nil, Nil, Nil, Nil, Plugins.Empty) + val matrix = unresolved(id, base, Nil, Nil, Nil, Nil, Nil, Nil, Plugins.Empty) + allMatrices(id) = matrix + matrix } private[sbt] def unresolved( @@ -343,6 +474,10 @@ object ProjectMatrix { plugins ) + def lookupMatrix(local: LocalProjectMatrix): ProjectMatrix = { + allMatrices.getOrElse(local.id, sys.error(s"${local.id} was not found")) + } + implicit def projectMatrixToLocalProjectMatrix(m: ProjectMatrix): LocalProjectMatrix = LocalProjectMatrix(m.id) diff --git a/src/main/scala/sbt/ProjectMatrixReference.scala b/src/main/scala/sbt/internal/ProjectMatrixReference.scala similarity index 92% rename from src/main/scala/sbt/ProjectMatrixReference.scala rename to src/main/scala/sbt/internal/ProjectMatrixReference.scala index 2f7d4b8c2..5ed710cda 100644 --- a/src/main/scala/sbt/ProjectMatrixReference.scala +++ b/src/main/scala/sbt/internal/ProjectMatrixReference.scala @@ -1,4 +1,5 @@ package sbt +package internal /** Identifies a project matrix. */ sealed trait ProjectMatrixReference diff --git a/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala b/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala index 0fceae49d..88fc607a7 100644 --- a/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala +++ b/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala @@ -1,6 +1,7 @@ package sbtprojectmatrix import sbt._ +import internal._ import java.util.concurrent.atomic.AtomicBoolean import scala.language.experimental.macros diff --git a/src/sbt-test/projectMatrix/crosslib/build.sbt b/src/sbt-test/projectMatrix/crosslib/build.sbt deleted file mode 100644 index 0d7010f3e..000000000 --- a/src/sbt-test/projectMatrix/crosslib/build.sbt +++ /dev/null @@ -1,35 +0,0 @@ -ThisBuild / organization := "com.example" -ThisBuild / version := "0.1.0-SNAPSHOT" -ThisBuild / publishMavenStyle := true - -ThisBuild / ivyPaths := { - val base = (ThisBuild / baseDirectory).value - IvyPaths(base, Some(base / "ivy-cache")) -} -publish / skip := true - -lazy val core = (projectMatrix in file("core")) - .settings( - name := "core", - ivyPaths := (ThisBuild / ivyPaths).value - ) - .crossLibrary( - scalaVersions = Seq("2.12.8", "2.11.12"), - suffix = "Config1.2", - settings = Seq( - libraryDependencies += "com.typesafe" % "config" % "1.2.1" - ) - ) - .crossLibrary( - scalaVersions = Seq("2.12.8"), - suffix = "Config1.3", - settings = Seq( - libraryDependencies += "com.typesafe" % "config" % "1.3.3" - ) - ) - -// to reference project ref -lazy val coreConfig1_3 = core.crossLib("Config1.3")("2.12.8") - .settings( - publishMavenStyle := true - ) diff --git a/src/sbt-test/projectMatrix/crosslib/project/plugins.sbt b/src/sbt-test/projectMatrix/crosslib/project/plugins.sbt deleted file mode 100644 index 4e80bbafc..000000000 --- a/src/sbt-test/projectMatrix/crosslib/project/plugins.sbt +++ /dev/null @@ -1,5 +0,0 @@ -sys.props.get("plugin.version") match { - case Some(x) => addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % x) - case _ => sys.error("""|The system property 'plugin.version' is not defined. - |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) -} diff --git a/src/sbt-test/projectMatrix/crosslib/test b/src/sbt-test/projectMatrix/crosslib/test deleted file mode 100644 index 909bf9e3a..000000000 --- a/src/sbt-test/projectMatrix/crosslib/test +++ /dev/null @@ -1,5 +0,0 @@ -> publishLocal - -$ exists ivy-cache/local/com.example/core_config1.2_2.11/0.1.0-SNAPSHOT/poms/core_config1.2_2.11.pom -$ exists ivy-cache/local/com.example/core_config1.2_2.12/0.1.0-SNAPSHOT/poms/core_config1.2_2.12.pom -$ exists ivy-cache/local/com.example/core_config1.3_2.12/0.1.0-SNAPSHOT/poms/core_config1.3_2.12.pom diff --git a/src/sbt-test/projectMatrix/custom/app/src/main/scala/B.scala b/src/sbt-test/projectMatrix/custom/app/src/main/scala/B.scala new file mode 100644 index 000000000..0af0d7579 --- /dev/null +++ b/src/sbt-test/projectMatrix/custom/app/src/main/scala/B.scala @@ -0,0 +1,5 @@ +package example + +object B { + def b: Int = A.a +} diff --git a/src/sbt-test/projectMatrix/custom/build.sbt b/src/sbt-test/projectMatrix/custom/build.sbt index c90b71841..10b14e863 100644 --- a/src/sbt-test/projectMatrix/custom/build.sbt +++ b/src/sbt-test/projectMatrix/custom/build.sbt @@ -8,26 +8,39 @@ ThisBuild / ivyPaths := { } publish / skip := true +lazy val config12 = ConfigAxis("Config1_2", "config1.2") +lazy val config13 = ConfigAxis("Config1_3", "config1.3") + +lazy val scala212 = "2.12.10" +lazy val scala211 = "2.11.12" + lazy val core = (projectMatrix in file("core")) + .jvmPlatform(scalaVersions = Seq(scala212, scala211)) + +lazy val app = (projectMatrix in file("app")) + .dependsOn(core) .settings( - name := "core", + name := "app", ivyPaths := (ThisBuild / ivyPaths).value ) - .custom( - idSuffix = "Config1_2", - directorySuffix = "-config1.2", - scalaVersions = Seq("2.12.8", "2.11.12"), + .customRow( + scalaVersions = Seq(scala212, scala211), + axisValues = Seq(config12, VirtualAxis.jvm), _.settings( moduleName := name.value + "_config1.2", libraryDependencies += "com.typesafe" % "config" % "1.2.1" ) ) - .custom( - idSuffix = "Config1_3", - directorySuffix = "-config1.3", - scalaVersions = Seq("2.12.8", "2.11.12"), + .customRow( + scalaVersions = Seq(scala212, scala211), + axisValues = Seq(config13, VirtualAxis.jvm), _.settings( moduleName := name.value + "_config1.3", libraryDependencies += "com.typesafe" % "config" % "1.3.3" ) ) + +lazy val appConfig12_212 = app.finder(config13, VirtualAxis.jvm)(scala212) + .settings( + publishMavenStyle := true + ) diff --git a/src/sbt-test/projectMatrix/custom/core/src/main/scala/A.scala b/src/sbt-test/projectMatrix/custom/core/src/main/scala/A.scala new file mode 100644 index 000000000..e62671081 --- /dev/null +++ b/src/sbt-test/projectMatrix/custom/core/src/main/scala/A.scala @@ -0,0 +1,5 @@ +package example + +object A { + def a: Int = 1 +} diff --git a/src/sbt-test/projectMatrix/custom/project/ConfigAxis.scala b/src/sbt-test/projectMatrix/custom/project/ConfigAxis.scala new file mode 100644 index 000000000..b1124c60e --- /dev/null +++ b/src/sbt-test/projectMatrix/custom/project/ConfigAxis.scala @@ -0,0 +1,5 @@ +import sbt._ + +case class ConfigAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis { + +} diff --git a/src/sbt-test/projectMatrix/custom/test b/src/sbt-test/projectMatrix/custom/test index e1b9b9ed6..c92f20c49 100644 --- a/src/sbt-test/projectMatrix/custom/test +++ b/src/sbt-test/projectMatrix/custom/test @@ -1,6 +1,6 @@ > publishLocal -$ exists ivy-cache/local/com.example/core_config1.2_2.11/0.1.0-SNAPSHOT/poms/core_config1.2_2.11.pom -$ exists ivy-cache/local/com.example/core_config1.2_2.12/0.1.0-SNAPSHOT/poms/core_config1.2_2.12.pom -$ exists ivy-cache/local/com.example/core_config1.3_2.11/0.1.0-SNAPSHOT/poms/core_config1.3_2.11.pom -$ exists ivy-cache/local/com.example/core_config1.3_2.12/0.1.0-SNAPSHOT/poms/core_config1.3_2.12.pom +$ exists ivy-cache/local/com.example/app_config1.2_2.11/0.1.0-SNAPSHOT/poms/app_config1.2_2.11.pom +$ exists ivy-cache/local/com.example/app_config1.2_2.12/0.1.0-SNAPSHOT/poms/app_config1.2_2.12.pom +$ exists ivy-cache/local/com.example/app_config1.3_2.11/0.1.0-SNAPSHOT/poms/app_config1.3_2.11.pom +$ exists ivy-cache/local/com.example/app_config1.3_2.12/0.1.0-SNAPSHOT/poms/app_config1.3_2.12.pom diff --git a/src/sbt-test/projectMatrix/jvm/build.sbt b/src/sbt-test/projectMatrix/jvm/build.sbt index f5e6ae67e..e73f056f6 100644 --- a/src/sbt-test/projectMatrix/jvm/build.sbt +++ b/src/sbt-test/projectMatrix/jvm/build.sbt @@ -1,9 +1,17 @@ lazy val check = taskKey[Unit]("") -// lazy val root = (project in file(".")) -// .aggregate(core.projectRefs ++ app.projectRefs: _*) -// .settings( -// ) +lazy val root = (project in file(".")) + .aggregate(core.projectRefs ++ app.projectRefs: _*) + .settings( + ) + +lazy val app = (projectMatrix in file("app")) + .aggregate(core, intf) + .dependsOn(core, intf) + .settings( + name := "app" + ) + .jvmPlatform(scalaVersions = Seq("2.12.8")) lazy val core = (projectMatrix in file("core")) .settings( @@ -13,9 +21,12 @@ lazy val core = (projectMatrix in file("core")) ) .jvmPlatform(scalaVersions = Seq("2.12.8", "2.11.12")) -lazy val app = (projectMatrix in file("app")) - .dependsOn(core) +lazy val intf = (projectMatrix in file("intf")) .settings( - name := "app" + check := { + assert(moduleName.value == "intf", s"moduleName is ${moduleName.value}") + }, ) - .jvmPlatform(scalaVersions = Seq("2.12.8")) + .jvmPlatform(autoScalaLibrary = false) + +lazy val core212 = core.jvm("2.12.8")