Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for partially-shared source directories #145

Merged
merged 2 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion project/Extra.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object Extra {

val sbtPluginSettings = Def.settings(
organization := "org.portable-scala",
version := "1.1.1-SNAPSHOT",
version := "1.2.0-SNAPSHOT",
versionScheme := Some("semver-spec"),
scalacOptions ++= Seq(
"-deprecation",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import sbtcrossproject.{crossProject, CrossType}

lazy val foo = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.settings(scalaVersion := "2.11.11")
.jsSettings(scalaJSUseMainModuleInitializer := true)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object JSOrJVM {
def check = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object JSOrNative {
def check = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object JVMOrNative {
def check = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Platform {
def isJVM = false
def isJS = true
def isNative = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object JVMOrNative {
def check = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object JSOrNative {
def check = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Platform {
def isJVM = true
def isJS = false
def isNative = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object JSOrJVM {
def check = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Platform {
def isJVM = false
def isJS = false
def isNative = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Platform._
object Foo {
def main(args: Array[String]): Unit = {
assert(List(isJVM, isJS, isNative).count(identity) == 1)

if (isJVM)
assert(JSOrJVM.check && JVMOrNative.check && !JSOrNative.check)
if (isJS)
assert(JSOrJVM.check && !JVMOrNative.check && JSOrNative.check)
if (isNative)
assert(!JSOrJVM.check && JVMOrNative.check && JSOrNative.check)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
> fooJVM/run
> fooJS/run
> fooNative/run
107 changes: 85 additions & 22 deletions sbt-crossproject/src/main/scala/sbtcrossproject/CrossProject.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import sbtcrossproject._

import scala.language.implicitConversions

import scala.collection.immutable.HashMap
import scala.collection.immutable.ListSet

import sbt._
import Keys._

Expand Down Expand Up @@ -202,16 +205,17 @@ object CrossProject {
).settings(
CrossPlugin.autoImport.crossProjectPlatform := platform,
name := id, // #80
sharedSrc,
sharedResources
sharedSrc(platform),
sharedResources(platform)
)
)
}.toMap

new CrossProject(id, crossType, projects)
}

private def sharedSrcSettings(crossType: CrossType): Seq[Setting[_]] = {
private def sharedSrcSettings(
crossType: CrossType): Map[Platform, Seq[Setting[_]]] = {
def makeCrossSources(sharedSrcDir: Option[File],
scalaBinaryVersion: String,
cross: Boolean): Seq[File] = {
Expand All @@ -234,30 +238,89 @@ object CrossProject {
}
}

Seq(
unmanagedSourceDirectories in Compile ++= {
makeCrossSources(crossType.sharedSrcDir(baseDirectory.value, "main"),
scalaBinaryVersion.value,
crossPaths.value)
},
unmanagedSourceDirectories in Test ++= {
makeCrossSources(crossType.sharedSrcDir(baseDirectory.value, "test"),
scalaBinaryVersion.value,
crossPaths.value)
def makeSharedSettings(
key: SettingKey[Seq[File]],
config: String): Seq[(Platform, Seq[Setting[_]])] = {
val partiallyShared = makePartiallySharedSettings(platforms) {
platformSubset =>
Seq(
key ++= makeCrossSources(
crossType.partiallySharedSrcDir(baseDirectory.value,
platformSubset,
config),
scalaBinaryVersion.value,
crossPaths.value)
)
}
)

val shared = Seq(
key ++= makeCrossSources(
crossType.sharedSrcDir(baseDirectory.value, config),
scalaBinaryVersion.value,
crossPaths.value)
)

partiallyShared ++ platforms.map(_ -> shared) // add shared to each platform
}

val compileSettings =
makeSharedSettings(unmanagedSourceDirectories in Compile, "main")
val testSettings =
makeSharedSettings(unmanagedSourceDirectories in Test, "test")

(compileSettings ++ testSettings) // group-reduce the settings per-platform
.groupBy(_._1)
.map(kv => kv._1 -> kv._2.flatMap(_._2))
}

private def sharedResourcesSettings(
crossType: CrossType): Seq[Setting[_]] = {
Seq(
unmanagedResourceDirectories in Compile ++= {
crossType.sharedResourcesDir(baseDirectory.value, "main")
},
unmanagedResourceDirectories in Test ++= {
crossType.sharedResourcesDir(baseDirectory.value, "test")
crossType: CrossType): Map[Platform, Seq[Setting[_]]] = {
def makeSharedSettings(
key: SettingKey[Seq[File]],
config: String): Seq[(Platform, Seq[Setting[_]])] = {
val partiallyShared = makePartiallySharedSettings(platforms) {
platformSubset =>
Seq(
key ++= crossType
.partiallySharedResourcesDir(baseDirectory.value,
platformSubset,
config)
.toSeq
)
}

val shared = Seq(
key ++= crossType
.sharedResourcesDir(baseDirectory.value, config)
.toSeq
)

partiallyShared ++ platforms.map(_ -> shared) // add shared to each platform
}

val compileSettings =
makeSharedSettings(unmanagedResourceDirectories in Compile, "main")
val testSettings =
makeSharedSettings(unmanagedResourceDirectories in Test, "test")

(compileSettings ++ testSettings) // group-reduce the settings per-platform
.groupBy(_._1)
.map(kv => kv._1 -> kv._2.flatMap(_._2))
}

private def makePartiallySharedSettings(platforms: Seq[Platform])(
mkSettings: Seq[Platform] => Seq[Setting[_]])
: Seq[(Platform, Seq[Setting[_]])] = {
platforms.toSet
.subsets()
.filter(_.size > 1) // skip the empty+singleton subsets
.filterNot(_.size == platforms.size) // skip the all-platform subset
.toSeq
.map(_.toSeq.sortBy(_.identifier)) // use a consistent ordering
.flatMap { platformSubset => // make the settings for this subset of platforms
val settings = mkSettings(platformSubset)
platformSubset.map(_ -> settings)
}
)
}

}
Expand Down
33 changes: 33 additions & 0 deletions sbt-crossproject/src/main/scala/sbtcrossproject/CrossType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,32 @@ abstract class CrossType {
*/
def sharedSrcDir(projectBase: File, conf: String): Option[File]

/** The location of a partially shared source directory (if it exists)
* @param projectBase the base directory of a (true sbt) Project
* @param platforms non-empty seq of JSPlatform, JVMPlatform, NativePlatform, ...
* @param conf name of sub-directory for the configuration (typically "main"
* or "test")
*/
def partiallySharedSrcDir(projectBase: File,
platforms: Seq[Platform],
conf: String): Option[File] = None

/** The location of a shared resources directory (if it exists)
* @param projectBase the base directory of a (true sbt) Project
* @param conf name of sub-directory for the configuration (typically "main"
* or "test")
*/
def sharedResourcesDir(projectBase: File, conf: String): Option[File] = None

/** The location of a partially shared resources directory (if it exists)
* @param projectBase the base directory of a (true sbt) Project
* @param conf name of sub-directory for the configuration (typically "main"
* or "test")
*/
def partiallySharedResourcesDir(projectBase: File,
platforms: Seq[Platform],
conf: String): Option[File] = None

}

object CrossType {
Expand All @@ -69,9 +88,23 @@ object CrossType {
def sharedSrcDir(projectBase: File, conf: String): Option[File] =
Some(projectBase.getParentFile / "shared" / "src" / conf / "scala")

override def partiallySharedSrcDir(projectBase: File,
platforms: Seq[Platform],
conf: String): Option[File] = {
val dir = platforms.map(_.identifier).mkString("-")
Some(projectBase.getParentFile / dir / "src" / conf / "scala")
}

override def sharedResourcesDir(projectBase: File,
conf: String): Option[File] =
Some(projectBase.getParentFile / "shared" / "src" / conf / "resources")

override def partiallySharedResourcesDir(projectBase: File,
platforms: Seq[Platform],
conf: String): Option[File] = {
val dir = platforms.map(_.identifier).mkString("-")
Some(projectBase.getParentFile / dir / "src" / conf / "resources")
}
}

/**
Expand Down