├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── examples ├── common-cross │ ├── bar │ │ └── src │ │ │ └── main │ │ │ └── scala │ │ │ └── Bar.scala │ ├── build.sbt │ ├── common │ │ └── src │ │ │ └── main │ │ │ └── scala │ │ │ └── Common.scala │ ├── foo │ │ └── src │ │ │ └── main │ │ │ └── scala │ │ │ └── Foo.scala │ └── project │ │ ├── build.properties │ │ └── plugins.sbt ├── dependency-configurations │ ├── build.sbt │ └── project │ │ └── build.sbt └── simple │ ├── build.sbt │ └── project │ ├── build.properties │ └── plugins.sbt └── sbt-cross ├── RELEASE.md ├── build.sbt ├── project ├── build.properties └── plugins.sbt ├── src └── main │ └── scala │ └── com │ └── lucidchart │ └── sbtcross │ ├── AggregateArgument.scala │ ├── Axis.scala │ ├── CrossedProject.scala │ ├── DefaultAxis.scala │ ├── LibraryVersionAxis.scala │ ├── LocalProjectDependency.scala │ ├── SbtCrossPlugin.scala │ └── ScalaAxis.scala └── version /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.swp 3 | 4 | .idea/ 5 | target*/ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | after_success: | 2 | if [ "$TRAVIS_SECURE_ENV_VARS" == true ]; then 3 | echo "$PGP_SECRET" | base64 --decode | gpg --import 4 | if [ -z "$TRAVIS_TAG" ]; then 5 | (cd sbt-cross && exec sbt publishSigned) 6 | else 7 | (cd sbt-cross && exec sbt "; publishSigned; sonatypeBundleRelease") 8 | fi 9 | fi 10 | cache: 11 | directories: 12 | - $HOME/.ivy2 13 | - $HOME/.sbt 14 | deploy: 15 | provider: releases 16 | api_key: 17 | secure: gtGkk0o5BwJyhdob+0PlL7zQHO1ACpO22cIYQyfoMvpcnTrrAHqa7Pxx7DUHstE0wIWCPrgKnzUbjqCvxpSZ2mrfg9K0CRLVBQv/BC45szXeKvAIwjij8kJY30QQD9G2xoom6vqi5OajS440jEmD0E4VgegQNaYY5HK0OKYizfU= 18 | file: '*/target/**/*.jar' 19 | file_glob: true 20 | on: 21 | tags: true 22 | repo: lucidsoftware/sbt-cross 23 | skip_cleanup: true 24 | git: 25 | depth: 1 26 | jdk: openjdk8 27 | language: scala 28 | script: 29 | - '[ "$TRAVIS_PULL_REQUEST" != false ] || export SBT_OPTS=-Dbuild.version=${TRAVIS_TAG:-$TRAVIS_BRANCH-SNAPSHOT}' 30 | - (cd sbt-cross && exec sbt checkFormat package test) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Lucid Software, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this project except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0.txt 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #sbt-cross 2 | 3 | [![Build Status](https://travis-ci.com/lucidsoftware/sbt-cross.svg?branch=master)](https://travis-ci.com/lucidsoftware/sbt-cross) 4 | ![Maven Version](https://img.shields.io/maven-central/v/com.lucidchart/sbt-cross.svg) 5 | 6 | A better solution for building multiple Scala versions (cross compiling) in SBT. 7 | 8 | ## Purpose 9 | 10 | SBT's `crossScalaVersions` allows projects to compile with multiple versions of Scala. 11 | 12 | However, `crossScalaVersions` is a hack that reuses projects by mutates settings. This causes problems: 13 | 14 | 1. Performance - Each Scala version is handled sequentially (not in parallel). 15 | 1. Subprojects - Project classpath dependencies can be tricky. 16 | 1. Aggregation - Aggregation doesn't take into account `crossScalaVersions` of subprojects, hence 17 | [sbt-doge](https://github.com/sbt/sbt-doge). 18 | 1. Cross paths - Very many tasks don't play nicely. E.g. if you use 19 | [sbt-native-packager](http://www.scala-sbt.org/sbt-native-packager/) and `+debian:packageBin`, you'll build 20 | two debs on top of each other. 21 | 1. General funniness - For example, [sbt-sonatype](https://github.com/xerial/sbt-sonatype#using-with-sbt-release-plugin) 22 | requires extra wrangling to work with `crossScalaVersions`. 23 | 24 | sbt-cross solves all by simply splitting projects: one for each version of Scala. This works with SBT's core 25 | project/task system, rather than fighting it. 26 | 27 | ## Install 28 | 29 | Requires SBT 1.3+. 30 | 31 | In project/plugins.sbt, add 32 | 33 | ```scala 34 | addSbtPlugin("com.lucidchart" % "sbt-cross" % "4.0") 35 | ``` 36 | 37 | For the latest development version, 38 | 39 | ```scala 40 | resolvers += Resolver.sonatypeRepo("snapshots") 41 | 42 | addSbtPlugin("com.lucidchart" % "sbt-cross" % "master-SNAPSHOT") 43 | ``` 44 | 45 | ## Example 46 | 47 | Suppose there is a project `pipers` that uses Scala 2.11, a project `drummers` that uses Scala 2.12, and they depend on a 48 | project `instruments`, which compiles with both Scala versions. 49 | 50 | This cannot be done with `crossScalaVersions`, but it can with sbt-cross. 51 | 52 | ```scala 53 | lazy val pipers = project.dependsOn(instruments_2_11).settings(scalaVersion := "2.11.8") 54 | lazy val drummers = project.dependsOn(instruments_2_12).settings(scalaVersion := "2.12.1") 55 | 56 | lazy val instruments = project.cross 57 | lazy val instruments_2_11 = instruments("2.11.8") 58 | lazy val instruments_2_12 = instruments("2.12.1") 59 | ``` 60 | 61 | This defines four projects: `pipers`, `drummers`, `instruments-2_11`, and `instruments-2_12`. 62 | 63 | SBT will concurrently compile the right ones in the right order. 64 | 65 | * `sbt pipers/compile` will compile `instruments_2_11` then `pipers`. 66 | 67 | * `sbt drummers/compile` will compile `instruments_2_12` then `drummers`. 68 | 69 | * `sbt compile` will compile `instruments_2_11` then `pipers` and, *in parallel*, `instruments_2_12` then `drummers`. 70 | 71 | See [examples](examples) for more. 72 | 73 | ### Additional crossing 74 | 75 | sbt-cross generalizes this approach to other any cross-compilation-like use. You can even chain cross versions. There is 76 | currently no documentation for this, but `LibraryVersionAxis` is an example. 77 | 78 | ## Contributions 79 | 80 | We welcome issues, questions, and contributions on our GitHub project 81 | ([https://github.com/lucidsoftware/sbt-cross](github.com/lucidsoftware/sbt-cross)). 82 | -------------------------------------------------------------------------------- /examples/common-cross/bar/src/main/scala/Bar.scala: -------------------------------------------------------------------------------- 1 | case class Bar(a: C, b: C, c: C, d: C, e: C, f: C, g: C, 2 | h: C, i: C, j: C, k: C, l: C, m: C, n: C, o: C, p: C, 3 | q: C, r: C, s: C, t: C, u: C, v: C, w: C, x: C, y: C, 4 | z: C) 5 | 6 | -------------------------------------------------------------------------------- /examples/common-cross/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val foo = (project in file("foo")).dependsOn(common_2_11).settings( 2 | scalaVersion := "2.11.12" 3 | ) 4 | 5 | lazy val bar = (project in file("bar")).dependsOn(common_2_12).settings( 6 | scalaVersion := "2.12.10" 7 | ) 8 | 9 | // unfortunately, pattern matching doesn't work in val assignment, 10 | // see: https://github.com/sbt/sbt/issues/2290 11 | lazy val common = (project in file("common")).cross 12 | 13 | lazy val common_2_11 = common("2.11.12") 14 | 15 | lazy val common_2_12 = common("2.12.10") 16 | 17 | -------------------------------------------------------------------------------- /examples/common-cross/common/src/main/scala/Common.scala: -------------------------------------------------------------------------------- 1 | class C {} 2 | 3 | -------------------------------------------------------------------------------- /examples/common-cross/foo/src/main/scala/Foo.scala: -------------------------------------------------------------------------------- 1 | object Foo { 2 | {new C} 3 | } 4 | 5 | -------------------------------------------------------------------------------- /examples/common-cross/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.3 2 | 3 | -------------------------------------------------------------------------------- /examples/common-cross/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.lucidchart" % "sbt-cross" % "0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /examples/dependency-configurations/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val mainCross = Project("main", file("main")).cross 2 | .dependsOn(testCross % "test") 3 | 4 | lazy val mainCross_2_10 = mainCross("2.10.5") 5 | 6 | lazy val mainCross_2_11 = mainCross("2.11.6") 7 | 8 | lazy val testCross = Project("common", file("common")).cross 9 | 10 | lazy val testCross_2_10 = testCross("2.10.5") 11 | 12 | lazy val testCross_2_11 = testCross("2.11.6") 13 | -------------------------------------------------------------------------------- /examples/dependency-configurations/project/build.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.lucidchart" % "sbt-cross" % "0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /examples/simple/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val base = Project("foo", file(".")).cross 2 | 3 | lazy val project_2_10 = base("2.10.4") 4 | 5 | lazy val project_2_11 = base("2.11.5") 6 | 7 | lazy val all = base.empty.aggregate(project_2_10, project_2_11) 8 | -------------------------------------------------------------------------------- /examples/simple/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.3 2 | 3 | -------------------------------------------------------------------------------- /examples/simple/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.lucidchart" % "sbt-cross" % "0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /sbt-cross/RELEASE.md: -------------------------------------------------------------------------------- 1 | # Releases 2 | 3 | ## Versioning scheme 4 | 5 | Versions are `.`. 6 | 7 | * Each major version series has a branch, with a SNAPSHOT version published for the latest. 8 | 9 | * Each major.minor version has a tag, which triggers publishing a release version. 10 | 11 | Commits are typically developed for `master` and then cherry-picked to branches as needed. 12 | 13 | ``` 14 | A - B - C - D - E - F - G - H (master) 15 | \ \ 16 | C' E' - G' - H' (2) 17 | \ (2.0) (2.1) 18 | D' 19 | (1.0, 1) 20 | 21 | Published versions: 22 | 1.0 23 | 1-SNAPSHOT 24 | 2.0 25 | 2.1 26 | 2-SNAPSHOT 27 | master-SNAPSHOT 28 | ``` 29 | 30 | ## Release process 31 | 32 | ### 1. Create and checkout branches 33 | 34 | New major version: create, checkout, and push a new branch for the major series. 35 | 36 | ```sh 37 | git checkout -b master 38 | git push -u HEAD 39 | ``` 40 | 41 | New minor version: checkout major series branch 42 | 43 | ```sh 44 | git checkout 45 | ``` 46 | 47 | ### 2. Tag 48 | 49 | Push a tag with the new version. 50 | 51 | ```sh 52 | git push HEAD:refs/tags/. 53 | ``` 54 | 55 | This triggers a release in Github and Sonatype. 56 | 57 | ### 3. Update documentation 58 | 59 | Update documentation and examples on `master` to point to the new version, commit, and push. 60 | -------------------------------------------------------------------------------- /sbt-cross/build.sbt: -------------------------------------------------------------------------------- 1 | import scala.sys.process._ 2 | 3 | val checkFormat = TaskKey[Unit]("check-format") 4 | 5 | checkFormat := { 6 | (scalariformFormat in Compile).value 7 | val directory = baseDirectory.value.absolutePath 8 | val logger = (streams in Compile).value.log 9 | val paths = s"git diff --name-only $directory".lineStream_! 10 | if (paths.nonEmpty) { 11 | logger.error("The following files are not corrected formatted:") 12 | paths.foreach { path => 13 | logger.error(s" $path") 14 | } 15 | logger.error("Run `sbt scalariform-format`") 16 | throw new RuntimeException(s"${paths.size} files need formatting") 17 | } 18 | } 19 | 20 | credentials += Credentials( 21 | "Sonatype Nexus Repository Manager", 22 | "oss.sonatype.org", 23 | sys.env.getOrElse("SONATYPE_USERNAME", ""), 24 | sys.env.getOrElse("SONATYPE_PASSWORD", "") 25 | ) 26 | 27 | developers := List( 28 | Developer("lucidsoftware", "Lucid Software", "github@lucidchart.com", url("https://www.golucid.co/")) 29 | ) 30 | 31 | description := "A better solution for cross compiling Scala versions in SBT." 32 | 33 | homepage := Some(url("https://github.com/lucidsoftware/sbt-cross")) 34 | 35 | libraryDependencies ++= Seq( 36 | "org.apache.commons" % "commons-lang3" % "3.5" 37 | ) 38 | 39 | licenses += "Apache 2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt") 40 | 41 | name := "sbt-cross" 42 | 43 | organization := "com.lucidchart" 44 | 45 | organizationHomepage := Some(url("https://www.golucido.co/")) 46 | 47 | organizationName := "Lucid Software" 48 | 49 | sbtPlugin := true 50 | 51 | scalacOptions ++= Seq("-deprecation") 52 | 53 | publishTo := sonatypePublishToBundle.value 54 | 55 | scmInfo := Some(ScmInfo(url("https://github.com/lucidsoftware/sbt-cross"), "scm:git:git@github.com:lucidsoftware/sbt-cross", None)) 56 | 57 | startYear := Some(2017) 58 | 59 | version := sys.props.getOrElse("build.version", "0-SNAPSHOT") 60 | -------------------------------------------------------------------------------- /sbt-cross/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.3 2 | -------------------------------------------------------------------------------- /sbt-cross/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.0") 2 | 3 | addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.3") 4 | 5 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.8") 6 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/AggregateArgument.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import scala.language.implicitConversions 4 | import sbt._ 5 | 6 | sealed trait AggregateArgument 7 | 8 | final case class ProjectAggregateArgument(project: Project) extends AggregateArgument 9 | 10 | object ProjectAggregateArgument { 11 | implicit def toArgument(project: Project): ProjectAggregateArgument = apply(project) 12 | } 13 | 14 | final case class VersionAggregateArgument(version: String) extends AggregateArgument 15 | 16 | object VersionAggregateArgument { 17 | implicit def toArgument(version: String): VersionAggregateArgument = apply(version) 18 | } 19 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/Axis.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import sbt.LocalProject 4 | 5 | trait Axis { 6 | def apply[A <: CrossableProject[A]](delegate: A, version: String): A 7 | def apply(project: LocalProject, version: String): LocalProject 8 | } 9 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/CrossedProject.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import sbt._ 4 | import scala.language.implicitConversions 5 | 6 | sealed trait CrossableProject[A <: CrossableProject[A]] { 7 | self: A => 8 | protected[this] type P 9 | final def %(configurations: String) = (this: LocalProjectDependency).copy(configurations = Some(configurations)) 10 | final def cross(axis: Axis) = new CrossedProject(axis, this) 11 | final def empty = Project(project.id, file(".cross") / project.id) 12 | final def localProject = LocalProject(project.id) 13 | def dependsOn(dependencies: LocalProjectDependency*): A 14 | def resolve: P 15 | def project: Project 16 | def withProject(project: Project): A 17 | } 18 | 19 | object CrossableProject { 20 | implicit def toDependency(project: CrossableProject[_]): LocalProjectDependency = LocalProjectDependency(project.localProject) 21 | } 22 | 23 | final case class BaseProject(project: Project) extends CrossableProject[BaseProject] { 24 | protected[this] type P = Project 25 | def cross: CrossedProject[BaseProject] = cross(ScalaAxis) 26 | def dependsOn(dependencies: LocalProjectDependency*) = copy(project.dependsOn(dependencies.map(_.classpathDependency): _*)) 27 | def resolve = project 28 | def withProject(project: Project) = copy(project) 29 | } 30 | 31 | final case class CrossedProject[A <: CrossableProject[A]](axis: Axis, delegate: A, dependencies: Seq[LocalProjectDependency] = Nil) extends CrossableProject[CrossedProject[A]] { 32 | protected[this] type P = this.type 33 | def aggregate(aggregates: AggregateArgument*) = empty.aggregate(aggregates.map { 34 | case ProjectAggregateArgument(project) => project: ProjectReference 35 | case VersionAggregateArgument(version) => axis(LocalProject(delegate.project.id), version) 36 | }: _*) 37 | def apply(version: String) = 38 | axis(delegate, version) 39 | .dependsOn(dependencies.map(d => d.copy(axis(d.project, version))): _*) 40 | .resolve 41 | def dependsOn(dependencies: LocalProjectDependency*) = copy(dependencies = this.dependencies ++ dependencies) 42 | def forVersions(version1: String) = Tuple1(apply(version1)) 43 | def forVersions(version1: String, version2: String) = (apply(version1), apply(version2)) 44 | def forVersions(version1: String, version2: String, version3: String) = (apply(version1), apply(version2), apply(version3)) 45 | def forVersions(version1: String, version2: String, version3: String, version4: String) = (apply(version1), apply(version2), apply(version3), apply(version4)) 46 | def forVersions(version1: String, version2: String, version3: String, version4: String, version5: String) = (apply(version1), apply(version2), apply(version3), apply(version4), apply(version5)) 47 | def project = delegate.project 48 | def resolve = this 49 | def withProject(project: Project) = copy(delegate = delegate.withProject(project)) 50 | } 51 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/DefaultAxis.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import sbt.Keys._ 4 | import sbt._ 5 | import sbt.plugins.CorePlugin 6 | 7 | trait DefaultAxis extends Axis { 8 | 9 | import DefaultAxisPlugin.autoImport._ 10 | 11 | protected[this] def name: String 12 | protected[this] def major(version: String): String 13 | protected[this] def id(id: String, version: String) = s"${id}_${major(version).replace(".", "_")}" 14 | def apply[A <: CrossableProject[A]](delegate: A, version: String) = { 15 | val project: ProjectDefinition[ProjectReference] = delegate.project 16 | // https://github.com/sbt/sbt/issues/1861 17 | // this isn't a complete fix, but most things aren't 18 | val newId = id(project.id, version) 19 | val newBase = 20 | if (project.base == file(".")) file(".cross") / newId 21 | else project.base 22 | val newProject = Project(newId, newBase) 23 | .aggregate(project.aggregate: _*) 24 | .dependsOn(project.dependencies: _*) 25 | .enablePlugins(project.plugins) 26 | .configs(project.configurations: _*) 27 | .settings(project.settings) 28 | .settings( 29 | baseDirectory := project.base.getAbsoluteFile, 30 | originalName := originalName.?.value.getOrElse(project.id), 31 | target := target.value / s"$name-${major(version)}") 32 | delegate.withProject(newProject) 33 | } 34 | def apply(project: LocalProject, version: String) = project.copy(id(project.project, version)) 35 | } 36 | 37 | object DefaultAxisPlugin extends AutoPlugin { 38 | object autoImport { 39 | val originalName = SettingKey[String]("original-name") 40 | } 41 | 42 | import autoImport._ 43 | 44 | override val trigger = allRequirements 45 | 46 | override val requires = CorePlugin 47 | 48 | override val projectSettings = Seq( 49 | name := originalName.?.value.getOrElse(name.value)) 50 | 51 | } 52 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/LibraryVersionAxis.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import org.apache.commons.lang3.StringUtils 4 | import sbt.Keys._ 5 | import sbt._ 6 | import sbt.plugins.JvmPlugin 7 | 8 | class LibraryVersionAxis(protected[this] val name: String, settingKey: SettingKey[String], versionFn: String => String) extends DefaultAxis { 9 | import LibraryVersionAxis._ 10 | 11 | protected[this] def major(version: String) = versionFn(version) 12 | 13 | override def apply[A <: CrossableProject[A]](delegate: A, version: String) = { 14 | val newDelegate = super.apply(delegate, version) 15 | newDelegate.withProject(newDelegate.project.settings( 16 | extraDirectories ++= (sourceDirectory.value +: extraDirectories.value).map(_ / s"$name-${major(version)}"), 17 | settingKey := version, 18 | Keys.version := { 19 | if (Keys.version.value.endsWith("-SNAPSHOT")) { 20 | s"${Keys.version.value.replace("-SNAPSHOT", "")}-${major(version)}-SNAPSHOT" 21 | } else { 22 | s"${Keys.version.value}-${major(version)}" 23 | } 24 | })) 25 | } 26 | } 27 | 28 | object LibraryVersionAxis { 29 | val majorVersion = (version: String) => version.indexOf('.') match { 30 | case StringUtils.INDEX_NOT_FOUND => version 31 | case i => version.take(i) 32 | } 33 | 34 | val minorVersion = (version: String) => StringUtils.ordinalIndexOf(version, ".", 2) match { 35 | case StringUtils.INDEX_NOT_FOUND => version 36 | case i => version.take(i) 37 | } 38 | 39 | val extraDirectories = SettingKey[Seq[File]]("extra-directories") 40 | } 41 | 42 | object LibraryVersionPlugin extends AutoPlugin { 43 | object autoImport { 44 | val extraDirectories = LibraryVersionAxis.extraDirectories 45 | } 46 | import autoImport._ 47 | 48 | override val trigger = allRequirements 49 | 50 | override val requires = JvmPlugin 51 | 52 | override val globalSettings = Seq( 53 | extraDirectories := Nil) 54 | 55 | override val projectSettings = Seq(Compile, Test).flatMap { config => 56 | Seq( 57 | unmanagedSourceDirectories in config ++= extraDirectories.value.flatMap { directory => 58 | (unmanagedSourceDirectories in config).value.flatMap(Path.rebase(sourceDirectory.value, directory)(_)) 59 | }, 60 | unmanagedResourceDirectories in config ++= extraDirectories.value.flatMap { directory => 61 | (unmanagedResourceDirectories in config).value.flatMap(Path.rebase(sourceDirectory.value, directory)(_)) 62 | }) 63 | } 64 | } -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/LocalProjectDependency.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import sbt.{ ClasspathDependency, LocalProject } 4 | 5 | case class LocalProjectDependency(project: LocalProject, configurations: Option[String] = None) { 6 | def classpathDependency = ClasspathDependency(project, configurations) 7 | } 8 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/SbtCrossPlugin.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import sbt._ 4 | import scala.language.implicitConversions 5 | 6 | object SbtCrossPlugin extends AutoPlugin { 7 | 8 | object autoImport { 9 | implicit def toCrossable(project: Project): BaseProject = new BaseProject(project) 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /sbt-cross/src/main/scala/com/lucidchart/sbtcross/ScalaAxis.scala: -------------------------------------------------------------------------------- 1 | package com.lucidchart.sbtcross 2 | 3 | import sbt.librarymanagement.CrossVersion 4 | import sbt.Keys._ 5 | 6 | class ScalaAxis extends DefaultAxis { 7 | protected[this] val name = "scala" 8 | protected[this] def major(version: String) = CrossVersion.binaryScalaVersion(version) 9 | override def apply[A <: CrossableProject[A]](delegate: A, version: String) = { 10 | val newDelegate = super.apply(delegate, version) 11 | newDelegate.withProject(newDelegate.project.settings( 12 | crossTarget := target.value, 13 | scalaVersion := version)) 14 | } 15 | } 16 | 17 | object ScalaAxis extends ScalaAxis 18 | -------------------------------------------------------------------------------- /sbt-cross/version: -------------------------------------------------------------------------------- 1 | 4.0 2 | --------------------------------------------------------------------------------