diff --git a/cli/src/main/scala/coursier/cli/Coursier.scala b/cli/src/main/scala/coursier/cli/Coursier.scala index 6349cb792..0162ebd44 100644 --- a/cli/src/main/scala/coursier/cli/Coursier.scala +++ b/cli/src/main/scala/coursier/cli/Coursier.scala @@ -4,15 +4,18 @@ package cli import java.io.File import caseapp._ -import coursier.core.{Fetch, Parse, Repository}, Repository.CachePolicy +import coursier.core.{MavenRepository, Parse, Repository}, Repository.CachePolicy import scalaz.concurrent.Task -case class Coursier(scope: List[String], - keepOptional: Boolean, - fetch: Boolean, - @ExtraName("v") verbose: List[Unit], - @ExtraName("N") maxIterations: Int = 100) extends App { +case class Coursier( + scope: List[String], + keepOptional: Boolean, + fetch: Boolean, + @ExtraName("c") offline: Boolean, + @ExtraName("v") verbose: List[Unit], + @ExtraName("N") maxIterations: Int = 100 +) extends App { val verbose0 = verbose.length @@ -26,8 +29,8 @@ case class Coursier(scope: List[String], def fileRepr(f: File) = f.toString - val logger: Fetch.Logger with FilesLogger = - new Fetch.Logger with FilesLogger { + val logger: MavenRepository.Logger with FilesLogger = + new MavenRepository.Logger with FilesLogger { def println(s: String) = Console.err.println(s) def downloading(url: String) = @@ -55,17 +58,13 @@ case class Coursier(scope: List[String], } val cachedMavenCentral = Repository.mavenCentral.copy( - fetch = Repository.mavenCentral.fetch.copy( - cache = Some(centralCacheDir), - logger = if (verbose0 <= 1) None else Some(logger) - ) + cache = Some(centralCacheDir), + logger = if (verbose0 <= 1) None else Some(logger) ) val repositories = Seq[Repository]( cachedMavenCentral, Repository.ivy2Local.copy( - fetch = Repository.ivy2Local.fetch.copy( - logger = if (verbose0 <= 1) None else Some(logger) - ) + logger = if (verbose0 <= 1) None else Some(logger) ) ) @@ -149,13 +148,17 @@ case class Coursier(scope: List[String], if (fetch) { println() - val cachePolicy: CachePolicy = CachePolicy.Default + val cachePolicy: CachePolicy = + if (offline) + CachePolicy.LocalOnly + else + CachePolicy.Default val artifacts = res.artifacts val files = new Files( Seq( - cachedMavenCentral.fetch.root -> centralFilesCacheDir + cachedMavenCentral.root -> centralFilesCacheDir ), () => ???, if (verbose0 <= 0) None else Some(logger) diff --git a/core-js/src/main/scala/coursier/core/Fetch.scala b/core-js/src/main/scala/coursier/core/MavenRepository.scala similarity index 88% rename from core-js/src/main/scala/coursier/core/Fetch.scala rename to core-js/src/main/scala/coursier/core/MavenRepository.scala index 62828ef3e..8eaf229d8 100644 --- a/core-js/src/main/scala/coursier/core/Fetch.scala +++ b/core-js/src/main/scala/coursier/core/MavenRepository.scala @@ -12,7 +12,7 @@ import js.Dynamic.{global => g} import scala.scalajs.js.timers._ -object Fetch { +object MavenRepository { def encodeURIComponent(s: String): String = g.encodeURIComponent(s).asInstanceOf[String] @@ -84,18 +84,24 @@ object Fetch { } -case class Fetch(root: String, - logger: Option[Fetch.Logger] = None) { +case class MavenRepository( + root: String, + ivyLike: Boolean = false, + logger: Option[MavenRepository.Logger] = None +) extends BaseMavenRepository(root, ivyLike) { - def apply(artifact: Artifact, - cachePolicy: Repository.CachePolicy): EitherT[Task, String, String] = { + + def fetch( + artifact: Artifact, + cachePolicy: Repository.CachePolicy + ): EitherT[Task, String, String] = { val url0 = root + artifact.url EitherT( Task { implicit ec => Future(logger.foreach(_.fetching(url0))) - .flatMap(_ => Fetch.get(url0)) + .flatMap(_ => MavenRepository.get(url0)) .map{ s => logger.foreach(_.fetched(url0)); \/-(s) } .recover{case e: Exception => logger.foreach(_.other(url0, e.getMessage)) diff --git a/core-js/src/test/scala/coursier/test/JsTests.scala b/core-js/src/test/scala/coursier/test/JsTests.scala index 82533d4e8..d4747b62c 100644 --- a/core-js/src/test/scala/coursier/test/JsTests.scala +++ b/core-js/src/test/scala/coursier/test/JsTests.scala @@ -1,7 +1,7 @@ package coursier package test -import coursier.core.{Fetch, Repository} +import coursier.core.{Repository, MavenRepository} import coursier.test.compatibility._ import utest._ @@ -18,7 +18,7 @@ object JsTests extends TestSuite { } 'get{ - Fetch.get("http://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.pom") + MavenRepository.get("http://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.pom") .map(core.compatibility.xmlParse) .map{ xml => assert(xml.right.toOption.exists(_.label == "project")) diff --git a/core-jvm/src/main/scala/coursier/core/Fetch.scala b/core-jvm/src/main/scala/coursier/core/MavenRepository.scala similarity index 85% rename from core-jvm/src/main/scala/coursier/core/Fetch.scala rename to core-jvm/src/main/scala/coursier/core/MavenRepository.scala index 73d6b509f..f88f0df2f 100644 --- a/core-jvm/src/main/scala/coursier/core/Fetch.scala +++ b/core-jvm/src/main/scala/coursier/core/MavenRepository.scala @@ -8,14 +8,19 @@ import scala.io.Codec import scalaz._, Scalaz._ import scalaz.concurrent.Task -case class Fetch(root: String, - cache: Option[File] = None, - logger: Option[Fetch.Logger] = None) { +case class MavenRepository( + root: String, + cache: Option[File] = None, + ivyLike: Boolean = false, + logger: Option[MavenRepository.Logger] = None +) extends BaseMavenRepository(root, ivyLike) { val isLocal = root.startsWith("file:///") - def apply(artifact: Artifact, - cachePolicy: Repository.CachePolicy): EitherT[Task, String, String] = { + def fetch( + artifact: Artifact, + cachePolicy: Repository.CachePolicy + ): EitherT[Task, String, String] = { def locally(eitherFile: String \/ File) = { Task { @@ -44,7 +49,7 @@ case class Fetch(root: String, val url = new URL(urlStr) def log = Task(logger.foreach(_.downloading(urlStr))) - def get = Fetch.readFully(url.openStream()) + def get = MavenRepository.readFully(url.openStream()) log.flatMap(_ => get) } @@ -70,7 +75,7 @@ case class Fetch(root: String, } -object Fetch { +object MavenRepository { trait Logger { def downloading(url: String): Unit diff --git a/core-jvm/src/test/scala/coursier/test/compatibility/package.scala b/core-jvm/src/test/scala/coursier/test/compatibility/package.scala index 563d745ac..a08aa54e4 100644 --- a/core-jvm/src/test/scala/coursier/test/compatibility/package.scala +++ b/core-jvm/src/test/scala/coursier/test/compatibility/package.scala @@ -1,6 +1,6 @@ package coursier.test -import coursier.core.Fetch +import coursier.core.MavenRepository import scala.concurrent.{ExecutionContext, Future} import scalaz.concurrent.Task @@ -14,10 +14,12 @@ package object compatibility { } def textResource(path: String)(implicit ec: ExecutionContext): Future[String] = Future { - def is = getClass.getClassLoader - .getResource(path).openStream() + def is = getClass + .getClassLoader + .getResource(path) + .openStream() - new String(Fetch.readFullySync(is), "UTF-8") + new String(MavenRepository.readFullySync(is), "UTF-8") } } diff --git a/core/src/main/scala/coursier/core/Repository.scala b/core/src/main/scala/coursier/core/Repository.scala index 54a3d1745..45b722315 100644 --- a/core/src/main/scala/coursier/core/Repository.scala +++ b/core/src/main/scala/coursier/core/Repository.scala @@ -1,6 +1,6 @@ package coursier.core -import coursier.core.Resolution.ModuleVersion +import coursier.core.Repository.CachePolicy import scalaz.{-\/, \/-, \/, EitherT} import scalaz.concurrent.Task @@ -8,19 +8,21 @@ import scalaz.concurrent.Task import coursier.core.compatibility.encodeURIComponent trait Repository { - def find(module: Module, - version: String, - cachePolicy: Repository.CachePolicy = Repository.CachePolicy.Default): EitherT[Task, String, (Artifact.Source, Project)] + def find( + module: Module, + version: String, + cachePolicy: Repository.CachePolicy = Repository.CachePolicy.Default + ): EitherT[Task, String, (Artifact.Source, Project)] } object Repository { - val mavenCentral = MavenRepository(Fetch("https://repo1.maven.org/maven2/")) + val mavenCentral = MavenRepository("https://repo1.maven.org/maven2/") - val sonatypeReleases = MavenRepository(Fetch("https://oss.sonatype.org/content/repositories/releases/")) - val sonatypeSnapshots = MavenRepository(Fetch("https://oss.sonatype.org/content/repositories/snapshots/")) + val sonatypeReleases = MavenRepository("https://oss.sonatype.org/content/repositories/releases/") + val sonatypeSnapshots = MavenRepository("https://oss.sonatype.org/content/repositories/snapshots/") - lazy val ivy2Local = MavenRepository(Fetch("file://" + sys.props("user.home") + "/.ivy2/local/"), ivyLike = true) + lazy val ivy2Local = MavenRepository("file://" + sys.props("user.home") + "/.ivy2/local/", ivyLike = true) /** @@ -34,9 +36,11 @@ object Repository { * version (e.g. version interval). Which version get chosen depends on * the repository implementation. */ - def find(repositories: Seq[Repository], - module: Module, - version: String): EitherT[Task, Seq[String], (Artifact.Source, Project)] = { + def find( + repositories: Seq[Repository], + module: Module, + version: String + ): EitherT[Task, Seq[String], (Artifact.Source, Project)] = { val lookups = repositories.map(repo => repo -> repo.find(module, version).run) val task = lookups.foldLeft(Task.now(-\/(Nil)): Task[Seq[String] \/ (Artifact.Source, Project)]) { @@ -131,7 +135,7 @@ object Repository { } } -object MavenRepository { +object BaseMavenRepository { def ivyLikePath(org: String, name: String, @@ -154,7 +158,7 @@ object MavenRepository { project: Project): Seq[Artifact] = { def ivyLikePath0(subDir: String, baseSuffix: String, ext: String) = - MavenRepository.ivyLikePath(dependency.module.organization, dependency.module.name, project.version, subDir, baseSuffix, ext) + BaseMavenRepository.ivyLikePath(dependency.module.organization, dependency.module.name, project.version, subDir, baseSuffix, ext) val path = if (ivyLike) @@ -206,13 +210,20 @@ object MavenRepository { } -case class MavenRepository(fetch: Fetch, - ivyLike: Boolean = false) extends Repository { +abstract class BaseMavenRepository( + root: String, + ivyLike: Boolean +) extends Repository { + + def fetch( + artifact: Artifact, + cachePolicy: CachePolicy + ): EitherT[Task, String, String] import Repository._ - import MavenRepository._ + import BaseMavenRepository._ - val source = MavenRepository.Source(fetch.root, ivyLike) + val source = BaseMavenRepository.Source(root, ivyLike) def projectArtifact(module: Module, version: String): Artifact = { val path = ( diff --git a/project/Coursier.scala b/project/Coursier.scala index afe29f9da..6c05d4303 100644 --- a/project/Coursier.scala +++ b/project/Coursier.scala @@ -59,7 +59,8 @@ object CoursierBuild extends Build { organization := "com.github.alexarchambault", scalaVersion := "2.11.6", crossScalaVersions := Seq("2.10.5", "2.11.6"), - resolvers += "Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases" + resolvers += "Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases", + resolvers += Resolver.sonatypeRepo("snapshots") ) ++ publishingSettings private lazy val commonCoreSettings = commonSettings ++ Seq[Setting[_]]( @@ -123,7 +124,7 @@ object CoursierBuild extends Build { .settings( name := "coursier-cli", libraryDependencies ++= Seq( - "com.github.alexarchambault" %% "case-app" % "0.2.2", + "com.github.alexarchambault" %% "case-app" % "0.3.0-SNAPSHOT", "ch.qos.logback" % "logback-classic" % "1.1.3" ) ++ { if (scalaVersion.value startsWith "2.10.") diff --git a/web/src/main/scala/coursier/web/Backend.scala b/web/src/main/scala/coursier/web/Backend.scala index bb9a6cf2c..708ba73c7 100644 --- a/web/src/main/scala/coursier/web/Backend.scala +++ b/web/src/main/scala/coursier/web/Backend.scala @@ -1,7 +1,7 @@ package coursier package web -import coursier.core.{Repository, MavenRepository, Fetch} +import coursier.core.{Repository, BaseMavenRepository, MavenRepository} import japgolly.scalajs.react.vdom.{TagMod, Attr} import japgolly.scalajs.react.vdom.Attrs.dangerouslySetInnerHtml import japgolly.scalajs.react.{ReactEventI, ReactComponentB, BackendScope} @@ -111,7 +111,7 @@ class Backend($: BackendScope[Unit, State]) { g.$("#resLogTab a:last").tab("show") $.modState(_.copy(resolving = true, log = Nil)) - val logger: Fetch.Logger = new Fetch.Logger { + val logger: MavenRepository.Logger = new MavenRepository.Logger { def fetched(url: String) = { println(s"<- $url") $.modState(s => s.copy(log = s"<- $url" +: s.log)) @@ -135,7 +135,7 @@ class Backend($: BackendScope[Unit, State]) { res .process - .run(fetch(s.repositories.map(r => r.copy(fetch = r.fetch.copy(logger = Some(logger))))), 100) + .run(fetch(s.repositories.map(r => r.copy(logger = Some(logger)))), 100) } // For reasons that are unclear to me, not delaying this when using the runNow execution context @@ -246,7 +246,7 @@ object App { )), <.td(Seq[Seq[TagMod]]( res.projectCache.get(dep.moduleVersion) match { - case Some((source: MavenRepository.Source, proj)) if !source.ivyLike => + case Some((source: BaseMavenRepository.Source, proj)) if !source.ivyLike => // FIXME Maven specific, generalize with source.artifacts val version0 = finalVersionOpt getOrElse dep.version val relPath = @@ -401,14 +401,14 @@ object App { def repoItem(repo: MavenRepository) = <.tr( <.td( - <.a(^.href := repo.fetch.root, - repo.fetch.root + <.a(^.href := repo.root, + repo.root ) ) ) val sortedRepos = repos - .sortBy(repo => repo.fetch.root) + .sortBy(repo => repo.root) <.table(^.`class` := "table", <.thead(