diff --git a/.github/decodekey.sh b/.github/decodekey.sh new file mode 100755 index 000000000..ac7c2c58f --- /dev/null +++ b/.github/decodekey.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# echo $PGP_SECRET | base64 --decode | gpg --import --batch --yes --pinentry-mode loopback --passphrase $PGP_PASSPHRASE +echo $PGP_SECRET | base64 --decode | gpg --batch --import diff --git a/.github/workflows/release.txt b/.github/workflows/release.txt new file mode 100644 index 000000000..30bad8521 --- /dev/null +++ b/.github/workflows/release.txt @@ -0,0 +1,32 @@ +name: Release +on: + push: + tags: ["*"] + +jobs: + build: + runs-on: ubuntu-latest + env: + # define Java options for both official sbt and sbt-extras + JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8 + JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup JDK + uses: actions/setup-java@v3 + with: + distribution: "temurin" + java-version: 8 + cache: sbt + - name: Release + env: + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + PGP_SECRET: ${{ secrets.PGP_SECRET }} + CI_CLEAN: clean + CI_RELEASE: publishSigned + CI_SONATYPE_RELEASE: version + run: | + sbt ci-release diff --git a/README.markdown b/README.markdown new file mode 100644 index 000000000..7fefdbc00 --- /dev/null +++ b/README.markdown @@ -0,0 +1,199 @@ +sbt-projectmatrix +================= + +cross building using subprojects. + +This is an experimental plugin that implements better cross building. + +setup +----- + +**Requirements**: Requires sbt 1.2.0 or above. + +In `project/plugins.sbt`: + +```scala +addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.10.0") + +// add also the following for Scala.js support +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.10.1") +``` + +usage +----- + +### building against multiple Scala versions + +After adding sbt-projectmatrix to your build, here's how you can set up a matrix with two Scala versions. + +```scala +ThisBuild / organization := "com.example" +ThisBuild / scalaVersion := "2.13.3" +ThisBuild / version := "0.1.0-SNAPSHOT" + +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core" + ) + .jvmPlatform(scalaVersions = Seq("2.13.3", "2.12.12")) +``` + +This will create subprojects `core` and `core2_12`. +Unlike `++` style stateful cross building, these will build in parallel. + +### two matrices + +It gets more interesting if you have more than one matrix. + +```scala +ThisBuild / organization := "com.example" +ThisBuild / scalaVersion := "2.13.3" +ThisBuild / version := "0.1.0-SNAPSHOT" + +// uncomment if you want root +// lazy val root = (project in file(".")) +// .aggregate(core.projectRefs ++ app.projectRefs: _*) +// .settings( +// ) + +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core" + ) + .jvmPlatform(scalaVersions = Seq("2.13.3", "2.12.12")) + +lazy val app = (projectMatrix in file("app")) + .dependsOn(core) + .settings( + name := "app" + ) + .jvmPlatform(scalaVersions = Seq("2.13.3")) +``` + +This is an example where `core` builds against Scala 2.12 and 2.13, but app only builds for one of them. + +### Scala.js support + +[Scala.js](http://scala-js.org/) support was added in sbt-projectmatrix 0.2.0. +To use this, you need to setup sbt-scalajs as well: + +```scala +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core" + ) + .jsPlatform(scalaVersions = Seq("2.12.12", "2.11.12")) +``` + +This will create subprojects `coreJS2_11` and `coreJS2_12`. + +### Scala Native support + +[Scala Native](http://scala-native.org) support will be added in upcoming release. +To use this, you need to setup sbt-scala-native` as well: + +```scala +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core" + ) + .nativePlatform(scalaVersions = Seq("2.11.12")) +``` + +This will create subproject `coreNative2_11`. + +### parallel cross-library building + +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 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 := "app" + ) + .customRow( + scalaVersions = Seq(scala212, scala211), + axisValues = Seq(config12, VirtualAxis.jvm), + _.settings( + moduleName := name.value + "_config1.2", + libraryDependencies += "com.typesafe" % "config" % "1.2.1" + ) + ) + .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 `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. + +### referencing the generated subprojects + +You might want to reference to one of the projects within `build.sbt`. + +```scala +lazy val core12 = core.jvm("2.12.8") + +lazy val appConfig12_212 = app.finder(config13, VirtualAxis.jvm)("2.12.8") +``` + +In the above `core12` returns `Project` type. + +### accessing axes from subprojects + +Each generated subproject can access the values for all the axes using `virtualAxes` key: + +```scala +lazy val platformTest = settingKey[String]("") + +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core" + ) + .jsPlatform(scalaVersions = Seq("2.12.12", "2.11.12")) + .jvmPlatform(scalaVersion = Seq("2.12.12", "2.13.3")) + .settings( + platformTest := { + if(virtualAxes.value.contains(VirtualAxis.jvm)) + "JVM project" + else + "JS project" + } + ) +``` + +credits +------- + +- The idea of representing cross build using subproject was pionieered by Tobias Schlatter's work on Scala.js plugin, which was later expanded to [ sbt-crossproject](https://github.com/portable-scala/sbt-crossproject). However, this only addresses the platform (JVM, JS, Native) cross building. +- [sbt-cross](https://github.com/lucidsoftware/sbt-cross) written by Paul Draper in 2015 implements cross building across Scala versions. + +license +------- + +MIT License diff --git a/src/main/scala/sbt/VirtualAxis.scala b/src/main/scala/sbt/VirtualAxis.scala new file mode 100644 index 000000000..e601a14d2 --- /dev/null +++ b/src/main/scala/sbt/VirtualAxis.scala @@ -0,0 +1,118 @@ +package sbt + +import sbt.librarymanagement.CrossVersion.{ binaryScalaVersion, 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 = + lhs.forall(isStronglyCompatible(_, rhs)) && rhs.forall(isStronglyCompatible(_, lhs)) + + private[sbt] def isStronglyCompatible(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) + } + + def isSecondaryMatch(lhs: Seq[VirtualAxis], rhs: Seq[VirtualAxis]): Boolean = + lhs.forall(isSecondaryCompatible(_, rhs)) && rhs.forall(isSecondaryCompatible(_, lhs)) + + def isSecondaryCompatible(v: VirtualAxis, stack: Seq[VirtualAxis]): Boolean = + v match { + case v: ScalaVersionAxis => + val thatSVOpt = (stack collect { + case x: ScalaVersionAxis => x + }).headOption + thatSVOpt match { + case Some(ScalaVersionAxis(sv, _)) => + (v.scalaVersion == sv) || + isScala2Scala3Sandwich(partialVersion(v.scalaVersion), partialVersion(sv)) + case _ => true + } + case _ => + isStronglyCompatible(v, stack) + } + + private[sbt] def isScala2Scala3Sandwich(sbv1: Option[(Long, Long)], sbv2: Option[(Long, Long)]): Boolean = { + def str(x: Option[(Long, Long)]): String = + x match { + case Some((a, b)) => s"$a.$b" + case _ => "0.0" + } + isScala2Scala3Sandwich(str(sbv1), str(sbv2)) + } + + private[sbt] def isScala2Scala3Sandwich(sbv1: String, sbv2: String): Boolean = { + def compare(a: String, b: String): Boolean = + a == "2.13" && (b.startsWith("0.") || b.startsWith("3.")) + compare(sbv1, sbv2) || compare(sbv2, sbv1) + } + + // This admits partial Scala version + private[sbt] def isPartialVersionEquals(ax1: VirtualAxis, ax2: VirtualAxis): Boolean = { + (ax1, ax2) match { + case (ax1: ScalaVersionAxis, ax2: ScalaVersionAxis) => + (ax1 == ax2) || (ax1.value == ax2.value) + case _ => ax1 == ax2 + } + } + + 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 scalaABIVersion(scalaVersion: String): ScalaVersionAxis = + scalaVersionAxis(scalaVersion, binaryScalaVersion(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/internal/ProjectMatrix.scala b/src/main/scala/sbt/internal/ProjectMatrix.scala new file mode 100644 index 000000000..1e426bfdd --- /dev/null +++ b/src/main/scala/sbt/internal/ProjectMatrix.scala @@ -0,0 +1,633 @@ +package sbt +package internal + +import java.util.Locale +import scala.collection.immutable.ListMap +import scala.collection.mutable +import Keys._ +import scala.util.Try +import sbt.internal.inc.ReflectUtilities + +import sbtprojectmatrix.ProjectMatrixKeys + +/** + * A project matrix is an implementation of a composite project + * that represents cross building across some axis (such as platform) + * and Scala version. + * + * {{{ + * lazy val core = (projectMatrix in file("core")) + * .settings( + * name := "core" + * ) + * .jvmPlatform(Seq("2.12.6", "2.11.12")) + * }}} + */ +sealed trait ProjectMatrix extends CompositeProject { + def id: String + + /** The base directory for the project matrix.*/ + def base: sbt.File + + def withId(id: String): ProjectMatrix + + /** Sets the base directory for this project matrix.*/ + def in(dir: sbt.File): ProjectMatrix + + /** Adds new configurations directly to this project. To override an existing configuration, use `overrideConfigs`. */ + def configs(cs: Configuration*): ProjectMatrix + + /** Adds classpath dependencies on internal or external projects. */ + def dependsOn(deps: MatrixClasspathDep[ProjectMatrixReference]*): ProjectMatrix + + /** Adds classpath dependencies on internal or external non-matrix projects. */ + def dependsOn(deps: ClasspathDep[ProjectReference]*)(implicit dummyImplicit: DummyImplicit): ProjectMatrix + + /** + * Adds projects to be aggregated. When a user requests a task to run on this project from the command line, + * the task will also be run in aggregated projects. + */ + def aggregate(refs: ProjectMatrixReference*): ProjectMatrix + + /** + * Allows non-matrix projects to be aggregated in a matrix project. + */ + def aggregate(refs: ProjectReference*)(implicit dummyImplicit: DummyImplicit): ProjectMatrix + + /** Appends settings to the current settings sequence for this project. */ + def settings(ss: Def.SettingsDefinition*): ProjectMatrix + + /** + * 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 + + /** + * Applies the given functions to this Project. + * The second function is applied to the result of applying the first to this Project and so on. + * The intended use is a convenience for applying default configuration provided by a plugin. + */ + def configure(transforms: (Project => Project)*): ProjectMatrix + + /** + * 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(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Setting[_]]): ProjectMatrix + def jvmPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project): ProjectMatrix + def jvmPlatform(autoScalaLibrary: Boolean, scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix + def jvm: ProjectFinder + + def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix + def jsPlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix + def jsPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Setting[_]]): ProjectMatrix + def jsPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project): ProjectMatrix + def js: ProjectFinder + + def nativePlatform(scalaVersions: Seq[String]): ProjectMatrix + def nativePlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix + def nativePlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Setting[_]]): ProjectMatrix + def nativePlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project): ProjectMatrix + def native: ProjectFinder + + def defaultAxes(axes: VirtualAxis*): ProjectMatrix + + 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 + def allProjects(): Seq[(Project, Seq[VirtualAxis])] + + // 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. + */ +sealed trait MatrixClasspathDep[MR <: ProjectMatrixReference] { + def matrix: MR; def configuration: Option[String] +} + +trait ProjectFinder { + def apply(scalaVersion: String): Project + def apply(autoScalaLibrary: Boolean): Project + def get: Seq[Project] +} + +object ProjectMatrix { + import sbt.io.syntax._ + + val jvmIdSuffix: String = "JVM" + val jvmDirectorySuffix: String = "-jvm" + val jsIdSuffix: String = "JS" + val jsDirectorySuffix: String = "-js" + val nativeIdSuffix: String = "Native" + val nativeDirectorySuffix: String = "-native" + + 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 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) + + def isSecondaryMatch(that: ProjectRow): Boolean = + VirtualAxis.isSecondaryMatch(this.axisValues, that.axisValues) + + override def toString: String = s"ProjectRow($autoScalaLibrary, $axisValues)" + } + + final class ProjectMatrixReferenceSyntax(m: ProjectMatrixReference) { + def %(conf: String): ProjectMatrix.MatrixClasspathDependency = + ProjectMatrix.MatrixClasspathDependency(m, Some(conf)) + + def %(conf: Configuration): ProjectMatrix.MatrixClasspathDependency = + ProjectMatrix.MatrixClasspathDependency(m, Some(conf.name)) + } + + final case class MatrixClasspathDependency( + matrix: ProjectMatrixReference, + configuration: Option[String] + ) extends MatrixClasspathDep[ProjectMatrixReference] + + private final class ProjectMatrixDef( + val id: String, + val base: sbt.File, + val scalaVersions: Seq[String], + val rows: Seq[ProjectRow], + val aggregate: Seq[ProjectMatrixReference], + val nonMatrixAggregate: Seq[ProjectReference], + val dependencies: Seq[MatrixClasspathDep[ProjectMatrixReference]], + val nonMatrixDependencies: Seq[ClasspathDep[ProjectReference]], + val settings: Seq[Def.Setting[_]], + val configurations: Seq[Configuration], + val plugins: Plugins, + val transforms: Seq[Project => Project], + val defAxes: Seq[VirtualAxis], + ) extends ProjectMatrix { self => + lazy val resolvedMappings: ListMap[ProjectRow, Project] = resolveMappings + private def resolveProjectIds: Map[ProjectRow, String] = { + Map((for { + r <- rows + } yield { + val axes = r.axisValues.sortBy(_.suffixOrder) + .filterNot(isSortOfDefaultAxis) + val idSuffix = axes.map(_.idSuffix).mkString("") + val childId = self.id + idSuffix + r -> childId + }): _*) + } + + private def isSortOfDefaultAxis(a: VirtualAxis): Boolean = + defAxes exists { da => VirtualAxis.isPartialVersionEquals(da, a) } + + private def resolveMappings: ListMap[ProjectRow, Project] = { + val projectIds = resolveProjectIds + + ListMap((for { + r <- rows + } yield { + 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) } ++ nonMatrixDependencies + val aggs = aggregate.map { + case ref: LocalProjectMatrix => + val other = lookupMatrix(ref) + resolveMatrixAggregate(other, r) + } ++ nonMatrixAggregate + val dotSbtMatrix = new java.io.File(".sbt") / "matrix" + IO.createDirectory(dotSbtMatrix) + val p = Project(childId, dotSbtMatrix / childId) + .dependsOn(deps: _*) + .aggregate(aggs: _*) + .setPlugins(plugins) + .configs(configurations: _*) + .settings( + name := self.id + ) + .settings( + r.scalaVersionOpt match { + case Some(sv) => + List(Keys.scalaVersion := sv) + case _ => + List(Keys.autoScalaLibrary := false, Keys.crossPaths := false) + } + ) + .settings( + target := base.getAbsoluteFile / "target" / svDirSuffix.dropWhile(_ == '-'), + crossTarget := Keys.target.value, + sourceDirectory := base.getAbsoluteFile / "src", + unmanagedBase := base.getAbsoluteFile / "lib", + inConfig(Compile)(makeSources(nonScalaDirSuffix, svDirSuffix)), + inConfig(Test)(makeSources(nonScalaDirSuffix, svDirSuffix)), + projectDependencies := projectDependenciesTask.value, + ProjectMatrixKeys.virtualAxes := axes, + ProjectMatrixKeys.projectMatrixBaseDirectory := base, + ) + .settings(self.settings) + .configure(transforms: _*) + + r -> r.process(p) + }): _*) + } + + // backport of https://github.com/sbt/sbt/pull/5767 + def projectDependenciesTask: Def.Initialize[Task[Seq[ModuleID]]] = + Def.task { + val orig = projectDependencies.value + val sbv = scalaBinaryVersion.value + val ref = thisProjectRef.value + val data = settingsData.value + val deps = buildDependencies.value + deps.classpath(ref) flatMap { dep => + for { + depProjId <- (dep.project / projectID).get(data) + depSBV <- (dep.project / scalaBinaryVersion).get(data) + depCross <- (dep.project / crossVersion).get(data) + } yield { + depCross match { + case b: CrossVersion.Binary if VirtualAxis.isScala2Scala3Sandwich(sbv, depSBV) => + depProjId + .withCrossVersion(CrossVersion.constant(depSBV)) + .withConfigurations(dep.configuration) + .withExplicitArtifacts(Vector.empty) + case _ => + depProjId.withConfigurations(dep.configuration).withExplicitArtifacts(Vector.empty) + } + } + } + } + + 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)) orElse + rows.find(r => r.isSecondaryMatch(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( + scalaSource.value.getParentFile / s"scala${dirSuffix}", + scalaSource.value.getParentFile / s"scala$svDirSuffix", + javaSource.value.getParentFile / s"java${dirSuffix}" + ) + } + + override def withId(id: String): ProjectMatrix = copy(id = id) + + override def in(dir: sbt.File): ProjectMatrix = copy(base = dir) + + override def configs(cs: Configuration*): ProjectMatrix = + copy(configurations = configurations ++ cs) + + override def aggregate(refs: ProjectMatrixReference*): ProjectMatrix = + copy(aggregate = (aggregate: Seq[ProjectMatrixReference]) ++ refs) + + override def aggregate(refs: ProjectReference*)(implicit dummyImplicit: DummyImplicit): ProjectMatrix = + copy(nonMatrixAggregate = (nonMatrixAggregate: Seq[ProjectReference]) ++ refs) + + override def dependsOn(deps: MatrixClasspathDep[ProjectMatrixReference]*): ProjectMatrix = + copy(dependencies = dependencies ++ deps) + + override def dependsOn(deps: ClasspathDep[ProjectReference]*)(implicit dummyImplicit: DummyImplicit) = + copy(nonMatrixDependencies = nonMatrixDependencies ++ deps) + + /** Appends settings to the current settings sequence for this project. */ + override def settings(ss: Def.SettingsDefinition*): ProjectMatrix = + copy(settings = (settings: Seq[Def.Setting[_]]) ++ Def.settings(ss: _*)) + + override def enablePlugins(ns: Plugins*): ProjectMatrix = + setPlugins(ns.foldLeft(plugins)(Plugins.and)) + + override def disablePlugins(ps: AutoPlugin*): ProjectMatrix = + setPlugins(Plugins.and(plugins, Plugins.And(ps.map(p => Plugins.Exclude(p)).toList))) + + override def configure(ts: (Project => Project)*): ProjectMatrix = + copy(transforms = transforms ++ ts) + + def setPlugins(ns: Plugins): ProjectMatrix = copy(plugins = ns) + + 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 = + 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 jvmPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Setting[_]]): ProjectMatrix = + customRow(true, scalaVersions, VirtualAxis.jvm +: axisValues, {_.settings(settings)}) + + override def jvmPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project): ProjectMatrix = + customRow(true, scalaVersions, VirtualAxis.jvm +: axisValues, configure) + + override def jvm: ProjectFinder = new AxisBaseProjectFinder(Seq(VirtualAxis.jvm)) + + override def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix = + jsPlatform(scalaVersions, Nil) + + private def enableScalaJSPlugin(project: Project): Project = + project.enablePlugins(scalajsPlugin(this.getClass.getClassLoader).getOrElse( + sys.error("""Scala.js plugin was not found. Add the sbt-scalajs plugin into project/plugins.sbt: + | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "x.y.z") + |""".stripMargin) + )) + + + override def jsPlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = + customRow(true, scalaVersions, Seq(VirtualAxis.js), + project => enableScalaJSPlugin(project).settings(settings)) + + override def jsPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Setting[_]]): ProjectMatrix = + customRow(true, scalaVersions, VirtualAxis.js +: axisValues, + project => enableScalaJSPlugin(project).settings(settings)) + + override def jsPlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project): ProjectMatrix = + customRow(true, scalaVersions, VirtualAxis.js +: axisValues, + project => configure(enableScalaJSPlugin(project))) + + override def defaultAxes(axes: VirtualAxis*): ProjectMatrix = + copy(defAxes = axes.toSeq) + + def scalajsPlugin(classLoader: ClassLoader): Try[AutoPlugin] = { + import sbtprojectmatrix.ReflectionUtil._ + withContextClassloader(classLoader) { loader => + getSingletonObject[AutoPlugin](loader, "org.scalajs.sbtplugin.ScalaJSPlugin$") + } + } + + 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) + + private def enableScalaNativePlugin(project: Project): Project = + project.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-native" % "x.y.z") + |""".stripMargin) + )) + + + override def nativePlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = + customRow(true, scalaVersions, Seq(VirtualAxis.native), project => enableScalaNativePlugin(project).settings(settings)) + + override def nativePlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Setting[_]]): ProjectMatrix = + customRow(true, scalaVersions, VirtualAxis.native +: axisValues, project => enableScalaNativePlugin(project).settings(settings)) + + override def nativePlatform(scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project): ProjectMatrix = + customRow(true, scalaVersions, VirtualAxis.native +: axisValues, project => configure(enableScalaNativePlugin(project))) + + def nativePlugin(classLoader: ClassLoader): Try[AutoPlugin] = { + import sbtprojectmatrix.ReflectionUtil._ + withContextClassloader(classLoader) { loader => + getSingletonObject[AutoPlugin](loader, "scala.scalanative.sbtplugin.ScalaNativePlugin$") + } + } + + override def projectRefs: Seq[ProjectReference] = + componentProjects map { case p => (p: ProjectReference) } + + 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 = + filterProjects(true, axisValues ++ Seq(VirtualAxis.scalaABIVersion(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 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 = + if (autoScalaLibrary) { + scalaVersions.foldLeft(this: ProjectMatrix) { (acc, sv) => + acc.customRow(autoScalaLibrary, axisValues ++ Seq(VirtualAxis.scalaABIVersion(sv)), process) + } + } else { + customRow(autoScalaLibrary, axisValues ++ 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) + + override def allProjects(): Seq[(Project, Seq[VirtualAxis])] = + resolvedMappings.map { case(row, project) => + project -> row.axisValues + }.toSeq + + def copy( + id: String = id, + base: sbt.File = base, + scalaVersions: Seq[String] = scalaVersions, + rows: Seq[ProjectRow] = rows, + aggregate: Seq[ProjectMatrixReference] = aggregate, + nonMatrixAggregate: Seq[ProjectReference] = nonMatrixAggregate, + dependencies: Seq[MatrixClasspathDep[ProjectMatrixReference]] = dependencies, + nonMatrixDependencies: Seq[ClasspathDep[ProjectReference]] = nonMatrixDependencies, + settings: Seq[Setting[_]] = settings, + configurations: Seq[Configuration] = configurations, + plugins: Plugins = plugins, + transforms: Seq[Project => Project] = transforms, + defAxes: Seq[VirtualAxis] = defAxes, + ): ProjectMatrix = { + val matrix = unresolved( + id, + base, + scalaVersions, + rows, + aggregate, + nonMatrixAggregate, + dependencies, + nonMatrixDependencies, + settings, + configurations, + plugins, + transforms, + defAxes, + ) + allMatrices(id) = matrix + matrix + } + } + + // called by macro + def apply(id: String, base: sbt.File): ProjectMatrix = { + val defaultDefAxes = Seq(VirtualAxis.jvm, VirtualAxis.scalaABIVersion("2.13.3")) + val matrix = unresolved(id, base, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Plugins.Empty, Nil, defaultDefAxes) + allMatrices(id) = matrix + matrix + } + + private[sbt] def unresolved( + id: String, + base: sbt.File, + scalaVersions: Seq[String], + rows: Seq[ProjectRow], + aggregate: Seq[ProjectMatrixReference], + nonMatrixAggregate: Seq[ProjectReference], + dependencies: Seq[MatrixClasspathDep[ProjectMatrixReference]], + nonMatrixDependencies: Seq[ClasspathDep[ProjectReference]], + settings: Seq[Def.Setting[_]], + configurations: Seq[Configuration], + plugins: Plugins, + transforms: Seq[Project => Project], + defAxes: Seq[VirtualAxis], + ): ProjectMatrix = + new ProjectMatrixDef( + id, + base, + scalaVersions, + rows, + aggregate, + nonMatrixAggregate, + dependencies, + nonMatrixDependencies, + settings, + configurations, + plugins, + transforms, + defAxes, + ) + + 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) + + import scala.reflect.macros._ + + def projectMatrixMacroImpl(c: blackbox.Context): c.Expr[ProjectMatrix] = { + import c.universe._ + val enclosingValName = std.KeyMacro.definingValName( + c, + methodName => + s"""$methodName must be directly assigned to a val, such as `val x = $methodName`. Alternatively, you can use `sbt.ProjectMatrix.apply`""" + ) + val name = c.Expr[String](Literal(Constant(enclosingValName))) + reify { ProjectMatrix(name.splice, new sbt.File(name.splice)) } + } +} diff --git a/src/main/scala/sbt/internal/ProjectMatrixReference.scala b/src/main/scala/sbt/internal/ProjectMatrixReference.scala new file mode 100644 index 000000000..5ed710cda --- /dev/null +++ b/src/main/scala/sbt/internal/ProjectMatrixReference.scala @@ -0,0 +1,8 @@ +package sbt +package internal + +/** Identifies a project matrix. */ +sealed trait ProjectMatrixReference + +/** Identifies a project in the current build context. */ +final case class LocalProjectMatrix(id: String) extends ProjectMatrixReference diff --git a/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala b/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala new file mode 100644 index 000000000..54d883ab2 --- /dev/null +++ b/src/main/scala/sbtprojectmatrix/ProjectMatrixPlugin.scala @@ -0,0 +1,31 @@ +package sbtprojectmatrix + +import sbt._ +import internal._ +import java.util.concurrent.atomic.AtomicBoolean +import scala.language.experimental.macros + +trait ProjectMatrixKeys { + val virtualAxes = settingKey[Seq[VirtualAxis]]("Virtual axes for the project") + val projectMatrixBaseDirectory = settingKey[File]("Base directory of the current project matrix") +} + +object ProjectMatrixKeys extends ProjectMatrixKeys + +object ProjectMatrixPlugin extends AutoPlugin { + override val requires = sbt.plugins.CorePlugin + override val trigger = allRequirements + object autoImport extends ProjectMatrixKeys { + def projectMatrix: ProjectMatrix = macro ProjectMatrix.projectMatrixMacroImpl + + implicit def matrixClasspathDependency[T]( + m: T + )(implicit ev: T => ProjectMatrixReference): ProjectMatrix.MatrixClasspathDependency = + ProjectMatrix.MatrixClasspathDependency(m, None) + + implicit def matrixReferenceSyntax[T]( + m: T + )(implicit ev: T => ProjectMatrixReference): ProjectMatrix.ProjectMatrixReferenceSyntax = + new ProjectMatrix.ProjectMatrixReferenceSyntax(m) + } +} diff --git a/src/main/scala/sbtprojectmatrix/ReflectionUtil.scala b/src/main/scala/sbtprojectmatrix/ReflectionUtil.scala new file mode 100644 index 000000000..77081ec6f --- /dev/null +++ b/src/main/scala/sbtprojectmatrix/ReflectionUtil.scala @@ -0,0 +1,36 @@ +package sbtprojectmatrix + +import java.lang.reflect.InvocationTargetException +import scala.reflect.ClassTag +import scala.util.Try + +object ReflectionUtil { + def getSingletonObject[A: ClassTag](classLoader: ClassLoader, className: String): Try[A] = + Try { + val clazz = classLoader.loadClass(className) + val t = implicitly[ClassTag[A]].runtimeClass + Option(clazz.getField("MODULE$").get(null)) match { + case None => throw new ClassNotFoundException(s"Unable to find $className using classloader: $classLoader") + case Some(c) if !t.isInstance(c) => throw new ClassCastException(s"${clazz.getName} is not a subtype of $t") + case Some(c: A) => c + } + } + .recover { + case i: InvocationTargetException if i.getTargetException != null => throw i.getTargetException + } + + def objectExists(classLoader: ClassLoader, className: String): Boolean = + try { + classLoader.loadClass(className).getField("MODULE$").get(null) != null + } catch { + case _: Throwable => false + } + + def withContextClassloader[A](loader: ClassLoader)(body: ClassLoader => A): A = { + val current = Thread.currentThread().getContextClassLoader + try { + Thread.currentThread().setContextClassLoader(loader) + body(loader) + } finally Thread.currentThread().setContextClassLoader(current) + } +} 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 new file mode 100644 index 000000000..10b14e863 --- /dev/null +++ b/src/sbt-test/projectMatrix/custom/build.sbt @@ -0,0 +1,46 @@ +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 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 := "app", + ivyPaths := (ThisBuild / ivyPaths).value + ) + .customRow( + scalaVersions = Seq(scala212, scala211), + axisValues = Seq(config12, VirtualAxis.jvm), + _.settings( + moduleName := name.value + "_config1.2", + libraryDependencies += "com.typesafe" % "config" % "1.2.1" + ) + ) + .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/project/plugins.sbt b/src/sbt-test/projectMatrix/custom/project/plugins.sbt new file mode 100644 index 000000000..4e80bbafc --- /dev/null +++ b/src/sbt-test/projectMatrix/custom/project/plugins.sbt @@ -0,0 +1,5 @@ +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/custom/test b/src/sbt-test/projectMatrix/custom/test new file mode 100644 index 000000000..c92f20c49 --- /dev/null +++ b/src/sbt-test/projectMatrix/custom/test @@ -0,0 +1,6 @@ +> publishLocal + +$ 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/finder/build.sbt b/src/sbt-test/projectMatrix/finder/build.sbt new file mode 100644 index 000000000..a4e8632c2 --- /dev/null +++ b/src/sbt-test/projectMatrix/finder/build.sbt @@ -0,0 +1,45 @@ +lazy val scala213 = "2.13.3" +lazy val scala212 = "2.12.12" +lazy val check = taskKey[Unit]("") + + +lazy val config12 = ConfigAxis("Config1_2", "config1.2") +lazy val config13 = ConfigAxis("Config1_3", "config1.3") + +lazy val root = (project in file(".")) + .aggregate((core.projectRefs ++ custom.projectRefs):_*) + +lazy val core = (projectMatrix in file("core")) + .jvmPlatform(scalaVersions = Seq(scala213, scala212)) + .jsPlatform(scalaVersions = Seq(scala212)) + +lazy val custom = + (projectMatrix in file("custom")) + .customRow( + scalaVersions = Seq(scala212), + axisValues = Seq(config13, VirtualAxis.jvm), + _.settings() + ) + +check := { + val coreResults: Map[Project, Set[VirtualAxis]] = core.allProjects().toMap.mapValues(_.toSet) + val customResults: Map[Project, Set[VirtualAxis]] = custom.allProjects().toMap.mapValues(_.toSet) + + val isJvm = VirtualAxis.jvm + val isJs = VirtualAxis.js + val is213 = VirtualAxis.scalaPartialVersion(scala213) + val is212 = VirtualAxis.scalaPartialVersion(scala212) + + val coreSubProjects = Set( + core.jvm(scala213), core.jvm(scala212), + core.js(scala212) + ) + + assert(coreResults.keySet == coreSubProjects) + assert(coreResults(core.jvm(scala213)) == Set(isJvm, is213)) + assert(coreResults(core.jvm(scala212)) == Set(isJvm, is212)) + assert(coreResults(core.js(scala212)) == Set(isJs, is212)) + + assert(customResults.keySet == Set(custom.jvm(scala212))) + assert(customResults(custom.jvm(scala212)) == Set(isJvm, is212, config13)) +} diff --git a/src/sbt-test/projectMatrix/finder/project/ConfigAxis.scala b/src/sbt-test/projectMatrix/finder/project/ConfigAxis.scala new file mode 100644 index 000000000..bdabcb757 --- /dev/null +++ b/src/sbt-test/projectMatrix/finder/project/ConfigAxis.scala @@ -0,0 +1,3 @@ +import sbt._ + +case class ConfigAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis diff --git a/src/sbt-test/projectMatrix/finder/project/plugins.sbt b/src/sbt-test/projectMatrix/finder/project/plugins.sbt new file mode 100644 index 000000000..60a69f1df --- /dev/null +++ b/src/sbt-test/projectMatrix/finder/project/plugins.sbt @@ -0,0 +1,7 @@ +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) +} + +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.3.0") diff --git a/src/sbt-test/projectMatrix/finder/test b/src/sbt-test/projectMatrix/finder/test new file mode 100644 index 000000000..e3bd83da1 --- /dev/null +++ b/src/sbt-test/projectMatrix/finder/test @@ -0,0 +1,2 @@ +> compile +> check diff --git a/src/sbt-test/projectMatrix/java/app/src/main/java-config1.2-jvm/com/config/MyClass.java b/src/sbt-test/projectMatrix/java/app/src/main/java-config1.2-jvm/com/config/MyClass.java new file mode 100644 index 000000000..b714ca27b --- /dev/null +++ b/src/sbt-test/projectMatrix/java/app/src/main/java-config1.2-jvm/com/config/MyClass.java @@ -0,0 +1,9 @@ +package com.config; + +public class MyClass { + + public static String configValue() { + return "1.2"; + } + +} diff --git a/src/sbt-test/projectMatrix/java/app/src/main/java-config1.3-jvm/com/config/MyClass.java b/src/sbt-test/projectMatrix/java/app/src/main/java-config1.3-jvm/com/config/MyClass.java new file mode 100644 index 000000000..2c4800d95 --- /dev/null +++ b/src/sbt-test/projectMatrix/java/app/src/main/java-config1.3-jvm/com/config/MyClass.java @@ -0,0 +1,9 @@ +package com.config; + +public class MyClass { + + public static String configValue() { + return "1.3"; + } + +} diff --git a/src/sbt-test/projectMatrix/java/app/src/main/scala/com/config/Main.scala b/src/sbt-test/projectMatrix/java/app/src/main/scala/com/config/Main.scala new file mode 100644 index 000000000..864de72cd --- /dev/null +++ b/src/sbt-test/projectMatrix/java/app/src/main/scala/com/config/Main.scala @@ -0,0 +1,5 @@ +package com.config + +object Main extends App { + println(s"Version: ${MyClass.configValue()}") +} diff --git a/src/sbt-test/projectMatrix/java/build.sbt b/src/sbt-test/projectMatrix/java/build.sbt new file mode 100644 index 000000000..d4532995a --- /dev/null +++ b/src/sbt-test/projectMatrix/java/build.sbt @@ -0,0 +1,41 @@ +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 config12 = ConfigAxis("Config1_2", "-config1.2") +lazy val config13 = ConfigAxis("Config1_3", "-config1.3") + +lazy val scala212 = "2.12.10" + +lazy val app = (projectMatrix in file("app")) + .settings( + name := "app", + ivyPaths := (ThisBuild / ivyPaths).value + ) + .customRow( + scalaVersions = Seq(scala212), + axisValues = Seq(config12, VirtualAxis.jvm), + _.settings( + moduleName := name.value + "_config1.2", + libraryDependencies += "com.typesafe" % "config" % "1.2.1" + ) + ) + .customRow( + scalaVersions = Seq(scala212), + 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/java/project/ConfigAxis.scala b/src/sbt-test/projectMatrix/java/project/ConfigAxis.scala new file mode 100644 index 000000000..b1124c60e --- /dev/null +++ b/src/sbt-test/projectMatrix/java/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/java/project/plugins.sbt b/src/sbt-test/projectMatrix/java/project/plugins.sbt new file mode 100644 index 000000000..4e80bbafc --- /dev/null +++ b/src/sbt-test/projectMatrix/java/project/plugins.sbt @@ -0,0 +1,5 @@ +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/java/test b/src/sbt-test/projectMatrix/java/test new file mode 100644 index 000000000..964c0eac1 --- /dev/null +++ b/src/sbt-test/projectMatrix/java/test @@ -0,0 +1,4 @@ +> publishLocal + +$ 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.12/0.1.0-SNAPSHOT/poms/app_config1.3_2.12.pom diff --git a/src/sbt-test/projectMatrix/js/build.sbt b/src/sbt-test/projectMatrix/js/build.sbt new file mode 100644 index 000000000..9300a02ef --- /dev/null +++ b/src/sbt-test/projectMatrix/js/build.sbt @@ -0,0 +1,17 @@ +// lazy val root = (project in file(".")) +// .aggregate(core.projectRefs ++ app.projectRefs: _*) +// .settings( +// ) + +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core" + ) + .jsPlatform(scalaVersions = Seq("2.12.8", "2.11.12")) + +lazy val app = (projectMatrix in file("app")) + .dependsOn(core) + .settings( + name := "app" + ) + .jsPlatform(scalaVersions = Seq("2.12.8")) diff --git a/src/sbt-test/projectMatrix/js/core/src/main/scala/Core.scala b/src/sbt-test/projectMatrix/js/core/src/main/scala/Core.scala new file mode 100644 index 000000000..274e01225 --- /dev/null +++ b/src/sbt-test/projectMatrix/js/core/src/main/scala/Core.scala @@ -0,0 +1,6 @@ +package a + +class Core { +} + +object Core extends Core diff --git a/src/sbt-test/projectMatrix/js/project/plugins.sbt b/src/sbt-test/projectMatrix/js/project/plugins.sbt new file mode 100644 index 000000000..70858c7d8 --- /dev/null +++ b/src/sbt-test/projectMatrix/js/project/plugins.sbt @@ -0,0 +1,6 @@ +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) +} +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.27") diff --git a/src/sbt-test/projectMatrix/js/test b/src/sbt-test/projectMatrix/js/test new file mode 100644 index 000000000..553c6bf3a --- /dev/null +++ b/src/sbt-test/projectMatrix/js/test @@ -0,0 +1,5 @@ +> fastOptJS + +$ exists app/target/js-2.12/app-fastopt.js +$ exists core/target/js-2.12/core-fastopt.js +$ exists core/target/js-2.11/core-fastopt.js diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/bar-app/D.scala b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/bar-app/D.scala new file mode 100644 index 000000000..b937ae06c --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/bar-app/D.scala @@ -0,0 +1,5 @@ +package example + +object D { + val x = C.x +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/bar-core/C.scala b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/bar-core/C.scala new file mode 100644 index 000000000..4d4fcc6df --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/bar-core/C.scala @@ -0,0 +1,5 @@ +package example + +object C { + val x = 1 +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/baz-app/F.scala b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/baz-app/F.scala new file mode 100644 index 000000000..5035ba457 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/baz-app/F.scala @@ -0,0 +1,5 @@ +package example + +object F { + val x = E.x +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/baz-core/E.scala b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/baz-core/E.scala new file mode 100644 index 000000000..cdac7bd76 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/baz-core/E.scala @@ -0,0 +1,5 @@ +package example + +object E { + val x = 1 +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/build.sbt b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/build.sbt new file mode 100644 index 000000000..825f5215c --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/build.sbt @@ -0,0 +1,57 @@ +lazy val check = taskKey[Unit]("") +lazy val scala3M1 = "3.0.0-M1" +lazy val scala3M2 = "3.0.0-M2" +lazy val scala213 = "2.13.4" + +lazy val fooApp = (projectMatrix in file("foo-app")) + .dependsOn(fooCore) + .settings( + name := "foo app", + ) + .jvmPlatform(scalaVersions = Seq(scala3M1, scala3M2)) + +lazy val fooApp3 = fooApp.jvm(scala3M1) + .settings( + test := { () }, + ) + +lazy val fooCore = (projectMatrix in file("foo-core")) + .settings( + name := "foo core", + ) + .jvmPlatform(scalaVersions = Seq(scala213, "2.12.12")) + +lazy val barApp = (projectMatrix in file("bar-app")) + .dependsOn(barCore) + .settings( + name := "bar app", + ) + .jvmPlatform(scalaVersions = Seq(scala213)) + +lazy val barCore = (projectMatrix in file("bar-core")) + .settings( + name := "bar core", + ) + .jvmPlatform(scalaVersions = Seq(scala3M2)) + +// choose 2.13 when bazCore offers both 2.13 and Dotty +lazy val bazApp = (projectMatrix in file("baz-app")) + .dependsOn(bazCore) + .settings( + name := "baz app", + check := { + val cp = (Compile / fullClasspath).value + .map(_.data.getName) + + assert(cp.contains("baz-core_2.13-0.1.0-SNAPSHOT.jar"), s"$cp") + assert(!cp.contains("baz-core_3.0.0-M1-0.1.0-SNAPSHOT.jar"), s"$cp") + }, + ) + .jvmPlatform(scalaVersions = Seq(scala213)) + +lazy val bazCore = (projectMatrix in file("baz-core")) + .settings( + name := "baz core", + exportJars := true, + ) + .jvmPlatform(scalaVersions = Seq(scala213, scala3M1)) diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/foo-app/B.scala b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/foo-app/B.scala new file mode 100644 index 000000000..ed82c07d1 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/foo-app/B.scala @@ -0,0 +1,5 @@ +package example + +object B { + val x = A.x +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/foo-core/A.scala b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/foo-core/A.scala new file mode 100644 index 000000000..be4b82a9f --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/foo-core/A.scala @@ -0,0 +1,5 @@ +package example + +object A { + val x = 1 +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/project/build.properties b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/project/build.properties new file mode 100644 index 000000000..c19c768d6 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.4.2 diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/project/plugins.sbt b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/project/plugins.sbt new file mode 100644 index 000000000..2db30a892 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/project/plugins.sbt @@ -0,0 +1,6 @@ +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) +} +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.4.5") diff --git a/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/test b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/test new file mode 100644 index 000000000..18ed59f1b --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich-sbt-1.3/test @@ -0,0 +1,7 @@ +> projects + +> fooApp3_0_0_M1/compile + +> barApp/compile + +> bazApp/check diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/bar-app/D.scala b/src/sbt-test/projectMatrix/jvm-sandwich/bar-app/D.scala new file mode 100644 index 000000000..b937ae06c --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/bar-app/D.scala @@ -0,0 +1,5 @@ +package example + +object D { + val x = C.x +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/bar-core/C.scala b/src/sbt-test/projectMatrix/jvm-sandwich/bar-core/C.scala new file mode 100644 index 000000000..4d4fcc6df --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/bar-core/C.scala @@ -0,0 +1,5 @@ +package example + +object C { + val x = 1 +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/baz-app/F.scala b/src/sbt-test/projectMatrix/jvm-sandwich/baz-app/F.scala new file mode 100644 index 000000000..5035ba457 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/baz-app/F.scala @@ -0,0 +1,5 @@ +package example + +object F { + val x = E.x +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/baz-core/E.scala b/src/sbt-test/projectMatrix/jvm-sandwich/baz-core/E.scala new file mode 100644 index 000000000..cdac7bd76 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/baz-core/E.scala @@ -0,0 +1,5 @@ +package example + +object E { + val x = 1 +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/build.sbt b/src/sbt-test/projectMatrix/jvm-sandwich/build.sbt new file mode 100644 index 000000000..98c3f574a --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/build.sbt @@ -0,0 +1,54 @@ +lazy val check = taskKey[Unit]("") +lazy val scala3M1 = "3.0.0-M1" +lazy val scala3M2 = "3.0.0-M2" +lazy val scala213 = "2.13.4" + +lazy val fooApp = (projectMatrix in file("foo-app")) + .dependsOn(fooCore) + .settings( + name := "foo app", + ) + .jvmPlatform(scalaVersions = Seq(scala3M1, scala3M2)) + +lazy val fooCore = (projectMatrix in file("foo-core")) + .settings( + name := "foo core", + ) + .jvmPlatform(scalaVersions = Seq(scala213, "2.12.12")) + +lazy val barApp = (projectMatrix in file("bar-app")) + .dependsOn(barCore) + .settings( + name := "bar app", + ) + .jvmPlatform(scalaVersions = Seq(scala213)) + +lazy val barCore = (projectMatrix in file("bar-core")) + .settings( + name := "bar core", + ) + .jvmPlatform(scalaVersions = Seq(scala3M1)) + +// choose 2.13 when bazCore offers both 2.13 and Dotty +lazy val bazApp = (projectMatrix in file("baz-app")) + .dependsOn(bazCore) + .settings( + name := "baz app", + check := { + val cp = (Compile / fullClasspath).value + .map(_.data.getName) + + streams.value.log.info(cp.toString) + assert(cp.contains("baz-core_2.13-0.1.0-SNAPSHOT.jar"), s"$cp") + assert(!cp.contains("baz-core_3.0.0-M1-0.1.0-SNAPSHOT.jar"), s"$cp") + assert(projectMatrixBaseDirectory.value == file("baz-app")) + }, + ) + .jvmPlatform(scalaVersions = Seq(scala213)) + +lazy val bazCore = (projectMatrix in file("baz-core")) + .settings( + name := "baz core", + exportJars := true, + ) + .jvmPlatform(scalaVersions = Seq(scala213, scala3M1, scala3M2)) diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/foo-app/B.scala b/src/sbt-test/projectMatrix/jvm-sandwich/foo-app/B.scala new file mode 100644 index 000000000..ed82c07d1 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/foo-app/B.scala @@ -0,0 +1,5 @@ +package example + +object B { + val x = A.x +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/foo-core/A.scala b/src/sbt-test/projectMatrix/jvm-sandwich/foo-core/A.scala new file mode 100644 index 000000000..be4b82a9f --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/foo-core/A.scala @@ -0,0 +1,5 @@ +package example + +object A { + val x = 1 +} diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/project/build.properties b/src/sbt-test/projectMatrix/jvm-sandwich/project/build.properties new file mode 100644 index 000000000..c19c768d6 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.4.2 diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/project/plugins.sbt b/src/sbt-test/projectMatrix/jvm-sandwich/project/plugins.sbt new file mode 100644 index 000000000..2db30a892 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/project/plugins.sbt @@ -0,0 +1,6 @@ +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) +} +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.4.5") diff --git a/src/sbt-test/projectMatrix/jvm-sandwich/test b/src/sbt-test/projectMatrix/jvm-sandwich/test new file mode 100644 index 000000000..18ed59f1b --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-sandwich/test @@ -0,0 +1,7 @@ +> projects + +> fooApp3_0_0_M1/compile + +> barApp/compile + +> bazApp/check diff --git a/src/sbt-test/projectMatrix/jvm-with-project-axes/build.sbt b/src/sbt-test/projectMatrix/jvm-with-project-axes/build.sbt new file mode 100644 index 000000000..4a7e5f31b --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-project-axes/build.sbt @@ -0,0 +1,53 @@ +import sbt.internal.ProjectMatrix +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 scala212 = "2.12.10" + +lazy val check = taskKey[Unit]("") + +lazy val config12 = ConfigAxis("Config1_2", "-config1.2") +lazy val config13 = ConfigAxis("Config1_3", "-config1.3") + +check := { + val app12 = app.finder(config12).apply(autoScalaLibrary = false) + assert(app12.id == "appConfig1_2", s"app12.id is ${app12.id}") + val app13 = app.finder(config13).apply(autoScalaLibrary = false) + assert(app13.id == "appConfig1_3", s"app13.id is ${app13.id}") +} + +lazy val app: ProjectMatrix = (projectMatrix in file("app")) + .settings( + name := "app", + ivyPaths := (ThisBuild / ivyPaths).value + ) + .aggregate(domain) + .dependsOn(domain) + .customRow( + autoScalaLibrary = false, + scalaVersions = Seq(scala212), + axisValues = Seq(config12, VirtualAxis.jvm), + _.settings( + libraryDependencies += "com.typesafe" % "config" % "1.2.1" + ) + ) + .customRow( + autoScalaLibrary = false, + scalaVersions = Seq(scala212), + axisValues = Seq(config13, VirtualAxis.jvm), + _.settings( + libraryDependencies += "com.typesafe" % "config" % "1.3.3" + ) + ) + +lazy val domain = (project in file("domain")) + .settings( + scalaVersion := scala212 + ) diff --git a/src/sbt-test/projectMatrix/jvm-with-project-axes/domain/src/main/scala/DataType.scala b/src/sbt-test/projectMatrix/jvm-with-project-axes/domain/src/main/scala/DataType.scala new file mode 100644 index 000000000..499a83d60 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-project-axes/domain/src/main/scala/DataType.scala @@ -0,0 +1,3 @@ +package a + +case class DataType() diff --git a/src/sbt-test/projectMatrix/jvm-with-project-axes/project/ConfigAxis.scala b/src/sbt-test/projectMatrix/jvm-with-project-axes/project/ConfigAxis.scala new file mode 100644 index 000000000..bdabcb757 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-project-axes/project/ConfigAxis.scala @@ -0,0 +1,3 @@ +import sbt._ + +case class ConfigAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis diff --git a/src/sbt-test/projectMatrix/jvm-with-project-axes/project/plugins.sbt b/src/sbt-test/projectMatrix/jvm-with-project-axes/project/plugins.sbt new file mode 100644 index 000000000..4e80bbafc --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-project-axes/project/plugins.sbt @@ -0,0 +1,5 @@ +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/jvm-with-project-axes/test b/src/sbt-test/projectMatrix/jvm-with-project-axes/test new file mode 100644 index 000000000..29c0480b3 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-project-axes/test @@ -0,0 +1,5 @@ +> compile + +$ exists domain/target/scala-2.12/classes/a/DataType.class + +> check diff --git a/src/sbt-test/projectMatrix/jvm-with-scoping/app/src/main/scala/Main.scala b/src/sbt-test/projectMatrix/jvm-with-scoping/app/src/main/scala/Main.scala new file mode 100644 index 000000000..510a46894 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-scoping/app/src/main/scala/Main.scala @@ -0,0 +1,5 @@ +package a + +object Main extends App { + val core = Core +} diff --git a/src/sbt-test/projectMatrix/jvm-with-scoping/build.sbt b/src/sbt-test/projectMatrix/jvm-with-scoping/build.sbt new file mode 100644 index 000000000..998141af4 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-scoping/build.sbt @@ -0,0 +1,44 @@ +lazy val scala213 = "2.13.3" +lazy val scala212 = "2.12.12" +lazy val check = taskKey[Unit]("") + +lazy val root = (project in file(".")) + .aggregate(core.projectRefs ++ app.projectRefs: _*) + .settings( + ) + +lazy val app = (projectMatrix in file("app")) + .aggregate(core, intf) + .dependsOn(core % Compile, intf % "compile->compile;test->test") + .settings( + name := "app" + ) + .jvmPlatform(scalaVersions = Seq(scala213)) + +lazy val core = (projectMatrix in file("core")) + .settings( + check := { + assert(moduleName.value == "core", s"moduleName is ${moduleName.value}") + + val directs = libraryDependencies.value + assert(directs.size == 2, s"$directs") + }, + ) + .jvmPlatform(scalaVersions = Seq(scala213, scala212)) + .configure(addStuff) + +lazy val intf = (projectMatrix in file("intf")) + .settings( + check := { + assert(moduleName.value == "intf", s"moduleName is ${moduleName.value}") + }, + ) + .jvmPlatform(autoScalaLibrary = false) + +lazy val core213 = core.jvm(scala213) + +def addStuff(p: Project): Project = { + p.settings( + libraryDependencies += "junit" % "junit" % "4.12" % Test + ) +} diff --git a/src/sbt-test/projectMatrix/jvm-with-scoping/core/src/main/scala/Core.scala b/src/sbt-test/projectMatrix/jvm-with-scoping/core/src/main/scala/Core.scala new file mode 100644 index 000000000..274e01225 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-scoping/core/src/main/scala/Core.scala @@ -0,0 +1,6 @@ +package a + +class Core { +} + +object Core extends Core diff --git a/src/sbt-test/projectMatrix/jvm-with-scoping/project/plugins.sbt b/src/sbt-test/projectMatrix/jvm-with-scoping/project/plugins.sbt new file mode 100644 index 000000000..4e80bbafc --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-scoping/project/plugins.sbt @@ -0,0 +1,5 @@ +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/jvm-with-scoping/test b/src/sbt-test/projectMatrix/jvm-with-scoping/test new file mode 100644 index 000000000..4a2cee2d6 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm-with-scoping/test @@ -0,0 +1,6 @@ +> compile + +$ exists core/target/jvm-2.13/classes/a/Core.class +$ exists core/target/jvm-2.12/classes/a/Core.class + +> core/check diff --git a/src/sbt-test/projectMatrix/jvm/build.sbt b/src/sbt-test/projectMatrix/jvm/build.sbt new file mode 100644 index 000000000..65b08b9e6 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm/build.sbt @@ -0,0 +1,36 @@ +lazy val scala213 = "2.13.3" +lazy val scala212 = "2.12.12" +lazy val check = taskKey[Unit]("") + +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(scala213)) + +lazy val core = (projectMatrix in file("core")) + .settings( + check := { + assert(moduleName.value == "core", s"moduleName is ${moduleName.value}") + assert(projectMatrixBaseDirectory.value == file("core")) + }, + ) + .jvmPlatform(scalaVersions = Seq(scala213, scala212)) + +lazy val intf = (projectMatrix in file("intf")) + .settings( + check := { + assert(moduleName.value == "intf", s"moduleName is ${moduleName.value}") + assert(projectMatrixBaseDirectory.value == file("intf")) + }, + ) + .jvmPlatform(autoScalaLibrary = false) + +lazy val core213 = core.jvm(scala213) diff --git a/src/sbt-test/projectMatrix/jvm/core/src/main/scala/Core.scala b/src/sbt-test/projectMatrix/jvm/core/src/main/scala/Core.scala new file mode 100644 index 000000000..274e01225 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm/core/src/main/scala/Core.scala @@ -0,0 +1,6 @@ +package a + +class Core { +} + +object Core extends Core diff --git a/src/sbt-test/projectMatrix/jvm/project/plugins.sbt b/src/sbt-test/projectMatrix/jvm/project/plugins.sbt new file mode 100644 index 000000000..4e80bbafc --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm/project/plugins.sbt @@ -0,0 +1,5 @@ +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/jvm/test b/src/sbt-test/projectMatrix/jvm/test new file mode 100644 index 000000000..4a2cee2d6 --- /dev/null +++ b/src/sbt-test/projectMatrix/jvm/test @@ -0,0 +1,6 @@ +> compile + +$ exists core/target/jvm-2.13/classes/a/Core.class +$ exists core/target/jvm-2.12/classes/a/Core.class + +> core/check diff --git a/src/sbt-test/projectMatrix/lib/build.sbt b/src/sbt-test/projectMatrix/lib/build.sbt new file mode 100644 index 000000000..4ee7b633d --- /dev/null +++ b/src/sbt-test/projectMatrix/lib/build.sbt @@ -0,0 +1,15 @@ +ThisBuild / version := "0.1.0-SNAPSHOT" + +lazy val util = projectMatrix + .jvmPlatform(scalaVersions = Seq("2.12.19", "2.13.13")) + +lazy val root = (projectMatrix in file(".")) + .dependsOn(util) + .jvmPlatform(scalaVersions = Seq("2.12.19")) + +// ss is second system +lazy val ss = projectMatrix + .dependsOn(util) + .jvmPlatform(scalaVersions = Seq("2.13.13")) + +lazy val strayJar = project diff --git a/src/sbt-test/projectMatrix/lib/project/plugins.sbt b/src/sbt-test/projectMatrix/lib/project/plugins.sbt new file mode 100644 index 000000000..4e80bbafc --- /dev/null +++ b/src/sbt-test/projectMatrix/lib/project/plugins.sbt @@ -0,0 +1,5 @@ +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/lib/src/main/scala/Main.scala b/src/sbt-test/projectMatrix/lib/src/main/scala/Main.scala new file mode 100644 index 000000000..ff1427531 --- /dev/null +++ b/src/sbt-test/projectMatrix/lib/src/main/scala/Main.scala @@ -0,0 +1,3 @@ +object Main extends App { + println(com.example.Lib.getMessage) +} diff --git a/src/sbt-test/projectMatrix/lib/ss/src/main/scala/Main.scala b/src/sbt-test/projectMatrix/lib/ss/src/main/scala/Main.scala new file mode 100644 index 000000000..ff1427531 --- /dev/null +++ b/src/sbt-test/projectMatrix/lib/ss/src/main/scala/Main.scala @@ -0,0 +1,3 @@ +object Main extends App { + println(com.example.Lib.getMessage) +} diff --git a/src/sbt-test/projectMatrix/lib/strayJar/src/main/java/com/example/Lib.java b/src/sbt-test/projectMatrix/lib/strayJar/src/main/java/com/example/Lib.java new file mode 100644 index 000000000..3740996fa --- /dev/null +++ b/src/sbt-test/projectMatrix/lib/strayJar/src/main/java/com/example/Lib.java @@ -0,0 +1,7 @@ +package com.example; + +public class Lib { + public static String getMessage() { + return "Hello, World!"; + } +} diff --git a/src/sbt-test/projectMatrix/lib/test b/src/sbt-test/projectMatrix/lib/test new file mode 100644 index 000000000..b55879894 --- /dev/null +++ b/src/sbt-test/projectMatrix/lib/test @@ -0,0 +1,15 @@ +# debug +#> unmanagedBase + +# make jar +> strayJar/package + +# check root +$ mkdir lib +$ copy-file strayJar/target/scala-2.12/strayjar_2.12-0.1.0-SNAPSHOT.jar lib/strayJar.jar +> root2_12/compile + +# check ss +$ mkdir ss/lib +$ copy-file strayJar/target/scala-2.12/strayjar_2.12-0.1.0-SNAPSHOT.jar ss/lib/strayJar.jar +> ss/compile diff --git a/src/sbt-test/projectMatrix/native/app/src/main/scala/App.scala b/src/sbt-test/projectMatrix/native/app/src/main/scala/App.scala new file mode 100644 index 000000000..2cbcd3db7 --- /dev/null +++ b/src/sbt-test/projectMatrix/native/app/src/main/scala/App.scala @@ -0,0 +1,8 @@ +package a + +object App { + def main(args: Array[String]): Unit = { + val a = new Core + println(s"Hello, world! ${a}") + } +} diff --git a/src/sbt-test/projectMatrix/native/build.sbt b/src/sbt-test/projectMatrix/native/build.sbt new file mode 100644 index 000000000..b9a3aab87 --- /dev/null +++ b/src/sbt-test/projectMatrix/native/build.sbt @@ -0,0 +1,19 @@ +// lazy val root = (project in file(".")) +// .aggregate(core.projectRefs ++ app.projectRefs: _*) +// .settings( +// ) + +lazy val core = (projectMatrix in file("core")) + .settings( + name := "core", + mainClass in (Compile, run) := Some("a.CoreMain") + ) + .nativePlatform(scalaVersions = Seq("2.11.12")) + +lazy val app = (projectMatrix in file("app")) + .dependsOn(core) + .settings( + name := "app", + mainClass in (Compile, run) := Some("a.App") + ) + .nativePlatform(scalaVersions = Seq("2.11.12")) diff --git a/src/sbt-test/projectMatrix/native/core/src/main/scala/Core.scala b/src/sbt-test/projectMatrix/native/core/src/main/scala/Core.scala new file mode 100644 index 000000000..274e01225 --- /dev/null +++ b/src/sbt-test/projectMatrix/native/core/src/main/scala/Core.scala @@ -0,0 +1,6 @@ +package a + +class Core { +} + +object Core extends Core diff --git a/src/sbt-test/projectMatrix/native/core/src/main/scala/CoreMain.scala b/src/sbt-test/projectMatrix/native/core/src/main/scala/CoreMain.scala new file mode 100644 index 000000000..718013861 --- /dev/null +++ b/src/sbt-test/projectMatrix/native/core/src/main/scala/CoreMain.scala @@ -0,0 +1,6 @@ +package a + +object CoreMain { + def main(args: Array[String]): Unit = { + } +} diff --git a/src/sbt-test/projectMatrix/native/project/build.properties b/src/sbt-test/projectMatrix/native/project/build.properties new file mode 100644 index 000000000..dc8f331cc --- /dev/null +++ b/src/sbt-test/projectMatrix/native/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.4.3 diff --git a/src/sbt-test/projectMatrix/native/project/plugins.sbt b/src/sbt-test/projectMatrix/native/project/plugins.sbt new file mode 100644 index 000000000..cb79d7dae --- /dev/null +++ b/src/sbt-test/projectMatrix/native/project/plugins.sbt @@ -0,0 +1,6 @@ +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) +} +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.0") diff --git a/src/sbt-test/projectMatrix/native/test b/src/sbt-test/projectMatrix/native/test new file mode 100644 index 000000000..d4d53c054 --- /dev/null +++ b/src/sbt-test/projectMatrix/native/test @@ -0,0 +1,4 @@ +> nativeLink + +$ exists app/target/native-2.11/app-out +$ exists core/target/native-2.11/core-out diff --git a/src/sbt-test/projectMatrix/projectAxes/build.sbt b/src/sbt-test/projectMatrix/projectAxes/build.sbt new file mode 100644 index 000000000..87667c258 --- /dev/null +++ b/src/sbt-test/projectMatrix/projectAxes/build.sbt @@ -0,0 +1,56 @@ +lazy val scala213 = "2.13.3" +lazy val scala212 = "2.12.12" +lazy val check = taskKey[Unit]("") +lazy val platformTest = settingKey[String]("") +lazy val configTest = settingKey[String]("") + + +lazy val config12 = ConfigAxis("Config1_2", "config1.2") +lazy val config13 = ConfigAxis("Config1_3", "config1.3") + +lazy val root = (project in file(".")) + .aggregate((core.projectRefs ++ custom.projectRefs):_*) + +lazy val core = (projectMatrix in file("core")) + .settings( + check := { + assert(platformTest.value.endsWith("-platform")) + assert(projectMatrixBaseDirectory.value == file("core")) + }, + ) + .jvmPlatform(scalaVersions = Seq(scala213, scala212)) + .jsPlatform(scalaVersions = Seq(scala212)) + .settings(platformSettings) + +lazy val custom = + (projectMatrix in file("custom")) + .customRow( + scalaVersions = Seq(scala212), + axisValues = Seq(config13, VirtualAxis.jvm), + _.settings() + ) + .settings(platformSettings) + .settings(customSettings) + .settings( + check := { + assert(platformTest.value.endsWith("-platform")) + assert(configTest.value.startsWith("config for")) + } + ) + + +lazy val platformSettings = Seq[Def.Setting[_]]( + platformTest := { + if(virtualAxes.value.contains(sbt.VirtualAxis.js)) "js-platform" + else if(virtualAxes.value.contains(sbt.VirtualAxis.jvm)) "jvm-platform" + else throw new RuntimeException(s"Something must be wrong (built-in platforms test) - virtualAxes value is ${virtualAxes.value}") + } +) + +lazy val customSettings = Seq[Def.Setting[_]]( + configTest := { + if(virtualAxes.value.contains(config12)) "config for 1.2" + else if (virtualAxes.value.contains(config13)) "config for 1.3" + else throw new RuntimeException(s"Something must be wrong (custom axis test ) - virtualAxes value is ${virtualAxes.value}") + } +) diff --git a/src/sbt-test/projectMatrix/projectAxes/project/ConfigAxis.scala b/src/sbt-test/projectMatrix/projectAxes/project/ConfigAxis.scala new file mode 100644 index 000000000..bdabcb757 --- /dev/null +++ b/src/sbt-test/projectMatrix/projectAxes/project/ConfigAxis.scala @@ -0,0 +1,3 @@ +import sbt._ + +case class ConfigAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis diff --git a/src/sbt-test/projectMatrix/projectAxes/project/plugins.sbt b/src/sbt-test/projectMatrix/projectAxes/project/plugins.sbt new file mode 100644 index 000000000..60a69f1df --- /dev/null +++ b/src/sbt-test/projectMatrix/projectAxes/project/plugins.sbt @@ -0,0 +1,7 @@ +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) +} + +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.3.0") diff --git a/src/sbt-test/projectMatrix/projectAxes/test b/src/sbt-test/projectMatrix/projectAxes/test new file mode 100644 index 000000000..e3bd83da1 --- /dev/null +++ b/src/sbt-test/projectMatrix/projectAxes/test @@ -0,0 +1,2 @@ +> compile +> check