Skip to content

Commit

Permalink
basic support for version pinning (used by default for scala-library/…
Browse files Browse the repository at this point in the history
…compiler) and for typelevel scala
  • Loading branch information
lihaoyi committed Apr 7, 2018
1 parent 26865c6 commit b9e9b68
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 55 deletions.
62 changes: 33 additions & 29 deletions scalalib/src/mill/scalalib/Dep.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@ import mill.util.JsonFormatters._
import upickle.default.{macroRW, ReadWriter => RW}
sealed trait Dep {
def configure(attributes: coursier.Attributes): Dep
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))
}
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))
}
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 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))
}
}
object Dep{

Expand All @@ -31,45 +35,45 @@ object Dep{
}
}
(module.split(':') match {
case Array(a, b, c) => Dep.Java(a, b, c, cross = false)
case Array(a, b, "", c) => Dep.Java(a, b, c, cross = true)
case Array(a, "", b, c) => Dep.Scala(a, b, c, cross = false)
case Array(a, "", b, "", c) => Dep.Scala(a, b, c, cross = true)
case Array(a, "", "", b, c) => Dep.Point(a, b, c, cross = false)
case Array(a, "", "", b, "", c) => Dep.Point(a, b, c, cross = true)
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 _ => 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), cross)
}
case class Java(dep: coursier.Dependency, cross: Boolean) extends Dep {
case class Java(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
}
object Java{
implicit def rw: RW[Java] = macroRW
def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
Java(coursier.Dependency(coursier.Module(org, name), version), cross)
def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
Java(coursier.Dependency(coursier.Module(org, name), version), cross, force)
}
}
implicit def default(dep: coursier.Dependency): Dep = new Java(dep, false)
def apply(dep: coursier.Dependency, cross: Boolean) = Scala(dep, cross)
case class Scala(dep: coursier.Dependency, cross: Boolean) extends Dep {
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): Dep = {
Scala(coursier.Dependency(coursier.Module(org, name), version), cross)
def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
Scala(coursier.Dependency(coursier.Module(org, name), version), cross, force)
}
}
case class Point(dep: coursier.Dependency, cross: Boolean) extends Dep {
case class Point(dep: coursier.Dependency, cross: Boolean, force: Boolean) extends Dep {
def configure(attributes: coursier.Attributes): Dep = copy(dep = dep.copy(attributes = attributes))
}
object Point{
implicit def rw: RW[Point] = macroRW
def apply(org: String, name: String, version: String, cross: Boolean): Dep = {
Point(coursier.Dependency(coursier.Module(org, name), version), cross)
def apply(org: String, name: String, version: String, cross: Boolean, force: Boolean): Dep = {
Point(coursier.Dependency(coursier.Module(org, name), version), cross, force)
}
}
implicit def rw = RW.merge[Dep](
Expand Down
49 changes: 36 additions & 13 deletions scalalib/src/mill/scalalib/Lib.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ object Lib{

def depToDependency(dep: Dep, scalaVersion: String, platformSuffix: String = ""): Dependency =
dep match {
case Dep.Java(dep, cross) =>
case Dep.Java(dep, cross, force) =>
dep.copy(
module = dep.module.copy(
name =
dep.module.name +
(if (!cross) "" else platformSuffix)
)
)
case Dep.Scala(dep, cross) =>
case Dep.Scala(dep, cross, force) =>
dep.copy(
module = dep.module.copy(
name =
Expand All @@ -53,7 +53,7 @@ object Lib{
"_" + scalaBinaryVersion(scalaVersion)
)
)
case Dep.Point(dep, cross) =>
case Dep.Point(dep, cross, force) =>
dep.copy(
module = dep.module.copy(
name =
Expand All @@ -65,7 +65,30 @@ object Lib{
}


def resolveDependenciesMetadata(repositories: Seq[Repository],
scalaVersion: String,
deps: TraversableOnce[Dep],
platformSuffix: String = "",
mapDependencies: Option[Dependency => Dependency] = None) = {
val depSeq = deps.toSeq
val flattened = depSeq.map(depToDependency(_, scalaVersion, platformSuffix))

val forceVersions = depSeq.filter(_.force)
.map(depToDependency(_, scalaVersion, platformSuffix))
.map(mapDependencies.getOrElse(identity[Dependency](_)))
.map{d => d.module -> d.version}
.toMap

val start = Resolution(
flattened.map(mapDependencies.getOrElse(identity[Dependency](_))).toSet,
forceVersions = forceVersions,
mapDependencies = mapDependencies
)

val fetch = Fetch.from(repositories, Cache.fetch())
val resolution = start.process.run(fetch).unsafePerformSync
(flattened, resolution)
}
/**
* Resolve dependencies using Coursier.
*
Expand All @@ -77,13 +100,12 @@ object Lib{
scalaVersion: String,
deps: TraversableOnce[Dep],
platformSuffix: String = "",
sources: Boolean = false): Result[Agg[PathRef]] = {
sources: Boolean = false,
mapDependencies: Option[Dependency => Dependency] = None): Result[Agg[PathRef]] = {

val flattened = deps.map(depToDependency(_, scalaVersion, platformSuffix)).toSet
val start = Resolution(flattened)

val fetch = Fetch.from(repositories, Cache.fetch())
val resolution = start.process.run(fetch).unsafePerformSync
val (_, resolution) = resolveDependenciesMetadata(
repositories, scalaVersion, deps, platformSuffix, mapDependencies
)
val errs = resolution.metadataErrors
if(errs.nonEmpty) {
val header =
Expand Down Expand Up @@ -130,16 +152,17 @@ object Lib{
}
}
def scalaCompilerIvyDeps(scalaVersion: String) = Agg[Dep](
ivy"org.scala-lang:scala-compiler:$scalaVersion",
ivy"org.scala-lang:scala-reflect:$scalaVersion"
ivy"org.scala-lang:scala-compiler:$scalaVersion".forceVersion(),
ivy"org.scala-lang:scala-reflect:$scalaVersion".forceVersion()
)
def scalaRuntimeIvyDeps(scalaVersion: String) = Agg[Dep](
ivy"org.scala-lang:scala-library:$scalaVersion"
ivy"org.scala-lang:scala-library:$scalaVersion".forceVersion()
)
def compilerBridgeIvyDep(scalaVersion: String) =
Dep.Point(
coursier.Dependency(coursier.Module("com.lihaoyi", "mill-bridge"), "0.1", transitive = false),
cross = false
cross = false,
force = false
)

}
27 changes: 17 additions & 10 deletions scalalib/src/mill/scalalib/ScalaModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package mill
package scalalib

import ammonite.ops._
import coursier.Repository
import coursier.{Dependency, Repository}
import mill.define.Task
import mill.define.TaskModule
import mill.eval.{PathRef, Result}
Expand Down Expand Up @@ -86,13 +86,16 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
)().flatten
}

def mapDependencies(d: coursier.Dependency) = d

def resolveDeps(deps: Task[Agg[Dep]], sources: Boolean = false) = T.task{
resolveDependencies(
repositories,
scalaVersion(),
deps(),
platformSuffix(),
sources
sources,
mapDependencies = Some(mapDependencies)
)
}

Expand Down Expand Up @@ -263,12 +266,9 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
}

def ivyDepsTree(inverse: Boolean = false) = T.command {
import coursier.{Cache, Fetch, Resolution}

val flattened = ivyDeps().map(depToDependency(_, scalaVersion(), platformSuffix())).toSeq
val start = Resolution(flattened.toSet)
val fetch = Fetch.from(repositories, Cache.fetch())
val resolution = start.process.run(fetch).unsafePerformSync
val (flattened, resolution) = Lib.resolveDependenciesMetadata(
repositories, scalaVersion(), ivyDeps(), platformSuffix(), Some(mapDependencies)
)

println(coursier.util.Print.dependencyTree(flattened, resolution,
printExclusions = false, reverse = inverse))
Expand Down Expand Up @@ -330,15 +330,22 @@ trait ScalaModule extends mill.Module with TaskModule { outer =>
}

def ammoniteReplClasspath = T{
resolveDeps(T.task{Agg(ivy"com.lihaoyi:::ammonite:1.1.0-7-33b728c")})()
localClasspath() ++
transitiveLocalClasspath() ++
unmanagedClasspath() ++
resolveDeps(T.task{
runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps() ++
Agg(ivy"com.lihaoyi:::ammonite:1.1.0-7-33b728c")
})()
}

def repl() = T.command{
if (T.ctx().log.inStream == DummyInputStream){
Result.Failure("repl needs to be run with the -i/--interactive flag")
}else{
Jvm.interactiveSubprocess(
mainClass = "ammonite.Main",
classPath = runClasspath().map(_.path) ++ ammoniteReplClasspath().map(_.path),
classPath = ammoniteReplClasspath().map(_.path),
mainArgs = Nil,
workingDir = pwd
)
Expand Down
6 changes: 3 additions & 3 deletions scalalib/src/mill/scalalib/publish/settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ object Artifact {
scalaFull: String,
scalaBin: String): Dependency = {
dep match {
case Dep.Java(dep, cross) =>
case Dep.Java(dep, cross, force) =>
Dependency(
Artifact(dep.module.organization, dep.module.name, dep.version),
Scope.Compile,
if (dep.configuration == "" ) None else Some(dep.configuration),
dep.exclusions.toList
)
case Dep.Scala(dep, cross) =>
case Dep.Scala(dep, cross, force) =>
Dependency(
Artifact(
dep.module.organization,
Expand All @@ -30,7 +30,7 @@ object Artifact {
if (dep.configuration == "") None else Some(dep.configuration),
dep.exclusions.toList
)
case Dep.Point(dep, cross) =>
case Dep.Point(dep, cross, force) =>
Dependency(
Artifact(
dep.module.organization,
Expand Down
37 changes: 37 additions & 0 deletions scalalib/test/src/mill/scalalib/HelloWorldTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ object HelloWorldTests extends TestSuite {
override def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode:0.1.4")
}
}

object HelloWorldTypeLevel extends HelloBase{
object foo extends ScalaModule {
def scalaVersion = "2.11.8"
override def mapDependencies(d: coursier.Dependency) = {
val artifacts = Set("scala-library", "scala-compiler", "scala-reflect")
if (d.module.organization != "org.scala-lang" || !artifacts(d.module.name)) d
else d.copy(module = d.module.copy(organization = "org.typelevel"))
}

def ivyDeps = Agg(
ivy"com.github.julien-truffaut::monocle-macro::1.4.0"
)
def scalacPluginIvyDeps = super.scalacPluginIvyDeps() ++ Agg(
ivy"org.scalamacros:::paradise:2.1.0"
)
}
}
val resourcePath = pwd / 'scalalib / 'test / 'resources / "hello-world"

def jarMainClass(jar: JarFile): Option[String] = {
Expand Down Expand Up @@ -438,6 +456,25 @@ object HelloWorldTests extends TestSuite {
!result2.exists(_.path.last == "sourcecode_2.12-0.1.3.jar")
)
}
'typeLevel - workspaceTest(HelloWorldTypeLevel){ eval =>
val classPathsToCheck = Seq(
HelloWorldTypeLevel.foo.runClasspath,
HelloWorldTypeLevel.foo.ammoniteReplClasspath,
HelloWorldTypeLevel.foo.compileClasspath
)
for(cp <- classPathsToCheck){
val Right((result, _)) = eval.apply(cp)
assert(
// Make sure every relevant piece org.scala-lang has been substituted for org.typelevel
!result.map(_.toString).exists(x =>
x.contains("scala-lang") &&
(x.contains("scala-library") || x.contains("scala-compiler") || x.contains("scala-reflect"))
),
result.map(_.toString).exists(x => x.contains("typelevel") && x.contains("scala-library"))

)
}
}
}


Expand Down

0 comments on commit b9e9b68

Please sign in to comment.