diff --git a/build.sbt b/build.sbt index c532a9c64..116a003be 100644 --- a/build.sbt +++ b/build.sbt @@ -220,6 +220,13 @@ lazy val cache = project import com.typesafe.tools.mima.core.ProblemFilters._ Seq( + // Since 1.0.0-M10 + // cache argument type changed from `Seq[(String, File)]` to `File` + ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.Cache.file"), + ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.Cache.fetch"), + ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.Cache.default"), + ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.Cache.validateChecksum"), + ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache.defaultBase"), // Since 1.0.0-M9 // Added an optional extra parameter to FileError.NotFound - only // its unapply method should break compatibility at the source level. diff --git a/cache/src/main/scala/coursier/Cache.scala b/cache/src/main/scala/coursier/Cache.scala index dd8d1cbb3..16a134020 100644 --- a/cache/src/main/scala/coursier/Cache.scala +++ b/cache/src/main/scala/coursier/Cache.scala @@ -43,25 +43,30 @@ object Cache { } } - private def withLocal(artifact: Artifact, cache: Seq[(String, File)]): Artifact = { + private def withLocal(artifact: Artifact, cache: File): Artifact = { def local(url: String) = if (url.startsWith("file:///")) url.stripPrefix("file://") else if (url.startsWith("file:/")) url.stripPrefix("file:") - else { - val localPathOpt = cache.collectFirst { - case (base, cacheDir) if url.startsWith(base) => - cacheDir.toString + "/" + escape(url.stripPrefix(base)) - } + else + // FIXME Should we fully parse the URL here? + // FIXME Should some safeguards be added against '..' components in paths? + url.split(":", 2) match { + case Array(protocol, remaining) => + val remaining0 = + if (remaining.startsWith("///")) + remaining.stripPrefix("///") + else if (remaining.startsWith("/")) + remaining.stripPrefix("/") + else + throw new Exception(s"URL $url doesn't contain an absolute path") - localPathOpt.getOrElse { - // FIXME Means we were handed an artifact from repositories other than the known ones - println(cache.mkString("\n")) - println(url) - ??? + new File(cache, escape(protocol + "/" + remaining0)) .toString + + case _ => + throw new Exception(s"No protocol found in URL $url") } - } if (artifact.extra.contains("local")) artifact @@ -180,7 +185,7 @@ object Cache { private def download( artifact: Artifact, - cache: Seq[(String, File)], + cache: File, checksums: Set[String], cachePolicy: CachePolicy, pool: ExecutorService, @@ -460,7 +465,7 @@ object Cache { def validateChecksum( artifact: Artifact, sumType: String, - cache: Seq[(String, File)], + cache: File, pool: ExecutorService ): EitherT[Task, FileError, Unit] = { @@ -514,7 +519,7 @@ object Cache { def file( artifact: Artifact, - cache: Seq[(String, File)] = default, + cache: File = default, cachePolicy: CachePolicy = CachePolicy.FetchMissing, checksums: Seq[Option[String]] = defaultChecksums, logger: Option[Logger] = None, @@ -565,7 +570,7 @@ object Cache { } def fetch( - cache: Seq[(String, File)] = default, + cache: File = default, cachePolicy: CachePolicy = CachePolicy.FetchMissing, checksums: Seq[Option[String]] = defaultChecksums, logger: Option[Logger] = None, @@ -613,18 +618,13 @@ object Cache { dropInfoAttributes = true ) - lazy val defaultBase = new File( + lazy val default = new File( sys.env.getOrElse( "COURSIER_CACHE", sys.props("user.home") + "/.coursier/cache/v1" ) ).getAbsoluteFile - lazy val default = Seq( - "http://" -> new File(defaultBase, "http"), - "https://" -> new File(defaultBase, "https") - ) - val defaultConcurrentDownloadCount = 6 lazy val defaultPool = diff --git a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala index 980d6f934..acb715e94 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala @@ -74,7 +74,7 @@ case class CommonOptions( case class CacheOptions( @Help("Cache directory (defaults to environment variable COURSIER_CACHE or ~/.coursier/cache/v1)") @Short("C") - cache: String = Cache.defaultBase.toString + cache: String = Cache.default.toString ) sealed abstract class CoursierCommand extends Command diff --git a/cli/src/main/scala-2.11/coursier/cli/Helper.scala b/cli/src/main/scala-2.11/coursier/cli/Helper.scala index 46932bd93..7f9ddf768 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Helper.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Helper.scala @@ -77,11 +77,7 @@ class Helper( ) } - val caches = - Seq( - "http://" -> new File(new File(cacheOptions.cache), "http"), - "https://" -> new File(new File(cacheOptions.cache), "https") - ) + val cache = new File(cacheOptions.cache) val pool = Executors.newFixedThreadPool(parallel, Strategy.DefaultDaemonThreadFactory) @@ -200,7 +196,7 @@ class Helper( None val fetchs = cachePolicies.map(p => - Cache.fetch(caches, p, checksums = checksums, logger = logger, pool = pool) + Cache.fetch(cache, p, checksums = checksums, logger = logger, pool = pool) ) val fetchQuiet = coursier.Fetch.from( repositories, @@ -332,8 +328,8 @@ class Helper( println(s" Found ${artifacts0.length} artifacts") val tasks = artifacts0.map(artifact => - (Cache.file(artifact, caches, cachePolicies.head, checksums = checksums, logger = logger, pool = pool) /: cachePolicies.tail)( - _ orElse Cache.file(artifact, caches, _, checksums = checksums, logger = logger, pool = pool) + (Cache.file(artifact, cache, cachePolicies.head, checksums = checksums, logger = logger, pool = pool) /: cachePolicies.tail)( + _ orElse Cache.file(artifact, cache, _, checksums = checksums, logger = logger, pool = pool) ).run.map(artifact.->) ) diff --git a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala index 1db20628f..9cf1f2946 100644 --- a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala +++ b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala @@ -39,7 +39,7 @@ object CoursierPlugin extends AutoPlugin { coursierVerbosity := 1, coursierResolvers <<= Tasks.coursierResolversTask, coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers, - coursierCache := Cache.defaultBase, + coursierCache := Cache.default, update <<= Tasks.updateTask(withClassifiers = false), updateClassifiers <<= Tasks.updateTask(withClassifiers = true), updateSbtClassifiers in Defaults.TaskGlobal <<= Tasks.updateTask(withClassifiers = true, sbtClassifiers = true), diff --git a/plugin/src/main/scala-2.10/coursier/Tasks.scala b/plugin/src/main/scala-2.10/coursier/Tasks.scala index b88058e75..fc48b39da 100644 --- a/plugin/src/main/scala-2.10/coursier/Tasks.scala +++ b/plugin/src/main/scala-2.10/coursier/Tasks.scala @@ -215,7 +215,7 @@ object Tasks { val artifactsChecksums = coursierArtifactsChecksums.value val maxIterations = coursierMaxIterations.value val cachePolicy = coursierCachePolicy.value - val cacheDir = coursierCache.value + val cache = coursierCache.value val sv = scalaVersion.value // is this always defined? (e.g. for Java only projects?) @@ -273,11 +273,6 @@ object Tasks { val repositories = Seq(globalPluginsRepo, interProjectRepo) ++ resolvers.flatMap(FromSbt.repository(_, ivyProperties)) - val caches = Seq( - "http://" -> new File(cacheDir, "http"), - "https://" -> new File(cacheDir, "https") - ) - val pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory) def createLogger() = new TermDisplay(new OutputStreamWriter(System.err)) @@ -286,8 +281,8 @@ object Tasks { val fetch = Fetch.from( repositories, - Cache.fetch(caches, CachePolicy.LocalOnly, checksums = checksums, logger = Some(resLogger), pool = pool), - Cache.fetch(caches, cachePolicy, checksums = checksums, logger = Some(resLogger), pool = pool) + Cache.fetch(cache, CachePolicy.LocalOnly, checksums = checksums, logger = Some(resLogger), pool = pool), + Cache.fetch(cache, cachePolicy, checksums = checksums, logger = Some(resLogger), pool = pool) ) def depsRepr(deps: Seq[(String, Dependency)]) = @@ -411,7 +406,7 @@ object Tasks { val artifactsLogger = createLogger() val artifactFileOrErrorTasks = allArtifacts.toVector.map { a => - Cache.file(a, caches, cachePolicy, checksums = artifactsChecksums, logger = Some(artifactsLogger), pool = pool).run.map((a, _)) + Cache.file(a, cache, cachePolicy, checksums = artifactsChecksums, logger = Some(artifactsLogger), pool = pool).run.map((a, _)) } if (verbosity >= 0) diff --git a/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala b/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala index f48875a18..a08755b03 100644 --- a/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala +++ b/tests/jvm/src/test/scala/coursier/test/ChecksumTests.scala @@ -37,10 +37,7 @@ object ChecksumTests extends TestSuite { val cachePath = getClass.getResource("/checksums").getPath - val cache = Seq( - "http://" -> new File(cachePath), - "https://" -> new File(cachePath) - ) + val cache = new File(cachePath) def validate(artifact: Artifact, sumType: String) = Cache.validateChecksum(