Merge pull request #807 from coursier/topic/less-scalaz

Remove scalaz dependency from core and cache
This commit is contained in:
Alexandre Archambault 2018-03-13 12:36:58 +01:00 committed by GitHub
commit 8cf4d7a16d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 526 additions and 659 deletions

View File

@ -1,6 +1,4 @@
language: java
install:
- npm install
os:
- osx
script:
@ -18,13 +16,13 @@ matrix:
- curl https://raw.githubusercontent.com/scala-native/scala-native/v0.3.6/bin/travis_setup.sh | bash -x
services:
- docker
- env: SCALA_VERSION=2.11.11 PUBLISH=1
- env: SCALA_VERSION=2.11.12 PUBLISH=1
os: linux
jdk: oraclejdk8
sudo: required
services:
- docker
- env: SCALA_VERSION=2.10.6 PUBLISH=1
- env: SCALA_VERSION=2.10.7 PUBLISH=1
os: linux
jdk: oraclejdk8
sudo: required
@ -36,21 +34,21 @@ matrix:
- env: SCALA_VERSION=2.12.4 SBT_SHADING=1
os: linux
jdk: oraclejdk8
- env: SCALA_VERSION=2.10.6 SBT_COURSIER=1
- env: SCALA_VERSION=2.10.7 SBT_COURSIER=1
os: linux
jdk: oraclejdk8
services:
- docker
- env: SCALA_VERSION=2.10.6 SBT_SHADING=1
- env: SCALA_VERSION=2.10.7 SBT_SHADING=1
os: linux
jdk: oraclejdk8
- env: SCALA_VERSION=2.12.4 SCALA_JS=1
os: linux
jdk: oraclejdk8
- env: SCALA_VERSION=2.11.11 SCALA_JS=1
- env: SCALA_VERSION=2.11.12 SCALA_JS=1
os: linux
jdk: oraclejdk8
- env: SCALA_VERSION=2.10.6 SCALA_JS=1
- env: SCALA_VERSION=2.10.7 SCALA_JS=1
os: linux
jdk: oraclejdk8
- os: linux

View File

@ -90,14 +90,9 @@ $ sbt
## Run unit tests (JS)
The JS tests require node to be installed, and a few dependencies to have been
fetched with
```
$ npm install
```
(run from the root of the coursier sources).
The JS tests require node to be installed. They automatically run `npm install` from the root of the coursier sources if needed.
JS tests can then be run like JVM tests, like
JS tests can be run like JVM tests, like
```
$ sbt
> ++2.12.4
@ -190,4 +185,4 @@ we need to put 2) and 3) into `message`:
Typically there needs to be at least 2 minor versions between since-version and to-be-removed-version to help migration.
For example, if since version is 1.1.0, then deprecation can be removed in 1.3.0
For example, if since version is 1.1.0, then deprecation can be removed in 1.3.0

View File

@ -160,17 +160,21 @@ val start = Resolution(
Create a fetch function able to get things from a few repositories via a local cache,
```scala
import coursier.util.Task
val repositories = Seq(
Cache.ivy2Local,
MavenRepository("https://repo1.maven.org/maven2")
)
val fetch = Fetch.from(repositories, Cache.fetch())
val fetch = Fetch.from(repositories, Cache.fetch[Task]())
```
Then run the resolution per-se,
```scala
val resolution = start.process.run(fetch).unsafePerformSync
import scala.concurrent.ExecutionContext.Implicits.global
val resolution = start.process.run(fetch).unsafeRun()
```
That will fetch and use metadata.
@ -183,11 +187,11 @@ These would mean that the resolution wasn't able to get metadata about some depe
Then fetch and get local copies of the artifacts themselves (the JARs) with
```scala
import java.io.File
import scalaz.concurrent.Task
import coursier.util.Gather
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
resolution.artifacts.map(Cache.file(_).run)
).unsafePerformSync
val localArtifacts: Seq[Either[FileError, File]] = Gather[Task].gather(
resolution.artifacts.map(Cache.file[Task](_).run)
).unsafeRun()
```
@ -468,7 +472,7 @@ The resolution process will go on by giving successive `Resolution`s, until the
`start` above is only the initial state - it is far from over, as the `isDone` method on it tells,
```scala
scala> start.isDone
res4: Boolean = false
res6: Boolean = false
```
@ -507,7 +511,7 @@ scala> MavenRepository(
| "https://nexus.corp.com/content/repositories/releases",
| authentication = Some(Authentication("user", "pass"))
| )
res6: coursier.maven.MavenRepository = MavenRepository(https://nexus.corp.com/content/repositories/releases,None,true,Some(Authentication(user, *******)))
res8: coursier.maven.MavenRepository = MavenRepository(https://nexus.corp.com/content/repositories/releases,None,true,Some(Authentication(user, *******)))
```
Now that we have repositories, we're going to mix these with things from the `coursier-cache` module,
@ -517,7 +521,7 @@ Given a sequence of dependencies, designated by their `Module` (organisation and
and version (just a `String`), it gives either errors (`Seq[String]`) or metadata (`(Artifact.Source, Project)`),
wrapping the whole in a monad `F`.
```scala
val fetch = Fetch.from(repositories, Cache.fetch())
val fetch = Fetch.from(repositories, Cache.fetch[Task]())
```
The monad used by `Fetch.from` is `scalaz.concurrent.Task`, but the resolution process is not tied to a particular
@ -543,7 +547,9 @@ resolution is particularly complex, in which case `maxIterations` could be incre
Let's run the whole resolution,
```scala
val resolution = start.process.run(fetch).unsafePerformSync
import scala.concurrent.ExecutionContext.Implicits.global
val resolution = start.process.run(fetch).unsafeRun()
```
To get additional feedback during the resolution, we can give the `Cache.default` method above
@ -567,11 +573,11 @@ which are dependencies whose versions could not be unified.
Then, if all went well, we can fetch and get local copies of the artifacts themselves (the JARs) with
```scala
import java.io.File
import scalaz.concurrent.Task
import coursier.util.Gather
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
resolution.artifacts.map(Cache.file(_).run)
).unsafePerformSync
val localArtifacts: Seq[Either[FileError, File]] = Gather[Task].gather(
resolution.artifacts.map(Cache.file[Task](_).run)
).unsafeRun()
```
We're using the `Cache.file` method, that can also be given a `Logger` (for more feedback) and a custom thread pool.

View File

@ -11,23 +11,23 @@ install:
)
[System.IO.Compression.ZipFile]::ExtractToDirectory("C:\sbt-bin.zip", "C:\sbt")
}
- cmd: SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0
- cmd: SET PATH=C:\sbt\sbt\bin;%JAVA_HOME%\bin;%PATH%
- cmd: SET SBT_OPTS=-XX:MaxPermSize=2g -Xmx4g
- git submodule update --init --recursive
build_script:
- sbt ++2.11.12 clean compile coreJVM/publishLocal
- sbt ++2.10.6 clean compile
- sbt ++2.12.4 coreJVM/publishLocal cache/publishLocal cli/publishLocal extra/publishLocal sbt-shared/publishLocal
- sbt ++2.10.6 coreJVM/publishLocal cache/publishLocal extra/publishLocal sbt-shared/publishLocal
- sbt ++2.10.7 clean compile
- sbt ++2.12.4 coreJVM/publishLocal cacheJVM/publishLocal extra/publishLocal scalazJVM/publishLocal cli/publishLocal
test_script:
- ps: Start-Job -filepath .\scripts\start-it-auth-server.ps1 -ArgumentList $pwd
- ps: Start-Sleep -s 15 # wait for the first server to have downloaded its dependencies
- ps: Start-Job -filepath .\scripts\start-it-no-listing-server.ps1 -ArgumentList $pwd
- sbt ++2.12.4 testsJVM/test testsJVM/it:test # Would node be around for testsJS/test?
- sbt ++2.11.11 testsJVM/test testsJVM/it:test
- sbt ++2.10.6 testsJVM/test testsJVM/it:test
- sbt ++2.12.4 "sbt-coursier/scripted sbt-coursier/simple" sbt-coursier/publishLocal "sbt-shading/scripted sbt-shading/*" # for sbt 1.0
- sbt ++2.10.6 "sbt-coursier/scripted sbt-coursier/*" "sbt-coursier/scripted sbt-coursier-0.13/*" sbt-coursier/publishLocal "sbt-shading/scripted sbt-shading/*" "sbt-shading/scripted sbt-shading-0.13/*" # for sbt 0.13
- sbt ++2.11.12 testsJVM/test testsJVM/it:test
- sbt ++2.10.7 testsJVM/test testsJVM/it:test
- sbt ++2.12.4 "sbt-coursier/scripted sbt-coursier/simple" "sbt-shading/scripted sbt-shading/*" # for sbt 1.0
- sbt ++2.10.7 "sbt-coursier/scripted sbt-coursier/*" "sbt-coursier/scripted sbt-coursier-0.13/*" "sbt-shading/scripted sbt-shading/*" "sbt-shading/scripted sbt-shading-0.13/*" # for sbt 0.13
branches:
only:
- master

123
build.sbt
View File

@ -30,7 +30,6 @@ lazy val core = crossProject
.settings(
shared,
name := "coursier",
libs += CrossDeps.scalazCore.value,
Mima.previousArtifacts,
Mima.coreFilters
)
@ -38,23 +37,12 @@ lazy val core = crossProject
lazy val coreJvm = core.jvm
lazy val coreJs = core.js
lazy val `fetch-js` = project
.disablePlugins(ScriptedPlugin)
.enablePlugins(ScalaJSPlugin)
.dependsOn(coreJs)
.settings(
shared,
dontPublish,
coursierPrefix
)
lazy val tests = crossProject
.disablePlugins(ScriptedPlugin)
.dependsOn(core)
.jvmConfigure(_.dependsOn(cache % "test"))
.jsConfigure(_.dependsOn(`fetch-js` % "test"))
.dependsOn(core, cache % "test", scalaz)
.jsSettings(
scalaJSStage.in(Global) := FastOptStage
scalaJSStage.in(Global) := FastOptStage,
testOptions := testOptions.dependsOn(runNpmInstallIfNeeded).value
)
.configs(Integration)
.settings(
@ -92,18 +80,44 @@ lazy val paths = project
addDirectoriesSources
)
lazy val cache = project
lazy val cache = crossProject
.disablePlugins(ScriptedPlugin)
.dependsOn(coreJvm)
.dependsOn(core)
.jvmSettings(
addPathsSources
)
.jsSettings(
name := "fetch-js"
)
.settings(
shared,
Mima.previousArtifacts,
coursierPrefix,
libs += Deps.scalazConcurrent,
Mima.cacheFilters,
addPathsSources
Mima.cacheFilters
)
lazy val cacheJvm = cache.jvm
lazy val cacheJs = cache.js
lazy val scalaz = crossProject
.disablePlugins(ScriptedPlugin)
.dependsOn(cache)
.jvmSettings(
libs += Deps.scalazConcurrent
)
.jsSettings(
libs += CrossDeps.scalazCore.value
)
.settings(
name := "scalaz-interop",
shared,
Mima.previousArtifacts,
coursierPrefix
)
lazy val scalazJvm = scalaz.jvm
lazy val scalazJs = scalaz.js
lazy val bootstrap = project
.disablePlugins(ScriptedPlugin)
.settings(
@ -118,7 +132,7 @@ lazy val bootstrap = project
lazy val extra = project
.disablePlugins(ScriptedPlugin)
.enablePlugins(ShadingPlugin)
.dependsOn(coreJvm, cache)
.dependsOn(coreJvm, cacheJvm)
.settings(
shared,
coursierPrefix,
@ -150,7 +164,7 @@ lazy val extra = project
)
lazy val cli = project
.dependsOn(coreJvm, cache, extra)
.dependsOn(coreJvm, cacheJvm, extra, scalazJvm)
.disablePlugins(ScriptedPlugin)
.enablePlugins(PackPlugin, SbtProguard)
.settings(
@ -182,7 +196,7 @@ lazy val cli = project
lazy val web = project
.disablePlugins(ScriptedPlugin)
.enablePlugins(ScalaJSPlugin)
.dependsOn(coreJs, `fetch-js`)
.dependsOn(coreJs, cacheJs)
.settings(
shared,
dontPublish,
@ -227,7 +241,7 @@ lazy val web = project
lazy val readme = project
.in(file("doc/readme"))
.dependsOn(coreJvm, cache)
.dependsOn(coreJvm, cacheJvm, scalazJvm)
.disablePlugins(ScriptedPlugin)
.enablePlugins(TutPlugin)
.settings(
@ -238,7 +252,7 @@ lazy val readme = project
)
lazy val `sbt-shared` = project
.dependsOn(coreJvm, cache)
.dependsOn(coreJvm, cacheJvm)
.disablePlugins(ScriptedPlugin)
.settings(
plugin,
@ -259,11 +273,22 @@ lazy val `sbt-shared` = project
)
lazy val `sbt-coursier` = project
.dependsOn(coreJvm, cache, extra, `sbt-shared`)
.dependsOn(coreJvm, cacheJvm, extra, `sbt-shared`, scalazJvm)
.disablePlugins(ScriptedPlugin)
.settings(
plugin,
utest
utest,
scriptedDependencies := {
scriptedDependencies.value
// TODO Get dependency projects automatically
// (but shouldn't scripted itself handle that…?)
publishLocal.in(coreJvm).value
publishLocal.in(cacheJvm).value
publishLocal.in(extra).value
publishLocal.in(`sbt-shared`).value
publishLocal.in(scalazJvm).value
}
)
lazy val `sbt-pgp-coursier` = project
@ -277,6 +302,11 @@ lazy val `sbt-pgp-coursier` = project
Seq(Deps.sbtPgp.value)
case _ => Nil
}
},
scriptedDependencies := {
scriptedDependencies.value
// TODO Get dependency projects automatically
scriptedDependencies.in(`sbt-coursier`).value
}
)
@ -290,11 +320,16 @@ lazy val `sbt-shading` = project
localM2Repository, // for a possibly locally published jarjar
libs += Deps.jarjar % "shaded",
// dependencies of jarjar-core - directly depending on these so that they don't get shaded
libs ++= Deps.jarjarTransitiveDeps
libs ++= Deps.jarjarTransitiveDeps,
scriptedDependencies := {
scriptedDependencies.value
// TODO Get dependency projects automatically
scriptedDependencies.in(`sbt-coursier`).value
}
)
lazy val okhttp = project
.dependsOn(cache)
.dependsOn(cacheJvm)
.disablePlugins(ScriptedPlugin)
.settings(
shared,
@ -310,7 +345,8 @@ lazy val jvm = project
testsJvm,
`proxy-tests`,
paths,
cache,
cacheJvm,
scalazJvm,
bootstrap,
extra,
cli,
@ -332,7 +368,7 @@ lazy val js = project
.disablePlugins(ScriptedPlugin)
.aggregate(
coreJs,
`fetch-js`,
cacheJs,
testsJs,
web
)
@ -342,37 +378,18 @@ lazy val js = project
moduleName := "coursier-js"
)
// run sbt-plugins/publishLocal to publish all that necessary for plugins
lazy val `sbt-plugins` = project
.dummy
.disablePlugins(ScriptedPlugin)
.aggregate(
coreJvm,
cache,
extra,
`sbt-shared`,
`sbt-coursier`,
`sbt-pgp-coursier`,
`sbt-shading`
)
.settings(
shared,
pluginOverrideCrossScalaVersion,
dontPublish
)
lazy val coursier = project
.in(root)
.disablePlugins(ScriptedPlugin)
.aggregate(
coreJvm,
coreJs,
`fetch-js`,
testsJvm,
testsJs,
`proxy-tests`,
paths,
cache,
cacheJvm,
cacheJs,
bootstrap,
extra,
cli,
@ -380,6 +397,8 @@ lazy val coursier = project
`sbt-coursier`,
`sbt-pgp-coursier`,
`sbt-shading`,
scalazJvm,
scalazJs,
web,
readme,
okhttp

View File

@ -2,8 +2,7 @@ scala_library(
name = "cache",
dependencies = [
"core:core",
"3rdparty/jvm:scalaz-concurrent",
"paths/src/main/java:paths",
],
sources = rglobs("*.scala"),
sources = rglobs("jvm/*.scala", "shared/*.scala"),
)

View File

@ -1,10 +1,9 @@
package coursier
import coursier.util.EitherT
import coursier.util.{EitherT, Task}
import org.scalajs.dom.raw.{Event, XMLHttpRequest}
import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.language.implicitConversions
import scala.scalajs.js
import js.Dynamic.{global => g}
import scala.scalajs.js.timers._

View File

@ -0,0 +1,8 @@
package coursier.util
abstract class PlatformTask {
implicit val gather: Gather[Task] =
new TaskGather {}
}

View File

@ -10,11 +10,12 @@ import java.util.regex.Pattern
import coursier.core.Authentication
import coursier.ivy.IvyRepository
import coursier.internal.FileUtil
import coursier.util.Base64.Encoder
import scala.annotation.tailrec
import java.io.{Serializable => _, _}
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.{Files, StandardCopyOption}
import java.util.Base64
import coursier.util.{EitherT, Schedulable}
@ -34,9 +35,6 @@ object Cache {
}
}
// java.nio.charset.StandardCharsets.UTF_8 not available in Java 6
private val UTF_8 = Charset.forName("UTF-8")
// Check SHA-1 if available, else be fine with no checksum
val defaultChecksums = Seq(Some("SHA-1"), None)
@ -268,7 +266,9 @@ object Cache {
).r
private def basicAuthenticationEncode(user: String, password: String): String =
(user + ":" + password).getBytes(UTF_8).toBase64
Base64.getEncoder.encodeToString(
s"$user:$password".getBytes(UTF_8)
)
/**
* Returns a `java.net.URL` for `s`, possibly using the custom protocol handlers found under the
@ -334,9 +334,8 @@ object Cache {
var success = false
try {
c.setRequestMethod("HEAD")
val len = Some(c.getContentLength) // TODO Use getContentLengthLong when switching to Java >= 7
.filter(_ >= 0)
.map(_.toLong)
val len = Some(c.getContentLengthLong)
.filter(_ >= 0L)
// TODO 404 Not found could be checked here
@ -581,8 +580,7 @@ object Cache {
else if (responseCode(conn) == Some(401))
Left(FileError.Unauthorized(url, realm = realm(conn)))
else {
// TODO Use the safer getContentLengthLong when switching back to Java >= 7
for (len0 <- Option(conn.getContentLength) if len0 >= 0L) {
for (len0 <- Option(conn.getContentLengthLong) if len0 >= 0L) {
val len = len0 + (if (partialDownload) alreadyDownloaded else 0L)
logger.foreach(_.downloadLength(url, len, alreadyDownloaded, watching = false))
}
@ -601,7 +599,7 @@ object Cache {
withStructureLock(cache) {
file.getParentFile.mkdirs()
FileUtil.atomicMove(tmp, file)
Files.move(tmp.toPath, file.toPath, StandardCopyOption.ATOMIC_MOVE)
}
for (lastModified <- Option(conn.getLastModified) if lastModified > 0L)

View File

@ -0,0 +1,48 @@
package coursier.internal
import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream, InputStream}
import java.nio.file.Files
object FileUtil {
def write(file: File, bytes: Array[Byte]): Unit = {
var fos: FileOutputStream = null
try {
fos = new FileOutputStream(file)
fos.write(bytes)
fos.close()
} finally {
if (fos != null) fos.close()
}
}
def readFully(is: InputStream): Array[Byte] = {
val buffer = new ByteArrayOutputStream
val data = Array.ofDim[Byte](16384)
var nRead = 0
while ({
nRead = is.read(data, 0, data.length)
nRead != -1
})
buffer.write(data, 0, nRead)
buffer.flush()
buffer.toByteArray
}
def readAllBytes(file: File): Array[Byte] = {
var fis: FileInputStream = null
try {
fis = new FileInputStream(file)
readFully(fis)
} finally {
if (fis != null)
fis.close()
}
}
def createTempDirectory(prefix: String): File =
Files.createTempDirectory(prefix).toFile
}

View File

@ -0,0 +1,33 @@
package coursier.util
import java.util.concurrent.ExecutorService
import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService, Future}
import scala.concurrent.duration.Duration
abstract class PlatformTask { self =>
def schedule[A](pool: ExecutorService)(f: => A): Task[A] = {
val ec0 = pool match {
case eces: ExecutionContextExecutorService => eces
case _ => ExecutionContext.fromExecutorService(pool) // FIXME Is this instantiation costly? Cache it?
}
Task(_ => Future(f)(ec0))
}
implicit val schedulable: Schedulable[Task] =
new TaskGather with Schedulable[Task] {
def schedule[A](pool: ExecutorService)(f: => A) = self.schedule(pool)(f)
}
def gather: Gather[Task] =
schedulable
implicit class PlatformTaskOps[T](private val task: Task[T]) {
def unsafeRun()(implicit ec: ExecutionContext): T =
Await.result(task.future(), Duration.Inf)
}
}

View File

@ -2,28 +2,14 @@ package coursier.util
import java.util.concurrent.{ExecutorService, Executors, ThreadFactory}
import scala.language.higherKinds
import scalaz.concurrent.{Task => ScalazTask}
trait Schedulable[F[_]] extends Gather[F] {
def schedule[A](pool: ExecutorService)(f: => A): F[A]
}
object Schedulable {
implicit val scalazTask: Schedulable[ScalazTask] =
new Schedulable[ScalazTask] {
def point[A](a: A) =
ScalazTask.point(a)
def schedule[A](pool: ExecutorService)(f: => A) =
ScalazTask(f)(pool)
def gather[A](elems: Seq[ScalazTask[A]]) =
ScalazTask.taskInstance.gather(elems)
def bind[A, B](elem: ScalazTask[A])(f: A => ScalazTask[B]) =
ScalazTask.taskInstance.bind(elem)(f)
}
lazy val defaultThreadPool =
fixedThreadPool(4 max Runtime.getRuntime.availableProcessors())
def fixedThreadPool(size: Int): ExecutorService =
Executors.newFixedThreadPool(

View File

@ -0,0 +1,33 @@
package coursier.util
import scala.concurrent.{ExecutionContext, Future, Promise}
final case class Task[T](value: ExecutionContext => Future[T]) extends AnyVal {
def map[U](f: T => U): Task[U] =
Task(implicit ec => value(ec).map(f))
def flatMap[U](f: T => Task[U]): Task[U] =
Task(implicit ec => value(ec).flatMap(t => f(t).value(ec)))
def handle[U >: T](f: PartialFunction[Throwable, U]): Task[U] =
Task(ec => value(ec).recover(f)(ec))
def future()(implicit ec: ExecutionContext): Future[T] =
value(ec)
}
object Task extends PlatformTask {
def point[A](a: A): Task[A] = {
val future = Future.successful(a)
Task(_ => future)
}
def delay[A](a: => A): Task[A] =
Task(ec => Future(a)(ec))
def never[A]: Task[A] =
Task(_ => Promise[A].future)
}

View File

@ -0,0 +1,12 @@
package coursier.util
import scala.concurrent.Future
trait TaskGather extends Gather[Task] {
def point[A](a: A) = Task.point(a)
def bind[A, B](elem: Task[A])(f: A => Task[B]) =
elem.flatMap(f)
def gather[A](elems: Seq[Task[A]]) =
Task(implicit ec => Future.sequence(elems.map(_.value(ec))))
}

View File

@ -1,101 +0,0 @@
package coursier.internal
import java.io._
import java.util.UUID
/** Java 6-compatible helpers mimicking NIO */
object FileUtil {
private object Java7 {
import java.nio.file.{ Files, StandardCopyOption }
def atomicMove(from: File, to: File): Unit =
Files.move(from.toPath, to.toPath, StandardCopyOption.ATOMIC_MOVE)
def createTempDirectory(prefix: String): File =
Files.createTempDirectory(prefix).toFile
}
private object Java6 {
def move(from: File, to: File): Unit =
if (!from.renameTo(to))
throw new IOException(s"Cannot move $from to $to")
def createTempDirectory(prefix: String): File = {
val tmpBaseDir = new File(sys.props("java.io.tmpdir"))
val tmpDir = new File(tmpBaseDir, s"$prefix-${UUID.randomUUID()}")
tmpDir.mkdirs()
tmpDir
}
}
private def versionGteq(version: String, to: (Int, Int)): Boolean =
version.split('.').take(2).map(s => scala.util.Try(s.toInt).toOption) match {
case Array(Some(major), Some(minor)) =>
Ordering[(Int, Int)].gteq((major, minor), (1, 7))
case _ => false
}
// Fine if set several times (if java7Available() is initially called concurrently)
@volatile private var java7AvailableOpt = Option.empty[Boolean]
private def java7Available(): Boolean =
java7AvailableOpt.getOrElse {
val available = sys.props.get("java.version").exists { version =>
versionGteq(version, (1, 7))
}
java7AvailableOpt = Some(available)
available
}
/** Not guaranteed to be atomic on Java 6 */
def atomicMove(from: File, to: File): Unit =
if (java7Available())
Java7.atomicMove(from, to)
else
Java6.move(from, to)
def write(file: File, bytes: Array[Byte]): Unit = {
var fos: FileOutputStream = null
try {
fos = new FileOutputStream(file)
fos.write(bytes)
fos.close()
} finally {
if (fos != null) fos.close()
}
}
def readFully(is: InputStream): Array[Byte] = {
val buffer = new ByteArrayOutputStream
val data = Array.ofDim[Byte](16384)
var nRead = 0
while ({
nRead = is.read(data, 0, data.length)
nRead != -1
})
buffer.write(data, 0, nRead)
buffer.flush()
buffer.toByteArray
}
def readAllBytes(file: File): Array[Byte] = {
var fis: FileInputStream = null
try {
fis = new FileInputStream(file)
readFully(fis)
} finally {
if (fis != null)
fis.close()
}
}
def createTempDirectory(prefix: String): File =
if (java7Available())
Java7.createTempDirectory(prefix)
else
Java6.createTempDirectory(prefix)
}

View File

@ -1,106 +0,0 @@
package coursier.util
import scala.collection.mutable.ArrayBuilder
/**
* Base64 encoder
* @author Mark Lister
* This software is distributed under the 2-Clause BSD license. See the
* LICENSE file in the root of the repository.
*
* Copyright (c) 2014 - 2015 Mark Lister
*
* The repo for this Base64 encoder lives at https://github.com/marklister/base64
* Please send your issues, suggestions and pull requests there.
*/
object Base64 {
final case class B64Scheme(encodeTable: Array[Char], strictPadding: Boolean = true,
postEncode: String => String = identity,
preDecode: String => String = identity) {
lazy val decodeTable = {
val b: Array[Int] = new Array[Int](256)
for (x <- encodeTable.zipWithIndex) {
b(x._1) = x._2.toInt
}
b
}
}
val base64 = new B64Scheme((('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ Seq('+', '/')).toArray)
val base64Url = new B64Scheme(base64.encodeTable.dropRight(2) ++ Seq('-', '_'), false,
_.replaceAllLiterally("=", "%3D"),
_.replaceAllLiterally("%3D", "="))
implicit class SeqEncoder(s: Seq[Byte]) {
def toBase64(implicit scheme: B64Scheme = base64): String = Encoder(s.toArray).toBase64
}
implicit class Encoder(b: Array[Byte]) {
val r = new StringBuilder((b.length + 3) * 4 / 3)
lazy val pad = (3 - b.length % 3) % 3
def toBase64(implicit scheme: B64Scheme = base64): String = {
def sixBits(x: Byte, y: Byte, z: Byte): Unit = {
val zz = (x & 0xff) << 16 | (y & 0xff) << 8 | (z & 0xff)
r += scheme.encodeTable(zz >> 18)
r += scheme.encodeTable(zz >> 12 & 0x3f)
r += scheme.encodeTable(zz >> 6 & 0x3f)
r += scheme.encodeTable(zz & 0x3f)
}
for (p <- 0 until b.length - 2 by 3) {
sixBits(b(p), b(p + 1), b(p + 2))
}
pad match {
case 0 =>
case 1 => sixBits(b(b.length - 2), b(b.length - 1), 0)
case 2 => sixBits(b(b.length - 1), 0, 0)
}
r.length = (r.length - pad)
r ++= "=" * pad
scheme.postEncode(r.toString())
}
}
implicit class Decoder(s: String) {
def toByteArray(implicit scheme: B64Scheme = base64): Array[Byte] = {
val pre = scheme.preDecode(s)
val cleanS = pre.replaceAll("=+$", "")
val pad = pre.length - cleanS.length
val computedPad = (4 - (cleanS.length % 4)) % 4
val r = new ArrayBuilder.ofByte
def threeBytes(a: Int, b: Int, c: Int, d: Int): Unit = {
val i = a << 18 | b << 12 | c << 6 | d
r += ((i >> 16).toByte)
r += ((i >> 8).toByte)
r += (i.toByte)
}
if (scheme.strictPadding) {
if (pad > 2) throw new java.lang.IllegalArgumentException("Invalid Base64 String: (excessive padding) " + s)
if (s.length % 4 != 0) throw new java.lang.IllegalArgumentException("Invalid Base64 String: (padding problem) " + s)
}
if (computedPad == 3) throw new java.lang.IllegalArgumentException("Invalid Base64 String: (string length) " + s)
try {
val s = (cleanS + "A" * computedPad)
for (x <- 0 until s.length - 1 by 4) {
val i = scheme.decodeTable(s.charAt(x)) << 18 |
scheme.decodeTable(s.charAt(x + 1)) << 12 |
scheme.decodeTable(s.charAt(x + 2)) << 6 |
scheme.decodeTable(s.charAt(x + 3))
r += ((i >> 16).toByte)
r += ((i >> 8).toByte)
r += (i.toByte)
}
} catch {
case e: NoSuchElementException => throw new java.lang.IllegalArgumentException("Invalid Base64 String: (invalid character)" + e.getMessage + s)
}
val res = r.result
res.slice(0, res.length - computedPad)
}
}
}

View File

@ -3,11 +3,12 @@ scala_library(
dependencies = [
"3rdparty/jvm:argonaut-shapeless",
"3rdparty/jvm:caseapp",
"cache/src/main/scala:cache",
"cache:cache",
"core:core",
"extra/src/main/scala/coursier:fallback-deps-repo",
"extra/src/main/scala/coursier/extra:extra",
"extra/src/main/scala-2.12/coursier/extra:native",
"scalaz:scalaz-interop",
":util",
],
sources = globs(
@ -22,7 +23,7 @@ scala_library(
name = "util",
dependencies = [
"3rdparty/jvm:argonaut-shapeless",
"cache/src/main/scala:cache",
"cache:cache",
"core:core",
],
sources = globs("coursier/cli/util/*.scala"),

View File

@ -2,6 +2,7 @@ package coursier
package cli
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, File, FileInputStream, IOException}
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.Files
import java.nio.file.attribute.PosixFilePermission
import java.util.Properties
@ -156,7 +157,7 @@ object Bootstrap extends CaseApp[BootstrapOptions] {
entry.setTime(time)
outputZip.putNextEntry(entry)
outputZip.write(content.getBytes("UTF-8"))
outputZip.write(content.getBytes(UTF_8))
outputZip.closeEntry()
}
@ -207,7 +208,7 @@ object Bootstrap extends CaseApp[BootstrapOptions] {
"exec java -jar " + options.options.javaOpt.map(s => "'" + s.replace("'", "\\'") + "'").mkString(" ") + " \"$0\" \"$@\""
).mkString("", "\n", "\n")
try FileUtil.write(output0, shellPreamble.getBytes("UTF-8") ++ buffer.toByteArray)
try FileUtil.write(output0, shellPreamble.getBytes(UTF_8) ++ buffer.toByteArray)
catch { case e: IOException =>
Console.err.println(s"Error while writing $output0${Option(e.getMessage).fold("")(" (" + _ + ")")}")
sys.exit(1)

View File

@ -6,8 +6,6 @@ import java.io.File
import caseapp._
import coursier.cli.options.FetchOptions
import scala.language.reflectiveCalls
final class Fetch(options: FetchOptions, args: RemainingArgs) {
val helper = new Helper(options.common, args.all, ignoreErrors = options.artifactOptions.force)

View File

@ -10,14 +10,14 @@ import coursier.cli.options.{CommonOptions, IsolatedLoaderOptions}
import coursier.cli.scaladex.Scaladex
import coursier.cli.util.{JsonElem, JsonPrintRequirement, JsonReport}
import coursier.extra.Typelevel
import coursier.interop.scalaz._
import coursier.ivy.IvyRepository
import coursier.util.Parse.ModuleRequirements
import coursier.util.{Parse, Print}
import coursier.util.{Gather, Parse, Print}
import scala.annotation.tailrec
import scala.concurrent.duration.Duration
import scalaz.concurrent.{Strategy, Task}
import scalaz.Nondeterminism
object Helper {
@ -145,14 +145,14 @@ class Helper(
None
val fetchs = cachePolicies.map(p =>
Cache.fetch(cache, p, checksums = Nil, logger = logger, pool = pool, ttl = ttl0)
Cache.fetch[Task](cache, p, checksums = Nil, logger = logger, pool = pool, ttl = ttl0)
)
logger.foreach(_.init())
val scaladex = Scaladex.cached(fetchs: _*)
val res = Nondeterminism[Task].gather(scaladexRawDependencies.map { s =>
val res = Gather[Task].gather(scaladexRawDependencies.map { s =>
val deps = scaladex.dependencies(
s,
scalaVersion,
@ -192,6 +192,7 @@ class Helper(
.collect { case Right(l) => l }
.flatten
.map { case (mod, ver) => (Dependency(mod, ver), Map[String, String]()) }
.toList
}
val (forceVersionErrors, forceVersions0) = Parse.moduleVersions(forceVersion, scalaVersion)

View File

@ -1,6 +1,7 @@
package coursier.cli
import java.io.{BufferedReader, File, InputStream, InputStreamReader, PipedInputStream, PipedOutputStream, PrintStream}
import java.nio.charset.StandardCharsets.UTF_8
import coursier.internal.FileUtil
@ -55,7 +56,7 @@ object SparkOutputHelper {
if (!written) {
println(s"Detected YARN app ID $id")
Option(yarnAppFile.getParentFile).foreach(_.mkdirs())
FileUtil.write(yarnAppFile, id.getBytes("UTF-8"))
FileUtil.write(yarnAppFile, id.getBytes(UTF_8))
written = true
}
}

View File

@ -6,11 +6,9 @@ import java.util.concurrent.ExecutorService
import argonaut._, Argonaut._, ArgonautShapeless._
import coursier.core.{Artifact, Attributes}
import coursier.util.EitherT
import coursier.interop.scalaz._
import coursier.util.{EitherT, Gather}
import coursier.{Fetch, Module}
import scala.language.higherKinds
import scalaz.Nondeterminism
import scalaz.concurrent.Task
object Scaladex {
@ -48,7 +46,7 @@ object Scaladex {
Right(new String(b, StandardCharsets.UTF_8))
})(pool))
}, Nondeterminism[Task])
}, Gather[Task])
def cached(fetch: Fetch.Content[Task]*): Scaladex[Task] =
Scaladex({
@ -59,13 +57,13 @@ object Scaladex {
)
(get(fetch.head) /: fetch.tail)(_ orElse get(_))
}, Nondeterminism[Task])
}, Gather[Task])
}
// TODO Add F[_] type param, change `fetch` type to `String => EitherT[F, String, String]`, adjust method signatures accordingly, ...
case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondeterminism[F]) {
case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], G: Gather[F]) {
private implicit def F0 = F
private implicit val G0 = G
// quick & dirty API for querying scaladex
@ -141,8 +139,8 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
orgNameOrError.flatMap {
case (ghOrg, ghRepo, artifactNames) =>
val moduleVersions = F.map(F.gather(artifactNames.map { artifactName =>
F.map(artifactInfos(ghOrg, ghRepo, artifactName).run) {
val moduleVersions = G.map(G.gather(artifactNames.map { artifactName =>
G.map(artifactInfos(ghOrg, ghRepo, artifactName).run) {
case Left(err) =>
logger(s"Cannot get infos about artifact $artifactName from $ghOrg/$ghRepo: $err, ignoring it")
Nil
@ -152,7 +150,7 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
}
}))(_.flatten)
EitherT(F.map(moduleVersions) { l =>
EitherT(G.map(moduleVersions) { l =>
if (l.isEmpty)
Left(s"No module found for $ghOrg/$ghRepo")
else

View File

@ -2,6 +2,8 @@ package coursier.cli.spark
import java.io.{File, FileInputStream, FileOutputStream}
import java.math.BigInteger
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.{Files, StandardCopyOption}
import java.security.MessageDigest
import java.util.jar.{Attributes, JarFile, JarOutputStream, Manifest}
import java.util.regex.Pattern
@ -207,7 +209,7 @@ object Assembly {
extraDependencies: Seq[String],
options: CommonOptions,
artifactTypes: Set[String],
checksumSeed: Array[Byte] = "v1".getBytes("UTF-8")
checksumSeed: Array[Byte] = "v1".getBytes(UTF_8)
): Either[String, (File, Seq[File])] = {
val helper = sparkJarsHelper(scalaVersion, sparkVersion, yarnVersion, default, extraDependencies, options)
@ -240,7 +242,7 @@ object Assembly {
md.update(checksumSeed)
for (c <- checksums.sorted) {
val b = c.getBytes("UTF-8")
val b = c.getBytes(UTF_8)
md.update(b, 0, b.length)
}
@ -271,7 +273,7 @@ object Assembly {
val tmpDest = new File(dest.getParentFile, s".${dest.getName}.part")
// FIXME Acquire lock on tmpDest
Assembly.make(jars, tmpDest, assemblyRules)
FileUtil.atomicMove(tmpDest, dest)
Files.move(tmpDest.toPath, dest.toPath, StandardCopyOption.ATOMIC_MOVE)
Right((dest, jars))
}.left.map(_.describe)
}

View File

@ -11,7 +11,7 @@ junit_tests(
scala_library(
name='lib',
dependencies = [
"cache/src/main/scala:cache"
"cache:cache"
],
sources = ["CliTestLib.scala"],
)

View File

@ -1,6 +1,7 @@
package coursier.cli
import java.io._
import java.nio.charset.StandardCharsets.UTF_8
import java.util.zip.ZipInputStream
import caseapp.core.RemainingArgs
@ -69,7 +70,7 @@ class CliBootstrapIntegrationTest extends FlatSpec with CliTestLib {
val zis = new ZipInputStream(new ByteArrayInputStream(actualContent))
val lines = new String(zipEntryContent(zis, "bootstrap-isolation-foo-jar-urls"), "UTF-8").lines.toVector
val lines = new String(zipEntryContent(zis, "bootstrap-isolation-foo-jar-urls"), UTF_8).lines.toVector
val extensions = lines
.map { l =>

View File

@ -2,7 +2,6 @@ scala_library(
name = "core",
dependencies = [
"3rdparty/jvm:fastParse",
"3rdparty/jvm:scalaz-core",
"3rdparty/jvm:jsoup",
# TODO(wisechengyi) for some reason there is no compile error
# and this is needed at runtime.

View File

@ -2,8 +2,6 @@ package coursier
import coursier.util.{EitherT, Gather, Monad}
import scala.language.higherKinds
object Fetch {
type Content[F[_]] = Artifact => EitherT[F, String, String]

View File

@ -2,7 +2,6 @@ package coursier.core
import coursier.Fetch
import scala.language.higherKinds
import coursier.core.compatibility.encodeURIComponent
import coursier.util.{EitherT, Monad}

View File

@ -4,7 +4,6 @@ package core
import coursier.util.Monad
import scala.annotation.tailrec
import scala.language.higherKinds
sealed abstract class ResolutionProcess {

View File

@ -4,8 +4,6 @@ import coursier.Fetch
import coursier.core._
import coursier.util.{EitherT, Monad, WebPage}
import scala.language.higherKinds
final case class IvyRepository(
pattern: Pattern,
metadataPatternOpt: Option[Pattern],

View File

@ -4,8 +4,6 @@ import coursier.util.Traverse.TraverseOps
import coursier.util.ValidationNel
import fastparse.all._
import scala.language.implicitConversions
final case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty]) {
def string: String = chunks.map(_.string).mkString

View File

@ -5,8 +5,6 @@ import coursier.core._
import coursier.core.compatibility.encodeURIComponent
import coursier.util.{EitherT, Monad, WebPage}
import scala.language.higherKinds
object MavenRepository {
val SnapshotTimestamp = "(.*-)?[0-9]{8}\\.[0-9]{6}-[0-9]+".r

View File

@ -1,7 +1,5 @@
package coursier.util
import scala.language.higherKinds
final case class EitherT[F[_], L, R](run: F[Either[L, R]]) {
def map[S](f: R => S)(implicit M: Monad[F]): EitherT[F, L, S] =
@ -44,11 +42,6 @@ final case class EitherT[F[_], L, R](run: F[Either[L, R]]) {
}
)
def scalaz(implicit M: Monad[F]): _root_.scalaz.EitherT[F, L, R] =
_root_.scalaz.EitherT(
M.map(run)(_root_.scalaz.\/.fromEither)
)
}
object EitherT {

View File

@ -1,18 +1,9 @@
package coursier.util
import scala.language.higherKinds
trait Gather[F[_]] extends Monad[F] {
def gather[A](elems: Seq[F[A]]): F[Seq[A]]
}
object Gather {
implicit def fromScalaz[F[_]](implicit N: scalaz.Nondeterminism[F]): Gather[F] =
new Gather[F] {
def point[A](a: A) = N.pure(a)
def bind[A, B](elem: F[A])(f: A => F[B]) = N.bind(elem)(f)
def gather[A](elems: Seq[F[A]]) = N.map(N.gather(elems))(l => l)
}
def apply[F[_]](implicit G: Gather[F]): Gather[F] = G
}

View File

@ -1,7 +1,5 @@
package coursier.util
import scala.language.higherKinds
trait Monad[F[_]] {
def point[A](a: A): F[A]
def bind[A, B](elem: F[A])(f: A => F[B]): F[B]
@ -9,13 +7,3 @@ trait Monad[F[_]] {
def map[A, B](elem: F[A])(f: A => B): F[B] =
bind(elem)(a => point(f(a)))
}
object Monad {
implicit def fromScalaz[F[_]](implicit M: scalaz.Monad[F]): Monad[F] =
new Monad[F] {
def point[A](a: A) = M.pure(a)
def bind[A, B](elem: F[A])(f: A => F[B]) = M.bind(elem)(f)
}
}

View File

@ -166,8 +166,8 @@ object Cache {
dropInfoAttributes = true
)
def fetch() = coursier.Cache.fetch()
def file(artifact: Artifact) = coursier.Cache.file(artifact)
def fetch[F[_]: coursier.util.Schedulable]() = coursier.Cache.fetch[F]()
def file[F[_]: coursier.util.Schedulable](artifact: Artifact) = coursier.Cache.file[F](artifact)
}
```
@ -187,17 +187,21 @@ val start = Resolution(
Create a fetch function able to get things from a few repositories via a local cache,
```tut:silent
import coursier.util.Task
val repositories = Seq(
Cache.ivy2Local,
MavenRepository("https://repo1.maven.org/maven2")
)
val fetch = Fetch.from(repositories, Cache.fetch())
val fetch = Fetch.from(repositories, Cache.fetch[Task]())
```
Then run the resolution per-se,
```tut:silent
val resolution = start.process.run(fetch).unsafePerformSync
import scala.concurrent.ExecutionContext.Implicits.global
val resolution = start.process.run(fetch).unsafeRun()
```
That will fetch and use metadata.
@ -210,11 +214,11 @@ These would mean that the resolution wasn't able to get metadata about some depe
Then fetch and get local copies of the artifacts themselves (the JARs) with
```tut:silent
import java.io.File
import scalaz.concurrent.Task
import coursier.util.Gather
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
resolution.artifacts.map(Cache.file(_).run)
).unsafePerformSync
val localArtifacts: Seq[Either[FileError, File]] = Gather[Task].gather(
resolution.artifacts.map(Cache.file[Task](_).run)
).unsafeRun()
```
@ -544,7 +548,7 @@ Given a sequence of dependencies, designated by their `Module` (organisation and
and version (just a `String`), it gives either errors (`Seq[String]`) or metadata (`(Artifact.Source, Project)`),
wrapping the whole in a monad `F`.
```tut:silent
val fetch = Fetch.from(repositories, Cache.fetch())
val fetch = Fetch.from(repositories, Cache.fetch[Task]())
```
The monad used by `Fetch.from` is `scalaz.concurrent.Task`, but the resolution process is not tied to a particular
@ -570,7 +574,9 @@ resolution is particularly complex, in which case `maxIterations` could be incre
Let's run the whole resolution,
```tut:silent
val resolution = start.process.run(fetch).unsafePerformSync
import scala.concurrent.ExecutionContext.Implicits.global
val resolution = start.process.run(fetch).unsafeRun()
```
To get additional feedback during the resolution, we can give the `Cache.default` method above
@ -594,11 +600,11 @@ which are dependencies whose versions could not be unified.
Then, if all went well, we can fetch and get local copies of the artifacts themselves (the JARs) with
```tut:silent
import java.io.File
import scalaz.concurrent.Task
import coursier.util.Gather
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
resolution.artifacts.map(Cache.file(_).run)
).unsafePerformSync
val localArtifacts: Seq[Either[FileError, File]] = Gather[Task].gather(
resolution.artifacts.map(Cache.file[Task](_).run)
).unsafeRun()
```
We're using the `Cache.file` method, that can also be given a `Logger` (for more feedback) and a custom thread pool.

View File

@ -32,7 +32,8 @@ object Native {
Seq(s"$binaryName$major$minor", s"$binaryName-$major.$minor")
} :+ binaryName
Process("which" +: binaryNames).lines_!
Process("which" +: binaryNames)
.lineStream_!
.map(new File(_))
.headOption
.getOrElse {
@ -325,7 +326,7 @@ object Native {
val compileOpts = {
val includes = {
val includedir =
Try(Process("llvm-config --includedir").lines_!)
Try(Process("llvm-config --includedir").lineStream_!)
.getOrElse(Seq.empty)
("/usr/local/include" +: includedir).map(s => s"-I$s")
}
@ -392,7 +393,7 @@ object Native {
val nativeCompileOptions = {
val includes = {
val includedir =
Try(Process("llvm-config --includedir").lines_!)
Try(Process("llvm-config --includedir").lineStream_!)
.getOrElse(Seq.empty)
("/usr/local/include" +: includedir).map(s => s"-I$s")
}
@ -444,7 +445,7 @@ object Native {
val nativeLinkingOptions = {
val libs = {
val libdir =
Try(Process("llvm-config --libdir").lines_!)
Try(Process("llvm-config --libdir").lineStream_!)
.getOrElse(Seq.empty)
("/usr/local/lib" +: libdir).map(s => s"-L$s")
}

View File

@ -2,7 +2,7 @@ scala_library(
name = "fallback-deps-repo",
dependencies = [
"core:core",
"cache/src/main/scala:cache",
"cache:cache",
],
sources = globs("*.scala"),
)

View File

@ -5,8 +5,6 @@ import java.net.{HttpURLConnection, URL, URLConnection}
import coursier.util.{EitherT, Monad}
import scala.language.higherKinds
object FallbackDependenciesRepository {
def exists(url: URL): Boolean = {

View File

@ -1,52 +0,0 @@
package coursier
import scala.concurrent.{ ExecutionContext, Future }
import scalaz.{ Nondeterminism, Reducer }
/**
* Minimal Future-based Task.
*
* Likely to be flawed and/or sub-optimal, but does the job.
*/
trait Task[T] { self =>
def map[U](f: T => U): Task[U] =
new Task[U] {
def runF(implicit ec: ExecutionContext) = self.runF.map(f)
}
def flatMap[U](f: T => Task[U]): Task[U] =
new Task[U] {
def runF(implicit ec: ExecutionContext) = self.runF.flatMap(f(_).runF)
}
def runF(implicit ec: ExecutionContext): Future[T]
}
object Task {
def now[A](a: A): Task[A] =
new Task[A] {
def runF(implicit ec: ExecutionContext) = Future.successful(a)
}
def apply[A](f: ExecutionContext => Future[A]): Task[A] =
new Task[A] {
def runF(implicit ec: ExecutionContext) = f(ec)
}
def gatherUnordered[T](tasks: Seq[Task[T]], exceptionCancels: Boolean = false): Task[Seq[T]] =
new Task[Seq[T]] {
def runF(implicit ec: ExecutionContext) = Future.traverse(tasks)(_.runF)
}
implicit val taskMonad: Nondeterminism[Task] =
new Nondeterminism[Task] {
def point[A](a: => A): Task[A] = Task.now(a)
def bind[A,B](fa: Task[A])(f: A => Task[B]): Task[B] = fa.flatMap(f)
override def reduceUnordered[A, M](fs: Seq[Task[A]])(implicit R: Reducer[A, M]): Task[M] =
Task { implicit ec =>
val f = Future.sequence(fs.map(_.runF))
f.map { l =>
(R.zero /: l)(R.snoc)
}
}
def chooseAny[A](head: Task[A], tail: Seq[Task[A]]): Task[(A, Seq[Task[A]])] =
???
}
}

View File

@ -1,4 +1,6 @@
import java.nio.file.Files
import sbt._
import sbt.Keys._
import sbt.ScriptedPlugin.autoImport.{sbtLauncher, scriptedBufferLog, ScriptedLaunchConf, scriptedLaunchOpts}
@ -31,30 +33,42 @@ object Settings {
scalazBintrayRepository,
sonatypeRepository("releases"),
crossScalaVersions := Seq(scala212, scala211, scala210), // defined for all projects to trump sbt-doge
scalacOptions ++= {
val targetJvm = scalaBinaryVersion.value match {
case "2.10" | "2.11" =>
Seq("-target:jvm-1.6")
case _ =>
Seq()
}
targetJvm ++ Seq("-feature", "-deprecation")
},
javacOptions ++= {
scalaBinaryVersion.value match {
case "2.10" | "2.11" =>
Seq(
"-source", "1.6",
"-target", "1.6"
)
case _ =>
Seq()
}
},
scalacOptions ++= Seq(
"-target:jvm-1.8",
"-feature",
"-deprecation",
"-language:higherKinds",
"-language:implicitConversions"
),
javacOptions ++= Seq(
"-source", "1.8",
"-target", "1.8"
),
javacOptions.in(Keys.doc) := Seq()
)
val runNpmInstallIfNeeded = Def.task {
val baseDir = baseDirectory.in(ThisBuild).value
val evFile = baseDir / "node_modules" / ".npm_run"
val log = streams.value.log
if (!evFile.exists()) {
val cmd = Seq("npm", "install")
val b = new ProcessBuilder(cmd: _*)
b.directory(baseDir)
b.inheritIO()
log.info(s"Running ${cmd.mkString(" ")}")
val p = b.start()
val retCode = p.waitFor()
if (retCode == 0)
log.info(s"${cmd.mkString(" ")} ran successfully")
else
sys.error(s"${cmd.mkString(" ")} failed (return code $retCode)")
// Parent dir should have been created by npm install
Files.write(evFile.toPath, Array.emptyByteArray)
}
}
lazy val shared = javaScalaPluginShared ++ Seq(
scalaVersion := scala212,
libs ++= {

View File

@ -81,7 +81,7 @@ object CoursierPlugin extends AutoPlugin {
IvyXml.writeFiles(currentProject, shadedConfigOpt, ivySbt.value, streams.value.log)
}).value
private val pluginIvySnapshotsBase = Resolver.SbtPluginRepositoryRoot.stripSuffix("/") + "/ivy-snapshots"
private val pluginIvySnapshotsBase = Resolver.SbtRepositoryRoot.stripSuffix("/") + "/ivy-snapshots"
// allows to get the actual repo list when sbt starts up
private val hackHack = Seq(
@ -93,25 +93,33 @@ object CoursierPlugin extends AutoPlugin {
// hack to trigger https://github.com/sbt/sbt/blob/v1.0.1/main/src/main/scala/sbt/Defaults.scala#L2856,
// to have the third case be used instead of the second one, at https://github.com/sbt/sbt/blob/v1.0.1/main/src/main/scala/sbt/Defaults.scala#L2069
// 😃🔫
new xsbti.AppConfiguration {
def provider() = {
import scala.language.reflectiveCalls
val prov = app.provider()
val noWarningForDeprecatedStuffProv = prov.asInstanceOf[{
def mainClass(): Class[_ <: xsbti.AppMain]
}]
new xsbti.AppProvider {
def newMain() = prov.newMain()
def components() = prov.components()
def mainClass() = prov.mainClass()
def mainClass() = noWarningForDeprecatedStuffProv.mainClass()
def mainClasspath() = prov.mainClasspath()
def loader() = prov.loader()
def scalaProvider() = {
val scalaProv = prov.scalaProvider()
val noWarningForDeprecatedStuffScalaProv = scalaProv.asInstanceOf[{
def libraryJar(): File
def compilerJar(): File
}]
new xsbti.ScalaProvider {
def app(id: xsbti.ApplicationID) = scalaProv.app(id)
def loader() = scalaProv.loader()
def jars() = scalaProv.jars()
def libraryJar() = scalaProv.libraryJar()
def libraryJar() = noWarningForDeprecatedStuffScalaProv.libraryJar()
def version() = scalaProv.version()
def compilerJar() = scalaProv.compilerJar()
def compilerJar() = noWarningForDeprecatedStuffScalaProv.compilerJar()
def launcher() = {
val launch = scalaProv.launcher()
new xsbti.Launcher {
@ -142,17 +150,12 @@ object CoursierPlugin extends AutoPlugin {
}
)
private val preloadedBase = {
val rawPattern = "file:///${sbt.preloaded-${sbt.global.base-${user.home}/.sbt}/preloaded/}"
Tasks.exceptionPatternParser().apply(rawPattern).string
}
def coursierSettings(
shadedConfigOpt: Option[(String, String)],
packageConfigs: Seq[(Configuration, String)]
) = hackHack ++ Seq(
clean := {
clean.value
val noWarningPlz = clean.value
Tasks.resolutionsCache.clear()
Tasks.reportsCache.clear()
},

View File

@ -2,8 +2,6 @@ package coursier
import coursier.util.{EitherT, Monad}
import scala.language.higherKinds
final case class InterProjectRepository(projects: Seq[Project]) extends Repository {
private val map = projects

View File

@ -1,5 +1,7 @@
package coursier
import java.nio.charset.StandardCharsets.UTF_8
import coursier.internal.FileUtil
import org.apache.ivy.core.module.id.ModuleRevisionId
@ -52,7 +54,7 @@ object IvyXml {
val content0 = rawContent(currentProject, shadedConfigOpt)
cacheIvyFile.getParentFile.mkdirs()
log.info(s"Writing Ivy file $cacheIvyFile")
FileUtil.write(cacheIvyFile, content0.getBytes("UTF-8"))
FileUtil.write(cacheIvyFile, content0.getBytes(UTF_8))
// Just writing an empty file here... Are these only used?
cacheIvyPropertiesFile.getParentFile.mkdirs()

View File

@ -4,9 +4,7 @@ final class ResolutionException(
val error: ResolutionError
) extends Exception(
error.message,
error.cause.orNull
) {
// not using the 4-arg Exception constructor, only available with Java >= 7
setStackTrace(Array()) // don't keep stack trace around (improves readability from the SBT console)
}
error.cause.orNull,
true,
false // don't keep stack trace around (improves readability from the SBT console)
)

View File

@ -2,8 +2,6 @@ package coursier
import sbt._
import scala.language.implicitConversions
// things from sbt-structure
object Structure {

View File

@ -6,6 +6,7 @@ import java.util.concurrent.{ConcurrentHashMap, ExecutorService, Executors}
import coursier.core.{Authentication, Publication}
import coursier.extra.Typelevel
import coursier.interop.scalaz._
import coursier.ivy.{IvyRepository, PropertiesPattern}
import coursier.Keys._
import coursier.Structure._
@ -1015,7 +1016,7 @@ object Tasks {
val artifactFileOrErrorTasks = allArtifacts.toVector.distinct.map { a =>
def f(p: CachePolicy) =
Cache.file(
Cache.file[Task](
a,
cache,
p,

View File

@ -4,7 +4,7 @@ import utest._
object IvyXmlTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
"no truncation" - {
val project = Project(

View File

@ -3,4 +3,8 @@ package coursier
object SbtCompatibility {
def needsIvyXmlLocal = List(sbt.Keys.deliverLocalConfiguration)
def needsIvyXml = List(sbt.Keys.deliverConfiguration)
implicit class ResolverCompationExtraOps(val res: sbt.Resolver.type) {
def SbtRepositoryRoot = res.SbtPluginRepositoryRoot
}
}

9
scalaz/BUILD Normal file
View File

@ -0,0 +1,9 @@
scala_library(
name = "scalaz-interop",
dependencies = [
"core:core",
"cache:cache",
"3rdparty/jvm:scalaz-concurrent",
],
sources = rglobs("jvm/*.scala", "shared/*.scala"),
)

View File

@ -0,0 +1,3 @@
package coursier.interop
abstract class PlatformScalazImplicits

View File

@ -0,0 +1,24 @@
package coursier.interop
import java.util.concurrent.ExecutorService
import coursier.util.Schedulable
import _root_.scalaz.concurrent.{Task => ScalazTask}
abstract class PlatformScalazImplicits {
implicit val scalazTaskSchedulable: Schedulable[ScalazTask] =
new Schedulable[ScalazTask] {
def point[A](a: A) =
ScalazTask.point(a)
def schedule[A](pool: ExecutorService)(f: => A) =
ScalazTask(f)(pool)
def gather[A](elems: Seq[ScalazTask[A]]) =
ScalazTask.taskInstance.gather(elems)
def bind[A, B](elem: ScalazTask[A])(f: A => ScalazTask[B]) =
ScalazTask.taskInstance.bind(elem)(f)
}
}

View File

@ -0,0 +1,24 @@
package coursier.interop
import coursier.util.{Gather, Monad}
object scalaz extends LowPriorityScalazImplicits {
implicit def coursierMonadFromScalaz[F[_]](implicit M: _root_.scalaz.Monad[F]): Monad[F] =
new Monad[F] {
def point[A](a: A) = M.pure(a)
def bind[A, B](elem: F[A])(f: A => F[B]) = M.bind(elem)(f)
}
}
abstract class LowPriorityScalazImplicits extends PlatformScalazImplicits {
implicit def coursierGatherFromScalaz[F[_]](implicit N: _root_.scalaz.Nondeterminism[F]): Gather[F] =
new Gather[F] {
def point[A](a: A) = N.pure(a)
def bind[A, B](elem: F[A])(f: A => F[B]) = N.bind(elem)(f)
def gather[A](elems: Seq[F[A]]) = N.map(N.gather(elems))(l => l)
}
}

View File

@ -70,7 +70,6 @@ sbtShading() {
runSbtCoursierTests() {
addPgpKeys
sbt ++$SCALA_VERSION sbt-plugins/publishLocal
if [ "$SCALA_VERSION" = "2.10" ]; then
sbt ++$SCALA_VERSION "sbt-coursier/scripted sbt-coursier/*" "sbt-coursier/scripted sbt-coursier-0.13/*"
else
@ -80,14 +79,14 @@ runSbtCoursierTests() {
}
runSbtShadingTests() {
sbt ++$SCALA_VERSION coreJVM/publishLocal cache/publishLocal extra/publishLocal sbt-shared/publishLocal sbt-coursier/publishLocal "sbt-shading/scripted sbt-shading/*"
sbt ++$SCALA_VERSION "sbt-shading/scripted sbt-shading/*"
if [ "$SCALA_VERSION" = "2.10" ]; then
sbt ++$SCALA_VERSION "sbt-shading/scripted sbt-shading-0.13/*"
fi
}
jsCompile() {
sbt ++$SCALA_VERSION js/compile js/test:compile coreJS/fastOptJS fetch-js/fastOptJS testsJS/test:fastOptJS js/test:fastOptJS
sbt ++$SCALA_VERSION js/compile js/test:compile coreJS/fastOptJS cacheJS/fastOptJS testsJS/test:fastOptJS js/test:fastOptJS
}
jvmCompile() {
@ -131,53 +130,7 @@ validateReadme() {
}
checkBinaryCompatibility() {
sbt ++${SCALA_VERSION} coreJVM/mimaReportBinaryIssues cache/mimaReportBinaryIssues
}
testSbtCoursierJava6() {
sbt ++${SCALA_VERSION} coreJVM/publishLocal cache/publishLocal extra/publishLocal sbt-coursier/publishLocal
git clone https://github.com/alexarchambault/scalacheck-shapeless.git
cd scalacheck-shapeless
git checkout e11ec8b2b069ee598b20ae3f3ad6e00f5edfd7ac
cd project
clean_plugin_sbt
cd project
clean_plugin_sbt
cd ../..
docker run -it --rm \
-v $HOME/.ivy2/local:/root/.ivy2/local \
-v $(pwd):/root/project \
-v $(pwd)/../bin:/root/bin \
-e CI=true \
openjdk:6-jre \
/bin/bash -c "cd /root/project && /root/bin/sbt update"
cd ..
# ensuring resolution error doesn't throw NoSuchMethodError
mkdir -p foo/project
cd foo
echo 'libraryDependencies += "foo" % "bar" % "1.0"' >> build.sbt
echo 'addSbtPlugin("io.get-coursier" % "sbt-coursier" % "'"$VERSION"'")' >> project/plugins.sbt
echo 'sbt.version=0.13.15' >> project/build.properties
docker run -it --rm \
-v $HOME/.ivy2/local:/root/.ivy2/local \
-v $(pwd):/root/project \
-v $(pwd)/../bin:/root/bin \
-e CI=true \
openjdk:6-jre \
/bin/bash -c "cd /root/project && /root/bin/sbt update || true" | tee -a output
grep "coursier.ResolutionException: Encountered 1 error" output
echo "Ok, found ResolutionException in output"
cd ..
}
clean_plugin_sbt() {
mv plugins.sbt plugins.sbt0
grep -v coursier plugins.sbt0 > plugins.sbt || true
echo '
addSbtPlugin("io.get-coursier" % "sbt-coursier" % "'"$VERSION"'")
' >> plugins.sbt
sbt ++${SCALA_VERSION} coreJVM/mimaReportBinaryIssues cacheJVM/mimaReportBinaryIssues
}
publish() {
@ -231,10 +184,6 @@ else
if is210 || is212; then
runSbtCoursierTests
fi
if is210; then
testSbtCoursierJava6
fi
elif sbtShading; then
if is210 || is212; then
runSbtShadingTests
@ -250,10 +199,6 @@ else
validateReadme
checkBinaryCompatibility
fi
# Not using a jdk6 matrix entry with Travis as some sources of coursier require Java 7 to compile
# (even though it won't try to call Java 7 specific methods if it detects it runs under Java 6).
# The tests here check that coursier is nonetheless fine when run under Java 6.
fi

View File

@ -9,7 +9,7 @@ import scala.concurrent.{ Future, Promise }
object JsTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'promise{
val p = Promise[Unit]()
Future(p.success(()))
@ -31,10 +31,10 @@ object JsTests extends TestSuite {
assert(proj.parent == Some(Module("ch.qos.logback", "logback-parent"), "1.1.3"))
}
.run
.runF
.map{ res =>
.map { res =>
assert(res.isRight)
}
.future()
}
}

View File

@ -1,7 +1,7 @@
package coursier.test
import coursier.util.{EitherT, TestEscape}
import coursier.{Fetch, Task}
import coursier.util.{EitherT, Task, TestEscape}
import coursier.Fetch
import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.scalajs.js

View File

@ -22,7 +22,7 @@ object DirectoryListingTests extends TestSuite {
val module = Module("com.abc", "test")
val version = "0.1"
val tests = TestSuite {
val tests = Tests {
'withListing - {
'jar - CentralTests.withArtifacts(
module,

View File

@ -7,7 +7,7 @@ import coursier.maven.MavenRepository
object HttpAuthenticationTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'httpAuthentication - {
// requires an authenticated HTTP server to be running on localhost:8080 with user 'user'
// and password 'pass'

View File

@ -1,13 +1,11 @@
package coursier
import java.io._
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_8
import coursier.util.EitherT
import coursier.util.{EitherT, Task}
import scala.language.implicitConversions
import scala.util.{Failure, Success, Try}
import scalaz.concurrent.Task
object Platform {
@ -25,10 +23,8 @@ object Platform {
buffer.toByteArray
}
private lazy val UTF_8 = Charset.forName("UTF-8")
def readFully(is: => InputStream): Task[Either[String, String]] =
Task {
Task.delay {
val t = Try {
val is0 = is
val b =

View File

@ -2,19 +2,21 @@ package coursier
package test
import java.io.File
import java.nio.file.Files
import coursier.cache.protocol.TestprotocolHandler
import coursier.internal.FileUtil
import coursier.util.Task
import utest._
import scala.concurrent.{Await, ExecutionContext}
import scala.concurrent.duration.Duration
import scala.util.Try
object CacheFetchTests extends TestSuite {
def check(extraRepo: Repository): Unit = {
val tmpDir = FileUtil.createTempDirectory("coursier-cache-fetch-tests")
val tmpDir = Files.createTempDirectory("coursier-cache-fetch-tests").toFile
def cleanTmpDir() = {
def delete(f: File): Boolean =
@ -30,36 +32,41 @@ object CacheFetchTests extends TestSuite {
Console.err.println(s"Warning: unable to remove temporary directory $tmpDir")
}
val res = try {
val fetch = Fetch.from(
Seq(
extraRepo,
MavenRepository("https://repo1.maven.org/maven2")
),
Cache.fetch(
tmpDir
val fetch = Fetch.from(
Seq(
extraRepo,
MavenRepository("https://repo1.maven.org/maven2")
),
Cache.fetch[Task](
tmpDir
)
)
val startRes = Resolution(
Set(
Dependency(
Module("com.github.alexarchambault", "coursier_2.11"), "1.0.0-M9-test"
)
)
)
val startRes = Resolution(
Set(
Dependency(
Module("com.github.alexarchambault", "coursier_2.11"), "1.0.0-M9-test"
)
)
)
val f = startRes
.process
.run(fetch)
.future()(ExecutionContext.global)
startRes.process.run(fetch).unsafePerformSync
} finally {
cleanTmpDir()
}
val res =
try Await.result(f, Duration.Inf)
finally {
cleanTmpDir()
}
val errors = res.errors
assert(errors.isEmpty)
}
val tests = TestSuite {
val tests = Tests {
// using scala-test would allow to put the below comments in the test names...

View File

@ -4,13 +4,14 @@ package test
import java.io.File
import java.math.BigInteger
import coursier.util.{Gather, Schedulable, Task}
import utest._
import scalaz.concurrent.Strategy
import scala.concurrent.{ExecutionContext, Future}
object ChecksumTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'parse - {
@ -82,13 +83,13 @@ object ChecksumTests extends TestSuite {
val cache = new File(cachePath)
def validate(artifact: Artifact, sumType: String) =
Cache.validateChecksum(
def validate(artifact: Artifact, sumType: String): Task[Either[FileError, Unit]] =
Cache.validateChecksum[Task](
artifact,
sumType,
cache,
Strategy.DefaultExecutorService
).run.unsafePerformSync
Schedulable.defaultThreadPool
).run
def artifact(url: String) = Artifact(
url,
@ -109,11 +110,14 @@ object ChecksumTests extends TestSuite {
"http://abc.com/com/github/alexarchambault/coursier_2.11/1.0.0-M9/coursier_2.11-1.0.0-M9.pom"
).map(artifact)
def validateAll(sumType: String) =
for (artifact <- artifacts) {
val res = validate(artifact, sumType)
assert(res.isRight)
}
def validateAll(sumType: String): Future[Seq[Unit]] =
Gather[Task].gather(
artifacts.map { artifact =>
validate(artifact, sumType).map { res =>
assert(res.isRight)
}
}
).future()(ExecutionContext.global)
'sha1 - validateAll("SHA-1")
'sha256 - validateAll("SHA-256")

View File

@ -18,7 +18,7 @@ object IvyTests extends TestSuite {
throw new Exception("Cannot happen")
)
val tests = TestSuite {
val tests = Tests {
'dropInfoAttributes - {
CentralTests.resolutionCheck(
module = Module(

View File

@ -9,7 +9,7 @@ object MavenTests extends TestSuite {
// only tested on the JVM for lack of support of XML attributes in the platform-dependent XML stubs
val tests = TestSuite {
val tests = Tests {
'testSnapshotNoVersioning - {
val dep = Dependency(

View File

@ -5,7 +5,7 @@ import utest._
object PropertiesTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'version - {
assert(Properties.version.nonEmpty)

View File

@ -4,6 +4,7 @@ import java.util.concurrent.ConcurrentHashMap
import coursier.{Fetch, Module}
import coursier.core.ResolutionProcess
import coursier.interop.scalaz._
import utest._
import scala.collection.JavaConverters._
@ -12,7 +13,7 @@ import scalaz.concurrent.Task
object ResolutionProcessTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'fetchAll - {

View File

@ -1,29 +1,24 @@
package coursier.test
import java.nio.charset.StandardCharsets
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.{Files, Paths}
import coursier.util.{EitherT, TestEscape}
import coursier.util.{EitherT, Task, TestEscape}
import coursier.{Cache, Fetch, Platform}
import scala.concurrent.{ExecutionContext, Future}
import scalaz.concurrent.Task
package object compatibility {
implicit val executionContext = scala.concurrent.ExecutionContext.global
implicit class TaskExtensions[T](val underlying: Task[T]) extends AnyVal {
def runF: Future[T] = Future.successful(underlying.unsafePerformSync)
}
def textResource(path: String)(implicit ec: ExecutionContext): Future[String] = Future {
val res = Option(getClass.getClassLoader.getResource(path)).getOrElse {
throw new Exception(s"Not found: resource $path")
}
val is = res.openStream()
new String(Platform.readFullySync(is), "UTF-8")
new String(Platform.readFullySync(is), UTF_8)
}
private val baseRepo = {
@ -48,9 +43,9 @@ package object compatibility {
val init = EitherT[Task, String, Unit] {
if (Files.exists(path))
Task.now(Right(()))
Task.point(Right(()))
else if (fillChunks)
Task[Either[String, Unit]] {
Task.delay[Either[String, Unit]] {
Files.createDirectories(path.getParent)
def is() = Cache.urlConnection(artifact.url, artifact.authentication).getInputStream
val b = Platform.readFullySync(is())
@ -61,7 +56,7 @@ package object compatibility {
Left(e.toString)
}
else
Task.now(Left(s"not found: $path"))
Task.point(Left(s"not found: $path"))
}
init.flatMap { _ =>
@ -80,7 +75,7 @@ package object compatibility {
if (fillChunks) {
val path0 = baseResources.resolve(path)
Files.createDirectories(path0.getParent)
Files.write(path0, content.getBytes(StandardCharsets.UTF_8))
Files.write(path0, content.getBytes(UTF_8))
}
}

View File

@ -1,4 +1,3 @@
io.get-coursier:coursier_2.11:1.1.0-SNAPSHOT:compile
org.scala-lang:scala-library:2.11.12:default
org.scala-lang.modules:scala-xml_2.11:1.0.6:default
org.scalaz:scalaz-core_2.11:7.2.16:default

View File

@ -22,7 +22,7 @@ object ActivationTests extends TestSuite {
// - condition on OS or JDK, but no OS or JDK info provided (-> no match)
// - negated OS infos (starting with "!") - not implemented yet
val tests = TestSuite {
val tests = Tests {
'OS - {
'fromProperties - {
'MacOSX - {

View File

@ -54,7 +54,7 @@ abstract class CentralTests extends TestSuite {
res
}
.runF
.future
}
def resolutionCheck(
@ -214,7 +214,7 @@ abstract class CentralTests extends TestSuite {
assert(artifact.url.endsWith("." + extension))
}
val tests = TestSuite {
val tests = Tests {
'logback - {
async {

View File

@ -8,7 +8,7 @@ object ExclusionsTests extends TestSuite {
def exclusionsAdd(e1: Set[(String, String)], e2: Set[(String, String)]) =
core.Exclusions.minimize(e1 ++ e2)
val tests = TestSuite {
val tests = Tests {
val e1 = Set(("org1", "name1"))
val e2 = Set(("org2", "name2"))

View File

@ -8,7 +8,7 @@ import utest._
object IvyPatternParserTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'plugin - {
val strPattern = "[organization]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/resolved.xml.[ext]"

View File

@ -22,7 +22,7 @@ object ParseTests extends TestSuite {
val url = "file%3A%2F%2Fsome%2Fencoded%2Furl"
val tests = TestSuite {
val tests = Tests {
"bintray-ivy:" - {
val obtained = Parse.repository("bintray-ivy:scalameta/maven")
assert(obtained.right.exists(isIvyRepo))

View File

@ -8,7 +8,7 @@ import utest._
object PomParsingTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'readClassifier{
val depNode ="""
<dependency>

View File

@ -18,7 +18,7 @@ object ResolutionTests extends TestSuite {
Resolution(deps, filter = filter, forceVersions = forceVersions)
.process
.run(Platform.fetch(repositories))
.runF
.future()
implicit class ProjectOps(val p: Project) extends AnyVal {
def kv: (ModuleVersion, (Artifact.Source, Project)) = p.moduleVersion -> (testRepository.source, p)
@ -206,7 +206,7 @@ object ResolutionTests extends TestSuite {
testRepository
)
val tests = TestSuite {
val tests = Tests {
'empty{
async{
val res = await(resolve0(

View File

@ -4,8 +4,6 @@ package test
import coursier.core._
import coursier.util.{EitherT, Monad}
import scala.language.higherKinds
final case class TestRepository(projects: Map[(Module, String), Project]) extends Repository {
val source = new core.Artifact.Source {
def artifacts(

View File

@ -6,7 +6,7 @@ import utest._
object VersionConstraintTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'parse{
'empty{
val c0 = Parse.versionConstraint("")

View File

@ -14,7 +14,7 @@ object VersionTests extends TestSuite {
versions.iterator.sliding(2).withPartial(false).forall{case Seq(a, b) => compare(a, b) < 0 }
val tests = TestSuite {
val tests = Tests {
'stackOverflow - {
val s = "." * 100000

View File

@ -6,7 +6,7 @@ import utest._
object PrintTests extends TestSuite {
val tests = TestSuite {
val tests = Tests {
'ignoreAttributes - {
val dep = Dependency(
Module("org", "name"),

View File

@ -54,7 +54,7 @@ object TreeTests extends TestSuite {
e.addChild(f)
val tests = TestSuite {
val tests = Tests {
'basic {
val str = Tree[Node](roots)(_.children, _.label)
assert(str ==

View File

@ -1,8 +1,8 @@
package coursier
package web
package coursier.web
import coursier.{Dependency, Fetch, MavenRepository, Module, Platform, Repository, Resolution}
import coursier.maven.MavenSource
import coursier.util.{Gather, Task}
import japgolly.scalajs.react.vdom.{ TagMod, Attr }
import japgolly.scalajs.react.vdom.Attrs.dangerouslySetInnerHtml
import japgolly.scalajs.react.{ ReactEventI, ReactComponentB, BackendScope }
@ -34,11 +34,11 @@ final case class State(
class Backend($: BackendScope[Unit, State]) {
def fetch(
repositories: Seq[core.Repository],
repositories: Seq[Repository],
fetch: Fetch.Content[Task]
): Fetch.Metadata[Task] = {
modVers => Task.gatherUnordered(
modVers => Gather[Task].gather(
modVers.map { case (module, version) =>
Fetch.find(repositories, module, version, fetch)
.run
@ -112,8 +112,8 @@ class Backend($: BackendScope[Unit, State]) {
.get(dep.moduleVersion)
.toSeq
.flatMap{case (_, proj) =>
core.Resolution.finalDependencies(dep, proj)
.filter(resolution.filter getOrElse core.Resolution.defaultFilter)
coursier.core.Resolution.finalDependencies(dep, proj)
.filter(resolution.filter getOrElse coursier.core.Resolution.defaultFilter)
}
val minDependencies = resolution.minDependencies
@ -185,7 +185,7 @@ class Backend($: BackendScope[Unit, State]) {
// For reasons that are unclear to me, not delaying this when using the runNow execution context
// somehow discards the $.modState above. (Not a major problem as queue is used by default.)
Future(task)(scala.scalajs.concurrent.JSExecutionContext.Implicits.queue).flatMap(_.runF).foreach { res: Resolution =>
Future(task)(scala.scalajs.concurrent.JSExecutionContext.Implicits.queue).flatMap(_.future()).foreach { res: Resolution =>
$.modState{ s =>
updateDepGraph(res)
updateTree(res, "#deptree", reverse = s.reverseTree)