summaryrefslogtreecommitdiff
path: root/scalalib/src/mill/scalalib/Dep.scala
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2018-08-05 23:23:12 +0900
committerLi Haoyi <haoyi.sg@gmail.com>2018-08-05 22:23:12 +0800
commitb9824967392e4b674881e5dcec4c4fbb05e6cd9b (patch)
tree40c67dff4ffb26f085ef52b1ec3e2341f33d27be /scalalib/src/mill/scalalib/Dep.scala
parent66c133a2ff58823c43ddfa7643fb74b8cf2bd0a6 (diff)
downloadmill-b9824967392e4b674881e5dcec4c4fbb05e6cd9b.tar.gz
mill-b9824967392e4b674881e5dcec4c4fbb05e6cd9b.tar.bz2
mill-b9824967392e4b674881e5dcec4c4fbb05e6cd9b.zip
Add support for Dotty projects (#397)
* Abstract over the scala compiler organization * Support using a locally published compiler Publishing locally with sbt means publishing ivy-style, which uses a different naming convention than maven, we now handle both cases. * Add minimal support for Dotty projects * Rewrite scalalib.Dep, introduce scalalib.CrossVersion Instead of Dep being a trait with three cases (Java/Scala/Point), it is now a case class where the cross field is an instance of the CrossVersion trait which has three cases (Constant/Binary/Full). This is more versatile since it allows for non-empty constant suffixes which will be used to implement withDottyCompat in the next commit. It's also a cleaner separation of concerns. We also deduplicate various pieces of codes that computed the artifact name: this is now always handled in Dep and CrossVersion. * Add simple way to use Scala 2 deps in a Dotty project This is similar to the withDottyCompat method in the sbt-dotty plugin. * Turn off the Dotty test on Java >= 9
Diffstat (limited to 'scalalib/src/mill/scalalib/Dep.scala')
-rw-r--r--scalalib/src/mill/scalalib/Dep.scala148
1 files changed, 94 insertions, 54 deletions
diff --git a/scalalib/src/mill/scalalib/Dep.scala b/scalalib/src/mill/scalalib/Dep.scala
index 9719bd2d..b419462c 100644
--- a/scalalib/src/mill/scalalib/Dep.scala
+++ b/scalalib/src/mill/scalalib/Dep.scala
@@ -1,32 +1,60 @@
package mill.scalalib
import mill.util.JsonFormatters._
import upickle.default.{macroRW, ReadWriter => RW}
-sealed trait Dep {
- def configure(attributes: coursier.Attributes): Dep
- def force: Boolean
- def forceVersion(): Dep = this match {
- case dep : Dep.Java => dep.copy(force = true)
- case dep : Dep.Scala => dep.copy(force = true)
- case dep : Dep.Point => dep.copy(force = true)
- }
- def exclude(exclusions: (String, String)*): Dep = this match {
- case dep : Dep.Java => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
- case dep : Dep.Scala => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
- case dep : Dep.Point => dep.copy(dep = dep.dep.copy(exclusions = dep.dep.exclusions ++ exclusions))
+
+import CrossVersion._
+
+case class Dep(dep: coursier.Dependency, cross: CrossVersion, force: Boolean) {
+ import Dep.isDotty
+
+ def artifactName(binaryVersion: String, fullVersion: String, platformSuffix: String) = {
+ val suffix = cross.suffixString(binaryVersion, fullVersion, platformSuffix)
+ dep.module.name + suffix
}
+ def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
+ def forceVersion(): Dep = copy(force = true)
+ def exclude(exclusions: (String, String)*) = copy(dep = dep.copy(exclusions = dep.exclusions ++ exclusions))
def excludeOrg(organizations: String*): Dep = exclude(organizations.map(_ -> "*"): _*)
def excludeName(names: String*): Dep = exclude(names.map("*" -> _): _*)
- def withConfiguration(configuration: String): Dep = this match {
- case dep : Dep.Java => dep.copy(dep = dep.dep.copy(configuration = configuration))
- case dep : Dep.Scala => dep.copy(dep = dep.dep.copy(configuration = configuration))
- case dep : Dep.Point => dep.copy(dep = dep.dep.copy(configuration = configuration))
- }
+ def toDependency(binaryVersion: String, fullVersion: String, platformSuffix: String) =
+ dep.copy(module = dep.module.copy(name = artifactName(binaryVersion, fullVersion, platformSuffix)))
+ def withConfiguration(configuration: String): Dep = copy(dep = dep.copy(configuration = configuration))
+
+ /**
+ * If scalaVersion is a Dotty version, replace the cross-version suffix
+ * by the Scala 2.x version that the Dotty version is retro-compatible with,
+ * otherwise do nothing.
+ *
+ * This setting is useful when your build contains dependencies that have only
+ * been published with Scala 2.x, if you have:
+ * {{{
+ * def ivyDeps = Agg(ivy"a::b:c")
+ * }}}
+ * you can replace it by:
+ * {{{
+ * def ivyDeps = Agg(ivy"a::b:c".withDottyCompat(scalaVersion()))
+ * }}}
+ * This will have no effect when compiling with Scala 2.x, but when compiling
+ * with Dotty this will change the cross-version to a Scala 2.x one. This
+ * works because Dotty is currently retro-compatible with Scala 2.x.
+ */
+ def withDottyCompat(scalaVersion: String): Dep =
+ cross match {
+ case cross: Binary if isDotty(scalaVersion) =>
+ copy(cross = Constant(value = "_2.12", platformed = cross.platformed))
+ case _ =>
+ this
+ }
}
-object Dep{
+
+object Dep {
val DefaultConfiguration = "default(compile)"
- implicit def parse(signature: String) = {
+ def isDotty(scalaVersion: String) =
+ scalaVersion.startsWith("0.")
+
+ implicit def parse(signature: String): Dep = {
val parts = signature.split(';')
val module = parts.head
val attributes = parts.tail.foldLeft(coursier.Attributes()) { (as, s) =>
@@ -37,48 +65,60 @@ object Dep{
}
}
(module.split(':') match {
- case Array(a, b, c) => Dep.Java(a, b, c, cross = false, force = false)
- case Array(a, b, "", c) => Dep.Java(a, b, c, cross = true, force = false)
- case Array(a, "", b, c) => Dep.Scala(a, b, c, cross = false, force = false)
- case Array(a, "", b, "", c) => Dep.Scala(a, b, c, cross = true, force = false)
- case Array(a, "", "", b, c) => Dep.Point(a, b, c, cross = false, force = false)
- case Array(a, "", "", b, "", c) => Dep.Point(a, b, c, cross = true, force = false)
+ case Array(a, b, c) => Dep(a, b, c, cross = empty(platformed = false))
+ case Array(a, b, "", c) => Dep(a, b, c, cross = empty(platformed = true))
+ case Array(a, "", b, c) => Dep(a, b, c, cross = Binary(platformed = false))
+ case Array(a, "", b, "", c) => Dep(a, b, c, cross = Binary(platformed = true))
+ case Array(a, "", "", b, c) => Dep(a, b, c, cross = Full(platformed = false))
+ case Array(a, "", "", b, "", c) => Dep(a, b, c, cross = Full(platformed = true))
case _ => throw new Exception(s"Unable to parse signature: [$signature]")
}).configure(attributes = attributes)
}
- def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
- this(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross)
- }
- case class Java(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
- def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
+ def apply(org: String, name: String, version: String, cross: CrossVersion, force: Boolean = false): Dep = {
+ apply(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
}
- object Java{
- implicit def rw: RW[Java] = macroRW
- def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
- Java(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
+ implicit def rw: RW[Dep] = macroRW
+}
+
+sealed trait CrossVersion {
+ /** If true, the cross-version suffix should start with a platform suffix if it exists */
+ def platformed: Boolean
+
+ def isBinary: Boolean =
+ this.isInstanceOf[Binary]
+ def isConstant: Boolean =
+ this.isInstanceOf[Constant]
+ def isFull: Boolean =
+ this.isInstanceOf[Full]
+
+ /** The string that should be appended to the module name to get the artifact name */
+ def suffixString(binaryVersion: String, fullVersion: String, platformSuffix: String): String = {
+ val firstSuffix = if (platformed) platformSuffix else ""
+ this match {
+ case cross: Constant =>
+ s"${firstSuffix}${cross.value}"
+ case cross: Binary =>
+ s"${firstSuffix}_${binaryVersion}"
+ case cross: Full =>
+ s"${firstSuffix}_${fullVersion}"
}
}
- implicit def default(dep: coursier.Dependency): Dep = new Java(dep, false, false)
- def apply(dep: coursier.Dependency, cross: Boolean) = Scala(dep, cross, false)
- case class Scala(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
- def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
- }
- object Scala{
- implicit def rw: RW[Scala] = macroRW
- def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
- Scala(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
- }
+}
+object CrossVersion {
+ case class Constant(value: String, platformed: Boolean) extends CrossVersion
+ object Constant {
+ implicit def rw: RW[Constant] = macroRW
}
- case class Point(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
- def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
+ case class Binary(platformed: Boolean) extends CrossVersion
+ object Binary {
+ implicit def rw: RW[Binary] = macroRW
}
- object Point{
- implicit def rw: RW[Point] = macroRW
- def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
- Point(coursier.Dependency(coursier.Module(org, name), version, DefaultConfiguration), cross, force)
- }
+ case class Full(platformed: Boolean) extends CrossVersion
+ object Full {
+ implicit def rw: RW[Full] = macroRW
}
- implicit def rw = RW.merge[Dep](
- Java.rw, Scala.rw, Point.rw
- )
+
+ def empty(platformed: Boolean) = Constant(value = "", platformed)
+
+ implicit def rw: RW[CrossVersion] = RW.merge(Constant.rw, Binary.rw, Full.rw)
}