Merge pull request #328 from alexarchambault/topic/develop

Switch to scalaz 7.2, some fixes / enhancements in SBT plugin
This commit is contained in:
Alexandre Archambault 2016-08-21 23:37:44 +02:00 committed by GitHub
commit 0d9a594792
18 changed files with 196 additions and 52 deletions

View File

@ -121,7 +121,10 @@ lazy val core = crossProject
.settings(mimaDefaultSettings: _*) .settings(mimaDefaultSettings: _*)
.settings( .settings(
name := "coursier", name := "coursier",
libraryDependencies += "com.lihaoyi" %%% "fastparse" % "0.3.7", libraryDependencies ++= Seq(
"org.scalaz" %%% "scalaz-core" % "7.2.5",
"com.lihaoyi" %%% "fastparse" % "0.3.7"
),
resourceGenerators.in(Compile) += { resourceGenerators.in(Compile) += {
(target, version).map { (dir, ver) => (target, version).map { (dir, ver) =>
import sys.process._ import sys.process._
@ -218,7 +221,6 @@ lazy val core = crossProject
.jvmSettings( .jvmSettings(
libraryDependencies ++= libraryDependencies ++=
Seq( Seq(
"org.scalaz" %% "scalaz-core" % "7.1.2",
"org.jsoup" % "jsoup" % "1.9.2" "org.jsoup" % "jsoup" % "1.9.2"
) ++ { ) ++ {
if (scalaVersion.value.startsWith("2.10.")) Seq() if (scalaVersion.value.startsWith("2.10.")) Seq()
@ -229,7 +231,6 @@ lazy val core = crossProject
) )
.jsSettings( .jsSettings(
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"com.github.japgolly.fork.scalaz" %%% "scalaz-core" % (if (scalaVersion.value.startsWith("2.10.")) "7.1.1" else "7.1.2"),
"org.scala-js" %%% "scalajs-dom" % "0.9.1", "org.scala-js" %%% "scalajs-dom" % "0.9.1",
"be.doeraene" %%% "scalajs-jquery" % "0.9.0" "be.doeraene" %%% "scalajs-jquery" % "0.9.0"
) )
@ -278,7 +279,7 @@ lazy val cache = project
.settings( .settings(
name := "coursier-cache", name := "coursier-cache",
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"org.scalaz" %% "scalaz-concurrent" % "7.1.2" "org.scalaz" %% "scalaz-concurrent" % "7.2.5"
), ),
previousArtifacts := Set("com.github.alexarchambault" %% moduleName.value % binaryCompatibilityVersion), previousArtifacts := Set("com.github.alexarchambault" %% moduleName.value % binaryCompatibilityVersion),
binaryIssueFilters ++= { binaryIssueFilters ++= {

View File

@ -32,16 +32,16 @@ object CacheParse {
} }
val validatedUrl = try { val validatedUrl = try {
url.map(Cache.url).validation url.map(Cache.url)
} catch { } catch {
case e: MalformedURLException => case e: MalformedURLException =>
("Error parsing URL " + url + Option(e.getMessage).fold("")(" (" + _ + ")")).failure ("Error parsing URL " + url + Option(e.getMessage).fold("")(" (" + _ + ")")).left
} }
validatedUrl.flatMap { url => validatedUrl.flatMap { url =>
Option(url.getUserInfo) match { Option(url.getUserInfo) match {
case None => case None =>
repo.validation repo
case Some(userInfo) => case Some(userInfo) =>
userInfo.split(":", 2) match { userInfo.split(":", 2) match {
case Array(user, password) => case Array(user, password) =>
@ -52,7 +52,7 @@ object CacheParse {
url.getFile url.getFile
).toString ).toString
repo.validation.map { repo.map {
case m: MavenRepository => case m: MavenRepository =>
m.copy( m.copy(
root = baseUrl, root = baseUrl,
@ -73,10 +73,10 @@ object CacheParse {
} }
case _ => case _ =>
s"No password found in user info of URL $url".failure s"No password found in user info of URL $url".left
} }
} }
} }.validation
} }
def repositories(l: Seq[String]): ValidationNel[String, Seq[Repository]] = def repositories(l: Seq[String]): ValidationNel[String, Seq[Repository]] =
@ -85,25 +85,25 @@ object CacheParse {
} }
def cachePolicies(s: String): ValidationNel[String, Seq[CachePolicy]] = def cachePolicies(s: String): ValidationNel[String, Seq[CachePolicy]] =
s.split(',').toVector.traverseU { s.split(',').toVector.traverseM[({ type L[X] = ValidationNel[String, X] })#L, CachePolicy] {
case "offline" => case "offline" =>
Seq(CachePolicy.LocalOnly).successNel Vector(CachePolicy.LocalOnly).successNel
case "update-local-changing" => case "update-local-changing" =>
Seq(CachePolicy.LocalUpdateChanging).successNel Vector(CachePolicy.LocalUpdateChanging).successNel
case "update-local" => case "update-local" =>
Seq(CachePolicy.LocalUpdate).successNel Vector(CachePolicy.LocalUpdate).successNel
case "update-changing" => case "update-changing" =>
Seq(CachePolicy.UpdateChanging).successNel Vector(CachePolicy.UpdateChanging).successNel
case "update" => case "update" =>
Seq(CachePolicy.Update).successNel Vector(CachePolicy.Update).successNel
case "missing" => case "missing" =>
Seq(CachePolicy.FetchMissing).successNel Vector(CachePolicy.FetchMissing).successNel
case "force" => case "force" =>
Seq(CachePolicy.ForceDownload).successNel Vector(CachePolicy.ForceDownload).successNel
case "default" => case "default" =>
Seq(CachePolicy.LocalOnly, CachePolicy.FetchMissing).successNel Vector(CachePolicy.LocalOnly, CachePolicy.FetchMissing).successNel
case other => case other =>
s"Unrecognized mode: $other".failureNel s"Unrecognized mode: $other".failureNel
}.map(_.flatten) }
} }

View File

@ -103,7 +103,7 @@ class Helper(
case Success(cp) => cp case Success(cp) => cp
case Failure(errors) => case Failure(errors) =>
prematureExit( prematureExit(
s"Error parsing modes:\n${errors.list.map(" "+_).mkString("\n")}" s"Error parsing modes:\n${errors.list.toList.map(" "+_).mkString("\n")}"
) )
} }
@ -155,7 +155,7 @@ class Helper(
sourceRepositories ++ repos sourceRepositories ++ repos
case Failure(errors) => case Failure(errors) =>
prematureExit( prematureExit(
s"Error with repositories:\n${errors.list.map(" "+_).mkString("\n")}" s"Error with repositories:\n${errors.list.toList.map(" "+_).mkString("\n")}"
) )
} }

View File

@ -12,17 +12,17 @@ case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty]) {
def substituteProperties(properties: Map[String, String]): String \/ Pattern = { def substituteProperties(properties: Map[String, String]): String \/ Pattern = {
val validation = chunks.toVector.traverseU { val validation = chunks.toVector.traverseM[({ type L[X] = ValidationNel[String, X] })#L, Pattern.Chunk] {
case ChunkOrProperty.Prop(name, alternativesOpt) => case ChunkOrProperty.Prop(name, alternativesOpt) =>
properties.get(name) match { properties.get(name) match {
case Some(value) => case Some(value) =>
Seq(Pattern.Chunk.Const(value)).successNel Vector(Pattern.Chunk.Const(value)).successNel
case None => case None =>
alternativesOpt match { alternativesOpt match {
case Some(alt) => case Some(alt) =>
PropertiesPattern(alt) PropertiesPattern(alt)
.substituteProperties(properties) .substituteProperties(properties)
.map(_.chunks) .map(_.chunks.toVector)
.validation .validation
.toValidationNel .toValidationNel
case None => case None =>
@ -33,17 +33,17 @@ case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty]) {
case ChunkOrProperty.Opt(l @ _*) => case ChunkOrProperty.Opt(l @ _*) =>
PropertiesPattern(l) PropertiesPattern(l)
.substituteProperties(properties) .substituteProperties(properties)
.map(l => Seq(Pattern.Chunk.Opt(l.chunks: _*))) .map(l => Vector(Pattern.Chunk.Opt(l.chunks: _*)))
.validation .validation
.toValidationNel .toValidationNel
case ChunkOrProperty.Var(name) => case ChunkOrProperty.Var(name) =>
Seq(Pattern.Chunk.Var(name)).successNel Vector(Pattern.Chunk.Var(name)).successNel
case ChunkOrProperty.Const(value) => case ChunkOrProperty.Const(value) =>
Seq(Pattern.Chunk.Const(value)).successNel Vector(Pattern.Chunk.Const(value)).successNel
}.map(_.flatten).map(Pattern(_)) }.map(Pattern(_))
validation.disjunction.leftMap { notFoundProps => validation.disjunction.leftMap { notFoundProps =>
s"Property(ies) not found: ${notFoundProps.toList.mkString(", ")}" s"Property(ies) not found: ${notFoundProps.toList.mkString(", ")}"

View File

@ -21,6 +21,7 @@ object CoursierPlugin extends AutoPlugin {
val mavenProfiles = Keys.mavenProfiles val mavenProfiles = Keys.mavenProfiles
val coursierSourceRepositories = Keys.coursierSourceRepositories val coursierSourceRepositories = Keys.coursierSourceRepositories
val coursierResolvers = Keys.coursierResolvers val coursierResolvers = Keys.coursierResolvers
val coursierRecursiveResolvers = Keys.coursierRecursiveResolvers
val coursierSbtResolvers = Keys.coursierSbtResolvers val coursierSbtResolvers = Keys.coursierSbtResolvers
val coursierUseSbtCredentials = Keys.coursierUseSbtCredentials val coursierUseSbtCredentials = Keys.coursierUseSbtCredentials
val coursierCredentials = Keys.coursierCredentials val coursierCredentials = Keys.coursierCredentials
@ -68,6 +69,7 @@ object CoursierPlugin extends AutoPlugin {
mavenProfiles := Set.empty, mavenProfiles := Set.empty,
coursierSourceRepositories := Nil, coursierSourceRepositories := Nil,
coursierResolvers <<= Tasks.coursierResolversTask, coursierResolvers <<= Tasks.coursierResolversTask,
coursierRecursiveResolvers <<= Tasks.coursierRecursiveResolversTask,
coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers, coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers,
coursierUseSbtCredentials := false, coursierUseSbtCredentials := false,
coursierCredentials := Map.empty, coursierCredentials := Map.empty,

View File

@ -24,6 +24,7 @@ object Keys {
val coursierSourceRepositories = SettingKey[Seq[File]]("coursier-source-repositories") val coursierSourceRepositories = SettingKey[Seq[File]]("coursier-source-repositories")
val coursierResolvers = TaskKey[Seq[Resolver]]("coursier-resolvers") val coursierResolvers = TaskKey[Seq[Resolver]]("coursier-resolvers")
val coursierRecursiveResolvers = TaskKey[Seq[Resolver]]("coursier-recursive-resolvers", "Resolvers of the current project, plus those of all from its inter-dependency projects")
val coursierSbtResolvers = TaskKey[Seq[Resolver]]("coursier-sbt-resolvers") val coursierSbtResolvers = TaskKey[Seq[Resolver]]("coursier-sbt-resolvers")
val coursierUseSbtCredentials = SettingKey[Boolean]("coursier-use-sbt-credentials") val coursierUseSbtCredentials = SettingKey[Boolean]("coursier-use-sbt-credentials")
val coursierCredentials = TaskKey[Map[String, Credentials]]("coursier-credentials") val coursierCredentials = TaskKey[Map[String, Credentials]]("coursier-credentials")

View File

@ -27,6 +27,29 @@ import scalaz.concurrent.{ Task, Strategy }
object Tasks { object Tasks {
def allRecursiveInterDependencies(state: sbt.State, projectRef: sbt.ProjectRef) = {
def dependencies(map: Map[String, Seq[String]], id: String): Set[String] = {
def helper(map: Map[String, Seq[String]], acc: Set[String]): Set[String] =
if (acc.exists(map.contains)) {
val (kept, rem) = map.partition { case (k, _) => acc(k) }
helper(rem, acc ++ kept.valuesIterator.flatten)
} else
acc
helper(map - id, map.getOrElse(id, Nil).toSet)
}
val allProjectsDeps =
for (p <- structure(state).allProjects)
yield p.id -> p.dependencies.map(_.project.project)
val deps = dependencies(allProjectsDeps.toMap, projectRef.project)
structure(state).allProjectRefs.filter(p => deps(p.project))
}
def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =
( (
externalResolvers, externalResolvers,
@ -46,13 +69,30 @@ object Tasks {
} }
} }
def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =
(
sbt.Keys.state,
sbt.Keys.thisProjectRef
).flatMap { (state, projectRef) =>
val projects = allRecursiveInterDependencies(state, projectRef)
coursierResolvers
.forAllProjects(state, projectRef +: projects)
.map(_.values.toVector.flatten)
}
def coursierFallbackDependenciesTask: Def.Initialize[sbt.Task[Seq[(Module, String, URL, Boolean)]]] = def coursierFallbackDependenciesTask: Def.Initialize[sbt.Task[Seq[(Module, String, URL, Boolean)]]] =
( (
sbt.Keys.state, sbt.Keys.state,
sbt.Keys.thisProjectRef sbt.Keys.thisProjectRef
).flatMap { (state, projectRef) => ).flatMap { (state, projectRef) =>
val allDependenciesTask = allDependencies.in(projectRef).get(state) val projects = allRecursiveInterDependencies(state, projectRef)
val allDependenciesTask = allDependencies
.forAllProjects(state, projectRef +: projects)
.map(_.values.toVector.flatten)
for { for {
allDependencies <- allDependenciesTask allDependencies <- allDependenciesTask
@ -103,25 +143,7 @@ object Tasks {
sbt.Keys.thisProjectRef sbt.Keys.thisProjectRef
).flatMap { (state, projectRef) => ).flatMap { (state, projectRef) =>
def dependencies(map: Map[String, Seq[String]], id: String): Set[String] = { val projects = allRecursiveInterDependencies(state, projectRef)
def helper(map: Map[String, Seq[String]], acc: Set[String]): Set[String] =
if (acc.exists(map.contains)) {
val (kept, rem) = map.partition { case (k, _) => acc(k) }
helper(rem, acc ++ kept.valuesIterator.flatten)
} else
acc
helper(map - id, map.getOrElse(id, Nil).toSet)
}
val allProjectsDeps =
for (p <- structure(state).allProjects)
yield p.id -> p.dependencies.map(_.project.project)
val deps = dependencies(allProjectsDeps.toMap, projectRef.project)
val projects = structure(state).allProjectRefs.filter(p => deps(p.project))
coursierProject.forAllProjects(state, projects).map(_.values.toVector) coursierProject.forAllProjects(state, projects).map(_.values.toVector)
} }
@ -374,7 +396,7 @@ object Tasks {
if (sbtClassifiers) if (sbtClassifiers)
coursierSbtResolvers.value coursierSbtResolvers.value
else else
coursierResolvers.value coursierRecursiveResolvers.value.distinct
val sourceRepositories = coursierSourceRepositories.value.map { dir => val sourceRepositories = coursierSourceRepositories.value.map { dir =>
// FIXME Don't hardcode this path? // FIXME Don't hardcode this path?

View File

@ -0,0 +1,6 @@
case class A(msg: String)
object A {
def default = A("OK")
}

View File

@ -0,0 +1,9 @@
import java.io.File
import java.nio.file.Files
object Main extends App {
val msg = shapeless.Generic[A].to(A.default).head
Files.write(new File("output").toPath, msg.getBytes("UTF-8"))
}

View File

@ -0,0 +1,26 @@
lazy val a = project
.settings(sharedSettings)
.settings(
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.234" from "https://oss.sonatype.org/content/repositories/releases/com/chuusai/shapeless_2.11/2.3.1/shapeless_2.11-2.3.1.jar"
)
lazy val b = project
.dependsOn(a)
.settings(sharedSettings)
lazy val root = project
.in(file("."))
.aggregate(a, b)
.settings(sharedSettings)
lazy val sharedSettings = Seq(
scalaVersion := "2.11.8",
coursierCachePolicies := {
if (sys.props("os.name").startsWith("Windows"))
coursierCachePolicies.value
else
Seq(coursier.CachePolicy.ForceDownload)
}
)

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,3 @@
$ delete output
> b/run
$ exists output

View File

@ -0,0 +1,6 @@
case class A(msg: String)
object A {
def default = A("OK")
}

View File

@ -0,0 +1,14 @@
import java.io.File
import java.nio.file.Files
import scalaz.stream._
import scalaz.concurrent.Task
object Main extends App {
val pch = Process.constant((i:Int) => Task.now(())).take(3)
val count = Process.constant(1).toSource.to(pch).runLog.run.size
assert(count == 3)
Files.write(new File("output").toPath, A.default.msg.getBytes("UTF-8"))
}

View File

@ -0,0 +1,30 @@
lazy val a = project
.settings(sharedSettings)
.settings(
resolvers += "Scalaz Bintray Repo" at "https://dl.bintray.com/scalaz/releases"
)
lazy val b = project
.dependsOn(a)
.settings(sharedSettings)
.settings(
// resolver added in inter-project dependency only - should still be fine
libraryDependencies += "org.scalaz.stream" %% "scalaz-stream" % "0.7.1a"
)
lazy val root = project
.in(file("."))
.aggregate(a, b)
.settings(sharedSettings)
lazy val sharedSettings = Seq(
scalaVersion := "2.11.8",
coursierCachePolicies := {
if (sys.props("os.name").startsWith("Windows"))
coursierCachePolicies.value
else
Seq(coursier.CachePolicy.ForceDownload)
}
)

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,3 @@
$ delete output
> b/run
$ exists output

View File

@ -4,6 +4,5 @@ com.lihaoyi:sourcecode_2.11:0.1.1:default
io.get-coursier:coursier_2.11:1.0.0-SNAPSHOT:compile io.get-coursier:coursier_2.11:1.0.0-SNAPSHOT:compile
org.jsoup:jsoup:1.9.2:default org.jsoup:jsoup:1.9.2:default
org.scala-lang:scala-library:2.11.8:default org.scala-lang:scala-library:2.11.8:default
org.scala-lang.modules:scala-parser-combinators_2.11:1.0.4:default
org.scala-lang.modules:scala-xml_2.11:1.0.5:default org.scala-lang.modules:scala-xml_2.11:1.0.5:default
org.scalaz:scalaz-core_2.11:7.1.2:default org.scalaz:scalaz-core_2.11:7.2.5:default