diff --git a/.travis.yml b/.travis.yml index fbdf255cf..0d46c454e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a8c4eee24..055813062 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -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 \ No newline at end of file +For example, if since version is 1.1.0, then deprecation can be removed in 1.3.0 diff --git a/README.md b/README.md index 5a181f670..c284041a6 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/appveyor.yml b/appveyor.yml index 6871207ed..983ea5eed 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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 diff --git a/build.sbt b/build.sbt index 140df21b1..03eb4008c 100644 --- a/build.sbt +++ b/build.sbt @@ -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 diff --git a/cache/src/main/scala/BUILD b/cache/BUILD similarity index 62% rename from cache/src/main/scala/BUILD rename to cache/BUILD index 76a035d6d..9af56dad8 100644 --- a/cache/src/main/scala/BUILD +++ b/cache/BUILD @@ -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"), ) diff --git a/fetch-js/src/main/scala/coursier/Platform.scala b/cache/js/src/main/scala/coursier/Platform.scala similarity index 97% rename from fetch-js/src/main/scala/coursier/Platform.scala rename to cache/js/src/main/scala/coursier/Platform.scala index 06c75a581..8d43d7ce9 100644 --- a/fetch-js/src/main/scala/coursier/Platform.scala +++ b/cache/js/src/main/scala/coursier/Platform.scala @@ -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._ diff --git a/cache/js/src/main/scala/coursier/util/PlatformTask.scala b/cache/js/src/main/scala/coursier/util/PlatformTask.scala new file mode 100644 index 000000000..171f9b72c --- /dev/null +++ b/cache/js/src/main/scala/coursier/util/PlatformTask.scala @@ -0,0 +1,8 @@ +package coursier.util + +abstract class PlatformTask { + + implicit val gather: Gather[Task] = + new TaskGather {} + +} diff --git a/cache/src/main/scala/coursier/AuthenticatedURLConnection.scala b/cache/jvm/src/main/scala/coursier/AuthenticatedURLConnection.scala similarity index 100% rename from cache/src/main/scala/coursier/AuthenticatedURLConnection.scala rename to cache/jvm/src/main/scala/coursier/AuthenticatedURLConnection.scala diff --git a/cache/src/main/scala/coursier/Cache.scala b/cache/jvm/src/main/scala/coursier/Cache.scala similarity index 98% rename from cache/src/main/scala/coursier/Cache.scala rename to cache/jvm/src/main/scala/coursier/Cache.scala index d8c4a47f0..005718682 100644 --- a/cache/src/main/scala/coursier/Cache.scala +++ b/cache/jvm/src/main/scala/coursier/Cache.scala @@ -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) diff --git a/cache/src/main/scala/coursier/CacheParse.scala b/cache/jvm/src/main/scala/coursier/CacheParse.scala similarity index 100% rename from cache/src/main/scala/coursier/CacheParse.scala rename to cache/jvm/src/main/scala/coursier/CacheParse.scala diff --git a/cache/src/main/scala/coursier/CachePolicy.scala b/cache/jvm/src/main/scala/coursier/CachePolicy.scala similarity index 100% rename from cache/src/main/scala/coursier/CachePolicy.scala rename to cache/jvm/src/main/scala/coursier/CachePolicy.scala diff --git a/cache/src/main/scala/coursier/FileError.scala b/cache/jvm/src/main/scala/coursier/FileError.scala similarity index 100% rename from cache/src/main/scala/coursier/FileError.scala rename to cache/jvm/src/main/scala/coursier/FileError.scala diff --git a/cache/src/main/scala/coursier/TermDisplay.scala b/cache/jvm/src/main/scala/coursier/TermDisplay.scala similarity index 100% rename from cache/src/main/scala/coursier/TermDisplay.scala rename to cache/jvm/src/main/scala/coursier/TermDisplay.scala diff --git a/cache/src/main/scala/coursier/Terminal.scala b/cache/jvm/src/main/scala/coursier/Terminal.scala similarity index 100% rename from cache/src/main/scala/coursier/Terminal.scala rename to cache/jvm/src/main/scala/coursier/Terminal.scala diff --git a/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala b/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala new file mode 100644 index 000000000..1ad5f4d1f --- /dev/null +++ b/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala @@ -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 + +} \ No newline at end of file diff --git a/cache/jvm/src/main/scala/coursier/util/PlatformTask.scala b/cache/jvm/src/main/scala/coursier/util/PlatformTask.scala new file mode 100644 index 000000000..37d47cacc --- /dev/null +++ b/cache/jvm/src/main/scala/coursier/util/PlatformTask.scala @@ -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) + } + +} diff --git a/cache/src/main/scala/coursier/util/Schedulable.scala b/cache/jvm/src/main/scala/coursier/util/Schedulable.scala similarity index 55% rename from cache/src/main/scala/coursier/util/Schedulable.scala rename to cache/jvm/src/main/scala/coursier/util/Schedulable.scala index b01a6f572..a19273a1c 100644 --- a/cache/src/main/scala/coursier/util/Schedulable.scala +++ b/cache/jvm/src/main/scala/coursier/util/Schedulable.scala @@ -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( diff --git a/cache/shared/src/main/scala/coursier/util/Task.scala b/cache/shared/src/main/scala/coursier/util/Task.scala new file mode 100644 index 000000000..6082fa3d0 --- /dev/null +++ b/cache/shared/src/main/scala/coursier/util/Task.scala @@ -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) + +} + diff --git a/cache/shared/src/main/scala/coursier/util/TaskGather.scala b/cache/shared/src/main/scala/coursier/util/TaskGather.scala new file mode 100644 index 000000000..ce674f26d --- /dev/null +++ b/cache/shared/src/main/scala/coursier/util/TaskGather.scala @@ -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)))) +} diff --git a/cache/src/main/scala/coursier/internal/FileUtil.scala b/cache/src/main/scala/coursier/internal/FileUtil.scala deleted file mode 100644 index 5a6970101..000000000 --- a/cache/src/main/scala/coursier/internal/FileUtil.scala +++ /dev/null @@ -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) - -} \ No newline at end of file diff --git a/cache/src/main/scala/coursier/util/Base64.scala b/cache/src/main/scala/coursier/util/Base64.scala deleted file mode 100644 index 58cf0c888..000000000 --- a/cache/src/main/scala/coursier/util/Base64.scala +++ /dev/null @@ -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) - } - - } - -} diff --git a/cli/src/main/scala-2.12/BUILD b/cli/src/main/scala-2.12/BUILD index 28b891725..2ec7e13b5 100644 --- a/cli/src/main/scala-2.12/BUILD +++ b/cli/src/main/scala-2.12/BUILD @@ -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"), diff --git a/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala b/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala index 5b1b7dac7..a130b752d 100644 --- a/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala +++ b/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala @@ -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) diff --git a/cli/src/main/scala-2.12/coursier/cli/Fetch.scala b/cli/src/main/scala-2.12/coursier/cli/Fetch.scala index 01fdf912b..caa1114c0 100644 --- a/cli/src/main/scala-2.12/coursier/cli/Fetch.scala +++ b/cli/src/main/scala-2.12/coursier/cli/Fetch.scala @@ -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) diff --git a/cli/src/main/scala-2.12/coursier/cli/Helper.scala b/cli/src/main/scala-2.12/coursier/cli/Helper.scala index d3be2e7e6..566dcebf1 100644 --- a/cli/src/main/scala-2.12/coursier/cli/Helper.scala +++ b/cli/src/main/scala-2.12/coursier/cli/Helper.scala @@ -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) diff --git a/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala b/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala index 291364499..3bfa043a2 100644 --- a/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala +++ b/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala @@ -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 } } diff --git a/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala b/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala index a96a1dfd8..93b13d4b2 100644 --- a/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala +++ b/cli/src/main/scala-2.12/coursier/cli/scaladex/Scaladex.scala @@ -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 diff --git a/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala b/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala index 0c0ed04bc..ed2c01ad5 100644 --- a/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala +++ b/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala @@ -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) } diff --git a/cli/src/test/scala-2.12/coursier/cli/BUILD b/cli/src/test/scala-2.12/coursier/cli/BUILD index f23d1786f..22a50d165 100644 --- a/cli/src/test/scala-2.12/coursier/cli/BUILD +++ b/cli/src/test/scala-2.12/coursier/cli/BUILD @@ -11,7 +11,7 @@ junit_tests( scala_library( name='lib', dependencies = [ - "cache/src/main/scala:cache" + "cache:cache" ], sources = ["CliTestLib.scala"], ) diff --git a/cli/src/test/scala-2.12/coursier/cli/CliBootstrapIntegrationTest.scala b/cli/src/test/scala-2.12/coursier/cli/CliBootstrapIntegrationTest.scala index 8f6dce705..114aec9c8 100644 --- a/cli/src/test/scala-2.12/coursier/cli/CliBootstrapIntegrationTest.scala +++ b/cli/src/test/scala-2.12/coursier/cli/CliBootstrapIntegrationTest.scala @@ -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 => diff --git a/core/BUILD b/core/BUILD index 677c721d6..325b699bd 100644 --- a/core/BUILD +++ b/core/BUILD @@ -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. diff --git a/core/shared/src/main/scala/coursier/Fetch.scala b/core/shared/src/main/scala/coursier/Fetch.scala index 866e9b9a3..0ac1a81e0 100644 --- a/core/shared/src/main/scala/coursier/Fetch.scala +++ b/core/shared/src/main/scala/coursier/Fetch.scala @@ -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] diff --git a/core/shared/src/main/scala/coursier/core/Repository.scala b/core/shared/src/main/scala/coursier/core/Repository.scala index cdd9d5c69..955b35f7d 100644 --- a/core/shared/src/main/scala/coursier/core/Repository.scala +++ b/core/shared/src/main/scala/coursier/core/Repository.scala @@ -2,7 +2,6 @@ package coursier.core import coursier.Fetch -import scala.language.higherKinds import coursier.core.compatibility.encodeURIComponent import coursier.util.{EitherT, Monad} diff --git a/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala b/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala index 827d78a41..274ffa100 100644 --- a/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala +++ b/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala @@ -4,7 +4,6 @@ package core import coursier.util.Monad import scala.annotation.tailrec -import scala.language.higherKinds sealed abstract class ResolutionProcess { diff --git a/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala b/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala index f86336c96..05192d1b5 100644 --- a/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala +++ b/core/shared/src/main/scala/coursier/ivy/IvyRepository.scala @@ -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], diff --git a/core/shared/src/main/scala/coursier/ivy/Pattern.scala b/core/shared/src/main/scala/coursier/ivy/Pattern.scala index d2eadc8b2..11a4a7bfe 100644 --- a/core/shared/src/main/scala/coursier/ivy/Pattern.scala +++ b/core/shared/src/main/scala/coursier/ivy/Pattern.scala @@ -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 diff --git a/core/shared/src/main/scala/coursier/maven/MavenRepository.scala b/core/shared/src/main/scala/coursier/maven/MavenRepository.scala index 3f3333165..4268e61fb 100644 --- a/core/shared/src/main/scala/coursier/maven/MavenRepository.scala +++ b/core/shared/src/main/scala/coursier/maven/MavenRepository.scala @@ -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 diff --git a/core/shared/src/main/scala/coursier/util/EitherT.scala b/core/shared/src/main/scala/coursier/util/EitherT.scala index e215e2652..35e8ee7a4 100644 --- a/core/shared/src/main/scala/coursier/util/EitherT.scala +++ b/core/shared/src/main/scala/coursier/util/EitherT.scala @@ -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 { diff --git a/core/shared/src/main/scala/coursier/util/Gather.scala b/core/shared/src/main/scala/coursier/util/Gather.scala index 0da299040..d119a468f 100644 --- a/core/shared/src/main/scala/coursier/util/Gather.scala +++ b/core/shared/src/main/scala/coursier/util/Gather.scala @@ -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 } diff --git a/core/shared/src/main/scala/coursier/util/Monad.scala b/core/shared/src/main/scala/coursier/util/Monad.scala index 026ca2ea7..94f5d0f72 100644 --- a/core/shared/src/main/scala/coursier/util/Monad.scala +++ b/core/shared/src/main/scala/coursier/util/Monad.scala @@ -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) - } - -} diff --git a/doc/readme/README.md b/doc/readme/README.md index 056b0deb0..5ba7299ac 100644 --- a/doc/readme/README.md +++ b/doc/readme/README.md @@ -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. diff --git a/extra/src/main/scala-2.12/coursier/extra/Native.scala b/extra/src/main/scala-2.12/coursier/extra/Native.scala index bc4bd9334..98bd0635b 100644 --- a/extra/src/main/scala-2.12/coursier/extra/Native.scala +++ b/extra/src/main/scala-2.12/coursier/extra/Native.scala @@ -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") } diff --git a/extra/src/main/scala/coursier/BUILD b/extra/src/main/scala/coursier/BUILD index cebddab94..7a3f0b0bc 100644 --- a/extra/src/main/scala/coursier/BUILD +++ b/extra/src/main/scala/coursier/BUILD @@ -2,7 +2,7 @@ scala_library( name = "fallback-deps-repo", dependencies = [ "core:core", - "cache/src/main/scala:cache", + "cache:cache", ], sources = globs("*.scala"), ) diff --git a/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala b/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala index 50ea1b297..405ad28a8 100644 --- a/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala +++ b/extra/src/main/scala/coursier/FallbackDependenciesRepository.scala @@ -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 = { diff --git a/fetch-js/src/main/scala/coursier/Task.scala b/fetch-js/src/main/scala/coursier/Task.scala deleted file mode 100644 index b1ab3aae9..000000000 --- a/fetch-js/src/main/scala/coursier/Task.scala +++ /dev/null @@ -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]])] = - ??? - } -} diff --git a/project/Settings.scala b/project/Settings.scala index 5960d4fe3..be5dfb024 100644 --- a/project/Settings.scala +++ b/project/Settings.scala @@ -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 ++= { diff --git a/sbt-coursier/src/main/scala/coursier/CoursierPlugin.scala b/sbt-coursier/src/main/scala/coursier/CoursierPlugin.scala index 2bd8e4481..9699603f3 100644 --- a/sbt-coursier/src/main/scala/coursier/CoursierPlugin.scala +++ b/sbt-coursier/src/main/scala/coursier/CoursierPlugin.scala @@ -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() }, diff --git a/sbt-coursier/src/main/scala/coursier/InterProjectRepository.scala b/sbt-coursier/src/main/scala/coursier/InterProjectRepository.scala index 23087d480..8a6baae31 100644 --- a/sbt-coursier/src/main/scala/coursier/InterProjectRepository.scala +++ b/sbt-coursier/src/main/scala/coursier/InterProjectRepository.scala @@ -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 diff --git a/sbt-coursier/src/main/scala/coursier/IvyXml.scala b/sbt-coursier/src/main/scala/coursier/IvyXml.scala index 7a4140f75..3b4f72a03 100644 --- a/sbt-coursier/src/main/scala/coursier/IvyXml.scala +++ b/sbt-coursier/src/main/scala/coursier/IvyXml.scala @@ -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() diff --git a/sbt-coursier/src/main/scala/coursier/ResolutionException.scala b/sbt-coursier/src/main/scala/coursier/ResolutionException.scala index f083c0ea3..9f8925a91 100644 --- a/sbt-coursier/src/main/scala/coursier/ResolutionException.scala +++ b/sbt-coursier/src/main/scala/coursier/ResolutionException.scala @@ -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) +) diff --git a/sbt-coursier/src/main/scala/coursier/Structure.scala b/sbt-coursier/src/main/scala/coursier/Structure.scala index 5128e554f..e8b09bd83 100644 --- a/sbt-coursier/src/main/scala/coursier/Structure.scala +++ b/sbt-coursier/src/main/scala/coursier/Structure.scala @@ -2,8 +2,6 @@ package coursier import sbt._ -import scala.language.implicitConversions - // things from sbt-structure object Structure { diff --git a/sbt-coursier/src/main/scala/coursier/Tasks.scala b/sbt-coursier/src/main/scala/coursier/Tasks.scala index 0a950ed0b..3670b21a5 100644 --- a/sbt-coursier/src/main/scala/coursier/Tasks.scala +++ b/sbt-coursier/src/main/scala/coursier/Tasks.scala @@ -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, diff --git a/sbt-coursier/src/test/scala/coursier/IvyXmlTests.scala b/sbt-coursier/src/test/scala/coursier/IvyXmlTests.scala index 8738a7aca..8f695d727 100644 --- a/sbt-coursier/src/test/scala/coursier/IvyXmlTests.scala +++ b/sbt-coursier/src/test/scala/coursier/IvyXmlTests.scala @@ -4,7 +4,7 @@ import utest._ object IvyXmlTests extends TestSuite { - val tests = TestSuite { + val tests = Tests { "no truncation" - { val project = Project( diff --git a/sbt-shared/src/main/scala-2.10/coursier/SbtCompatibility.scala b/sbt-shared/src/main/scala-2.10/coursier/SbtCompatibility.scala index 5ca0e8403..c00ba3c98 100644 --- a/sbt-shared/src/main/scala-2.10/coursier/SbtCompatibility.scala +++ b/sbt-shared/src/main/scala-2.10/coursier/SbtCompatibility.scala @@ -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 + } } diff --git a/scalaz/BUILD b/scalaz/BUILD new file mode 100644 index 000000000..4e577b17d --- /dev/null +++ b/scalaz/BUILD @@ -0,0 +1,9 @@ +scala_library( + name = "scalaz-interop", + dependencies = [ + "core:core", + "cache:cache", + "3rdparty/jvm:scalaz-concurrent", + ], + sources = rglobs("jvm/*.scala", "shared/*.scala"), +) diff --git a/scalaz/js/src/main/scala/coursier/interop/PlatformScalazImplicits.scala b/scalaz/js/src/main/scala/coursier/interop/PlatformScalazImplicits.scala new file mode 100644 index 000000000..96d33740f --- /dev/null +++ b/scalaz/js/src/main/scala/coursier/interop/PlatformScalazImplicits.scala @@ -0,0 +1,3 @@ +package coursier.interop + +abstract class PlatformScalazImplicits diff --git a/scalaz/jvm/src/main/scala/coursier/interop/PlatformScalazImplicits.scala b/scalaz/jvm/src/main/scala/coursier/interop/PlatformScalazImplicits.scala new file mode 100644 index 000000000..c64704958 --- /dev/null +++ b/scalaz/jvm/src/main/scala/coursier/interop/PlatformScalazImplicits.scala @@ -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) + } + +} diff --git a/scalaz/shared/src/main/scala/coursier/interop/scalaz.scala b/scalaz/shared/src/main/scala/coursier/interop/scalaz.scala new file mode 100644 index 000000000..8dffb3206 --- /dev/null +++ b/scalaz/shared/src/main/scala/coursier/interop/scalaz.scala @@ -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) + } + +} diff --git a/scripts/travis.sh b/scripts/travis.sh index 54e8c79ba..643388e59 100755 --- a/scripts/travis.sh +++ b/scripts/travis.sh @@ -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 diff --git a/tests/js/src/test/scala/coursier/test/JsTests.scala b/tests/js/src/test/scala/coursier/test/JsTests.scala index 55bc44213..eadc9d8a0 100644 --- a/tests/js/src/test/scala/coursier/test/JsTests.scala +++ b/tests/js/src/test/scala/coursier/test/JsTests.scala @@ -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() } } diff --git a/tests/js/src/test/scala/coursier/test/compatibility/package.scala b/tests/js/src/test/scala/coursier/test/compatibility/package.scala index 0f2c9b472..a96dfe9ed 100644 --- a/tests/js/src/test/scala/coursier/test/compatibility/package.scala +++ b/tests/js/src/test/scala/coursier/test/compatibility/package.scala @@ -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 diff --git a/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala b/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala index 224eab9bf..024d574f7 100644 --- a/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala +++ b/tests/jvm/src/it/scala/coursier/test/DirectoryListingTests.scala @@ -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, diff --git a/tests/jvm/src/it/scala/coursier/test/HttpAuthenticationTests.scala b/tests/jvm/src/it/scala/coursier/test/HttpAuthenticationTests.scala index 1fd350fef..952fa3b73 100644 --- a/tests/jvm/src/it/scala/coursier/test/HttpAuthenticationTests.scala +++ b/tests/jvm/src/it/scala/coursier/test/HttpAuthenticationTests.scala @@ -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' diff --git a/tests/jvm/src/test/scala/coursier/Platform.scala b/tests/jvm/src/test/scala/coursier/Platform.scala index 068df7bdd..2ba60cc1a 100644 --- a/tests/jvm/src/test/scala/coursier/Platform.scala +++ b/tests/jvm/src/test/scala/coursier/Platform.scala @@ -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 = diff --git a/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala b/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala index 2408842a4..2d309d266 100644 --- a/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/CacheFetchTests.scala @@ -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... diff --git a/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala b/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala index 0df27e310..6e63b9cf3 100644 --- a/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala @@ -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") diff --git a/tests/jvm/src/test/scala/coursier/test/IvyTests.scala b/tests/jvm/src/test/scala/coursier/test/IvyTests.scala index 6632149b7..094a09931 100644 --- a/tests/jvm/src/test/scala/coursier/test/IvyTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/IvyTests.scala @@ -18,7 +18,7 @@ object IvyTests extends TestSuite { throw new Exception("Cannot happen") ) - val tests = TestSuite { + val tests = Tests { 'dropInfoAttributes - { CentralTests.resolutionCheck( module = Module( diff --git a/tests/jvm/src/test/scala/coursier/test/MavenTests.scala b/tests/jvm/src/test/scala/coursier/test/MavenTests.scala index 93cf7dce1..7f039180d 100644 --- a/tests/jvm/src/test/scala/coursier/test/MavenTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/MavenTests.scala @@ -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( diff --git a/tests/jvm/src/test/scala/coursier/test/PropertiesTests.scala b/tests/jvm/src/test/scala/coursier/test/PropertiesTests.scala index c2b261ae9..09daf6aba 100644 --- a/tests/jvm/src/test/scala/coursier/test/PropertiesTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/PropertiesTests.scala @@ -5,7 +5,7 @@ import utest._ object PropertiesTests extends TestSuite { - val tests = TestSuite { + val tests = Tests { 'version - { assert(Properties.version.nonEmpty) diff --git a/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala b/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala index 1dd33e9be..2b0c21ebb 100644 --- a/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/ResolutionProcessTests.scala @@ -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 - { diff --git a/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala b/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala index 8912d45ae..2f3c27fb3 100644 --- a/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala +++ b/tests/jvm/src/test/scala/coursier/test/compatibility/package.scala @@ -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)) } } diff --git a/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.1.0-SNAPSHOT b/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.1.0-SNAPSHOT index 1c067087c..a85295a58 100644 --- a/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.1.0-SNAPSHOT +++ b/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.1.0-SNAPSHOT @@ -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 diff --git a/tests/shared/src/test/scala/coursier/test/ActivationTests.scala b/tests/shared/src/test/scala/coursier/test/ActivationTests.scala index d7d7f9a7c..8693dbdca 100644 --- a/tests/shared/src/test/scala/coursier/test/ActivationTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ActivationTests.scala @@ -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 - { diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index 1c86c5a10..2a57aab2f 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -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 { diff --git a/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala b/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala index 051421384..87d5a18e0 100644 --- a/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ExclusionsTests.scala @@ -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")) diff --git a/tests/shared/src/test/scala/coursier/test/IvyPatternParserTests.scala b/tests/shared/src/test/scala/coursier/test/IvyPatternParserTests.scala index 4d40fe9e8..73b0fb2d1 100644 --- a/tests/shared/src/test/scala/coursier/test/IvyPatternParserTests.scala +++ b/tests/shared/src/test/scala/coursier/test/IvyPatternParserTests.scala @@ -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]" diff --git a/tests/shared/src/test/scala/coursier/test/ParseTests.scala b/tests/shared/src/test/scala/coursier/test/ParseTests.scala index f32c8c0db..121745363 100644 --- a/tests/shared/src/test/scala/coursier/test/ParseTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ParseTests.scala @@ -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)) diff --git a/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala b/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala index 23aa32550..eec377c90 100644 --- a/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala +++ b/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala @@ -8,7 +8,7 @@ import utest._ object PomParsingTests extends TestSuite { - val tests = TestSuite { + val tests = Tests { 'readClassifier{ val depNode =""" diff --git a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala index d1ca90a2a..b8c21b966 100644 --- a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala @@ -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( diff --git a/tests/shared/src/test/scala/coursier/test/TestRepository.scala b/tests/shared/src/test/scala/coursier/test/TestRepository.scala index a0c016447..47284cee3 100644 --- a/tests/shared/src/test/scala/coursier/test/TestRepository.scala +++ b/tests/shared/src/test/scala/coursier/test/TestRepository.scala @@ -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( diff --git a/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala b/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala index 0f909d3a7..df8b10370 100644 --- a/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala +++ b/tests/shared/src/test/scala/coursier/test/VersionConstraintTests.scala @@ -6,7 +6,7 @@ import utest._ object VersionConstraintTests extends TestSuite { - val tests = TestSuite { + val tests = Tests { 'parse{ 'empty{ val c0 = Parse.versionConstraint("") diff --git a/tests/shared/src/test/scala/coursier/test/VersionTests.scala b/tests/shared/src/test/scala/coursier/test/VersionTests.scala index 74c486f83..98c64b9e2 100644 --- a/tests/shared/src/test/scala/coursier/test/VersionTests.scala +++ b/tests/shared/src/test/scala/coursier/test/VersionTests.scala @@ -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 diff --git a/tests/shared/src/test/scala/coursier/util/PrintTests.scala b/tests/shared/src/test/scala/coursier/util/PrintTests.scala index 42ee57fd7..3b0b37645 100644 --- a/tests/shared/src/test/scala/coursier/util/PrintTests.scala +++ b/tests/shared/src/test/scala/coursier/util/PrintTests.scala @@ -6,7 +6,7 @@ import utest._ object PrintTests extends TestSuite { - val tests = TestSuite { + val tests = Tests { 'ignoreAttributes - { val dep = Dependency( Module("org", "name"), diff --git a/tests/shared/src/test/scala/coursier/util/TreeTests.scala b/tests/shared/src/test/scala/coursier/util/TreeTests.scala index 71c895ebb..465063486 100644 --- a/tests/shared/src/test/scala/coursier/util/TreeTests.scala +++ b/tests/shared/src/test/scala/coursier/util/TreeTests.scala @@ -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 == diff --git a/web/src/main/scala/coursier/web/Backend.scala b/web/src/main/scala/coursier/web/Backend.scala index 0573bda17..47ec82df1 100644 --- a/web/src/main/scala/coursier/web/Backend.scala +++ b/web/src/main/scala/coursier/web/Backend.scala @@ -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)