diff --git a/build.sbt b/build.sbt index 3fd808f3c..a7d28fc97 100644 --- a/build.sbt +++ b/build.sbt @@ -219,6 +219,7 @@ lazy val cli = project .settings(commonSettings) .settings(noPublish210Settings) .settings(packAutoSettings) + .settings(proguardSettings) .settings( name := "coursier-cli", libraryDependencies ++= { @@ -229,7 +230,15 @@ lazy val cli = project }, resourceGenerators in Compile += packageBin.in(bootstrap).in(Compile).map { jar => Seq(jar) - }.taskValue + }.taskValue, + ProguardKeys.proguardVersion in Proguard := "5.2.1", + ProguardKeys.options in Proguard ++= Seq( + "-dontwarn", + "-keep class coursier.cli.Coursier {\n public static void main(java.lang.String[]);\n}", + "-keep class coursier.cli.IsolatedClassLoader {\n public java.lang.String[] getIsolationTargets();\n}" + ), + javaOptions in (Proguard, ProguardKeys.proguard) := Seq("-Xmx3172M"), + artifactPath in Proguard := (ProguardKeys.proguardDirectory in Proguard).value / "coursier-standalone.jar" ) lazy val web = project diff --git a/cache/src/main/scala/coursier/Cache.scala b/cache/src/main/scala/coursier/Cache.scala index af10e8168..846828393 100644 --- a/cache/src/main/scala/coursier/Cache.scala +++ b/cache/src/main/scala/coursier/Cache.scala @@ -357,8 +357,8 @@ object Cache { artifact0.checksumUrls.get(sumType) match { case Some(sumFile) => Task { - val sum = scala.io.Source.fromFile(sumFile) - .getLines() + val sum = new String(NioFiles.readAllBytes(new File(sumFile).toPath), "UTF-8") + .linesIterator .toStream .headOption .mkString @@ -471,7 +471,7 @@ object Cache { pool = pool ).leftMap(_.message).map { f => // FIXME Catch error here? - scala.io.Source.fromFile(f)("UTF-8").mkString + new String(NioFiles.readAllBytes(f.toPath), "UTF-8") } } @@ -571,31 +571,29 @@ object Cache { } -sealed trait FileError extends Product with Serializable { - def message: String -} +sealed abstract class FileError(val message: String) extends Product with Serializable object FileError { - case class DownloadError(message0: String) extends FileError { - def message = s"Download error: $message0" - } - case class NotFound(file: String) extends FileError { - def message = s"Not found: $file" - } - case class ChecksumNotFound(sumType: String, file: String) extends FileError { - def message = s"$sumType checksum not found: $file" - } - case class WrongChecksum(sumType: String, got: String, expected: String, file: String, sumFile: String) extends FileError { - def message = s"$sumType checksum validation failed: $file" - } + final case class DownloadError(reason: String) extends FileError(s"Download error: $reason") - sealed trait Recoverable extends FileError - case class Locked(file: File) extends Recoverable { - def message = s"Locked: $file" - } - case class ConcurrentDownload(url: String) extends Recoverable { - def message = s"Concurrent download: $url" - } + final case class NotFound(file: String) extends FileError(s"Not found: $file") + + final case class ChecksumNotFound( + sumType: String, + file: String + ) extends FileError(s"$sumType checksum not found: $file") + + final case class WrongChecksum( + sumType: String, + got: String, + expected: String, + file: String, + sumFile: String + ) extends FileError(s"$sumType checksum validation failed: $file") + + sealed abstract class Recoverable(message: String) extends FileError(message) + final case class Locked(file: File) extends Recoverable(s"Locked: $file") + final case class ConcurrentDownload(url: String) extends Recoverable(s"Concurrent download: $url") } diff --git a/cache/src/main/scala/coursier/CachePolicy.scala b/cache/src/main/scala/coursier/CachePolicy.scala index 0bf51e6e3..2e739640a 100644 --- a/cache/src/main/scala/coursier/CachePolicy.scala +++ b/cache/src/main/scala/coursier/CachePolicy.scala @@ -1,6 +1,6 @@ package coursier -sealed trait CachePolicy extends Product with Serializable +sealed abstract class CachePolicy extends Product with Serializable object CachePolicy { case object LocalOnly extends CachePolicy 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 64db345eb..d1a8af958 100644 --- a/cli/src/main/scala-2.11/coursier/cli/Coursier.scala +++ b/cli/src/main/scala-2.11/coursier/cli/Coursier.scala @@ -62,7 +62,7 @@ case class CacheOptions( cache: String = Cache.defaultBase.toString ) -sealed trait CoursierCommand extends Command +sealed abstract class CoursierCommand extends Command case class Resolve( @Recurse diff --git a/core/shared/src/main/scala/coursier/core/Definitions.scala b/core/shared/src/main/scala/coursier/core/Definitions.scala index 57a7c6c69..f178a0cab 100644 --- a/core/shared/src/main/scala/coursier/core/Definitions.scala +++ b/core/shared/src/main/scala/coursier/core/Definitions.scala @@ -9,7 +9,7 @@ package coursier.core * * Using the same terminology as Ivy. */ -case class Module( +final case class Module( organization: String, name: String, attributes: Map[String, String] @@ -28,6 +28,8 @@ case class Module( override def toString = s"$organization:$name" + (if (attributes.nonEmpty) s";$attributesStr" else "") + + override final lazy val hashCode = Module.unapply(this).get.hashCode() } /** @@ -36,7 +38,7 @@ case class Module( * The remaining fields are left untouched, some being transitively * propagated (exclusions, optional, in particular). */ -case class Dependency( +final case class Dependency( module: Module, version: String, configuration: String, @@ -48,11 +50,13 @@ case class Dependency( transitive: Boolean ) { - def moduleVersion = (module, version) + lazy val moduleVersion = (module, version) + + override lazy val hashCode = Dependency.unapply(this).get.hashCode() } // Maven-specific -case class Attributes( +final case class Attributes( `type`: String, classifier: String ) { @@ -60,7 +64,7 @@ case class Attributes( Publication(name, `type`, ext, classifier) } -case class Project( +final case class Project( module: Module, version: String, // First String is configuration (scope for Maven) @@ -83,7 +87,7 @@ case class Project( // Extra infos, not used during resolution info: Info ) { - def moduleVersion = (module, version) + lazy val moduleVersion = (module, version) /** All configurations that each configuration extends, including the ones it extends transitively */ lazy val allConfigurations: Map[String, Set[String]] = @@ -91,7 +95,7 @@ case class Project( } /** Extra project info, not used during resolution */ -case class Info( +final case class Info( description: String, homePage: String, licenses: Seq[(String, Option[String])], @@ -100,7 +104,7 @@ case class Info( ) object Info { - case class Developer( + final case class Developer( id: String, name: String, url: String @@ -110,10 +114,10 @@ object Info { } // Maven-specific -case class Activation(properties: Seq[(String, Option[String])]) +final case class Activation(properties: Seq[(String, Option[String])]) // Maven-specific -case class Profile( +final case class Profile( id: String, activeByDefault: Option[Boolean], activation: Activation, @@ -123,7 +127,7 @@ case class Profile( ) // Maven-specific -case class Versions( +final case class Versions( latest: String, release: String, available: List[String], @@ -131,7 +135,7 @@ case class Versions( ) object Versions { - case class DateTime( + final case class DateTime( year: Int, month: Int, day: Int, @@ -142,7 +146,7 @@ object Versions { } // Maven-specific -case class SnapshotVersion( +final case class SnapshotVersion( classifier: String, extension: String, value: String, @@ -150,7 +154,7 @@ case class SnapshotVersion( ) // Maven-specific -case class SnapshotVersioning( +final case class SnapshotVersioning( module: Module, version: String, latest: String, @@ -163,7 +167,7 @@ case class SnapshotVersioning( ) // Ivy-specific -case class Publication( +final case class Publication( name: String, `type`: String, ext: String, @@ -172,7 +176,7 @@ case class Publication( def attributes: Attributes = Attributes(`type`, classifier) } -case class Artifact( +final case class Artifact( url: String, checksumUrls: Map[String, String], extra: Map[String, Artifact], diff --git a/core/shared/src/main/scala/coursier/core/Resolution.scala b/core/shared/src/main/scala/coursier/core/Resolution.scala index ed3304d5e..8a2eb6b28 100644 --- a/core/shared/src/main/scala/coursier/core/Resolution.scala +++ b/core/shared/src/main/scala/coursier/core/Resolution.scala @@ -1,9 +1,10 @@ package coursier.core +import java.util.concurrent.ConcurrentHashMap import java.util.regex.Pattern.quote import scala.annotation.tailrec -import scala.collection.mutable +import scala.collection.JavaConverters._ import scalaz.{ \/-, -\/ } object Resolution { @@ -76,7 +77,7 @@ object Resolution { def substituteProps(s: String, properties: Map[String, String]) = { val matches = propRegex .findAllMatchIn(s) - .toList + .toVector .reverse if (matches.isEmpty) s @@ -172,7 +173,7 @@ object Resolution { ): (Seq[Dependency], Seq[Dependency], Map[Module, String]) = { val mergedByModVer = dependencies - .toList + .toVector .groupBy(dep => dep.module) .map { case (module, deps) => module -> { @@ -203,7 +204,7 @@ object Resolution { val merged = mergedByModVer .values - .toList + .toVector ( merged @@ -424,35 +425,60 @@ object Resolution { * @param projectCache: cache of known projects * @param errorCache: keeps track of the modules whose project definition could not be found */ -case class Resolution( +final case class Resolution( rootDependencies: Set[Dependency], dependencies: Set[Dependency], forceVersions: Map[Module, String], conflicts: Set[Dependency], projectCache: Map[Resolution.ModuleVersion, (Artifact.Source, Project)], errorCache: Map[Resolution.ModuleVersion, Seq[String]], + finalDependenciesCache: Map[Dependency, Seq[Dependency]], filter: Option[Dependency => Boolean], profileActivation: Option[(String, Activation, Map[String, String]) => Boolean] ) { + def copyWithCache( + rootDependencies: Set[Dependency] = rootDependencies, + dependencies: Set[Dependency] = dependencies, + forceVersions: Map[Module, String] = forceVersions, + conflicts: Set[Dependency] = conflicts, + projectCache: Map[Resolution.ModuleVersion, (Artifact.Source, Project)] = projectCache, + errorCache: Map[Resolution.ModuleVersion, Seq[String]] = errorCache, + filter: Option[Dependency => Boolean] = filter, + profileActivation: Option[(String, Activation, Map[String, String]) => Boolean] = profileActivation + ): Resolution = + copy( + rootDependencies, + dependencies, + forceVersions, + conflicts, + projectCache, + errorCache, + finalDependenciesCache ++ finalDependenciesCache0.asScala, + filter, + profileActivation + ) + import Resolution._ - private val finalDependenciesCache = - new mutable.HashMap[Dependency, Seq[Dependency]]() - private def finalDependencies0(dep: Dependency) = - finalDependenciesCache.synchronized { - finalDependenciesCache.getOrElseUpdate(dep, { - if (dep.transitive) - projectCache.get(dep.moduleVersion) match { - case Some((_, proj)) => - finalDependencies(dep, proj) - .filter(filter getOrElse defaultFilter) - case None => Nil - } - else - Nil - }) - } + private[core] val finalDependenciesCache0 = new ConcurrentHashMap[Dependency, Seq[Dependency]] + + private def finalDependencies0(dep: Dependency): Seq[Dependency] = + if (dep.transitive) { + val deps = finalDependenciesCache.getOrElse(dep, finalDependenciesCache0.get(dep)) + + if (deps == null) + projectCache.get(dep.moduleVersion) match { + case Some((_, proj)) => + val res = finalDependencies(dep, proj).filter(filter getOrElse defaultFilter) + finalDependenciesCache0.put(dep, res) + res + case None => Nil + } + else + deps + } else + Nil /** * Transitive dependencies of the current dependencies, according to @@ -460,9 +486,9 @@ case class Resolution( * * No attempt is made to solve version conflicts here. */ - def transitiveDependencies: Seq[Dependency] = + lazy val transitiveDependencies: Seq[Dependency] = (dependencies -- conflicts) - .toList + .toVector .flatMap(finalDependencies0) /** @@ -476,7 +502,7 @@ case class Resolution( * Returns a tuple made of the conflicting dependencies, all * the dependencies, and the retained version of each module. */ - def nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency], Map[Module, String]) = + lazy val nextDependenciesAndConflicts: (Seq[Dependency], Seq[Dependency], Map[Module, String]) = // TODO Provide the modules whose version was forced by dependency overrides too merge( rootDependencies.map(withDefaultConfig) ++ dependencies ++ transitiveDependencies, @@ -486,7 +512,7 @@ case class Resolution( /** * The modules we miss some info about. */ - def missingFromCache: Set[ModuleVersion] = { + lazy val missingFromCache: Set[ModuleVersion] = { val modules = dependencies .map(_.moduleVersion) val nextModules = nextDependenciesAndConflicts._2 @@ -500,7 +526,7 @@ case class Resolution( /** * Whether the resolution is done. */ - def isDone: Boolean = { + lazy val isDone: Boolean = { def isFixPoint = { val (nextConflicts, _, _) = nextDependenciesAndConflicts @@ -520,7 +546,7 @@ case class Resolution( * * The versions of all the dependencies returned are erased (emptied). */ - def reverseDependencies: Map[Dependency, Vector[Dependency]] = { + lazy val reverseDependencies: Map[Dependency, Vector[Dependency]] = { val (updatedConflicts, updatedDeps, _) = nextDependenciesAndConflicts val trDepsSeq = @@ -546,7 +572,7 @@ case class Resolution( * * The versions of all the dependencies returned are erased (emptied). */ - def remainingDependencies: Set[Dependency] = { + lazy val remainingDependencies: Set[Dependency] = { val rootDependencies0 = rootDependencies .map(withDefaultConfig) .map(eraseVersion) @@ -568,7 +594,7 @@ case class Resolution( broughtBy .filter(x => remaining.contains(x) || rootDependencies0(x)) ) - .toList + .toVector .toMap ) } @@ -581,7 +607,7 @@ case class Resolution( /** * The final next dependency set, stripped of no more required ones. */ - def newDependencies: Set[Dependency] = { + lazy val newDependencies: Set[Dependency] = { val remainingDependencies0 = remainingDependencies nextDependenciesAndConflicts._2 @@ -589,10 +615,10 @@ case class Resolution( .toSet } - private def nextNoMissingUnsafe: Resolution = { + private lazy val nextNoMissingUnsafe: Resolution = { val (newConflicts, _, _) = nextDependenciesAndConflicts - copy( + copyWithCache( dependencies = newDependencies ++ newConflicts, conflicts = newConflicts.toSet ) @@ -856,7 +882,7 @@ case class Resolution( newDeps } - copy( + copyWithCache( rootDependencies = dependencies, dependencies = helper(dependencies.map(updateVersion)) // don't know if something should be done about conflicts diff --git a/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala b/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala index 4ea83f9d0..8d6f3b43f 100644 --- a/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala +++ b/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala @@ -5,7 +5,7 @@ import scalaz._ import scala.annotation.tailrec -sealed trait ResolutionProcess { +sealed abstract class ResolutionProcess { def run[F[_]]( fetch: Fetch.Metadata[F], maxIterations: Int = 50 @@ -52,7 +52,7 @@ sealed trait ResolutionProcess { def current: Resolution } -case class Missing( +final case class Missing( missing: Seq[(Module, String)], current: Resolution, cont: Resolution => ResolutionProcess @@ -74,7 +74,7 @@ case class Missing( def cont0(res: Resolution) = { val res0 = successes.foldLeft(res){case (acc, (modVer, (source, proj))) => - acc.copy(projectCache = acc.projectCache + ( + acc.copyWithCache(projectCache = acc.projectCache + ( modVer -> (source, acc.withDependencyManagement(proj)) )) } @@ -83,7 +83,7 @@ case class Missing( } val current0 = current - .copy(errorCache = current.errorCache ++ errors) + .copyWithCache(errorCache = current.errorCache ++ errors) if (depMgmtMissing.isEmpty) cont0(current0) @@ -93,7 +93,7 @@ case class Missing( } -case class Continue( +final case class Continue( current: Resolution, cont: Resolution => ResolutionProcess ) extends ResolutionProcess { @@ -108,7 +108,7 @@ case class Continue( } -case class Done(resolution: Resolution) extends ResolutionProcess { +final case class Done(resolution: Resolution) extends ResolutionProcess { def current: Resolution = resolution } diff --git a/core/shared/src/main/scala/coursier/core/Version.scala b/core/shared/src/main/scala/coursier/core/Version.scala index b15d3f9ff..34da4d71d 100644 --- a/core/shared/src/main/scala/coursier/core/Version.scala +++ b/core/shared/src/main/scala/coursier/core/Version.scala @@ -20,7 +20,7 @@ case class Version(repr: String) extends Ordered[Version] { object Version { - sealed trait Item extends Ordered[Item] { + sealed abstract class Item extends Ordered[Item] { def compare(other: Item): Int = (this, other) match { case (Number(a), Number(b)) => a.compare(b) @@ -43,27 +43,27 @@ object Version { def compareToEmpty: Int = 1 } - sealed trait Numeric extends Item { + sealed abstract class Numeric extends Item { def repr: String def next: Numeric } - case class Number(value: Int) extends Numeric { + final case class Number(value: Int) extends Numeric { val order = 0 def next: Number = Number(value + 1) def repr: String = value.toString override def compareToEmpty = value.compare(0) } - case class BigNumber(value: BigInt) extends Numeric { + final case class BigNumber(value: BigInt) extends Numeric { val order = 0 def next: BigNumber = BigNumber(value + 1) def repr: String = value.toString override def compareToEmpty = value.compare(0) } - case class Qualifier(value: String, level: Int) extends Item { + final case class Qualifier(value: String, level: Int) extends Item { val order = -2 override def compareToEmpty = level.compare(0) } - case class Literal(value: String) extends Item { + final case class Literal(value: String) extends Item { val order = -1 override def compareToEmpty = if (value.isEmpty) 0 else 1 } @@ -93,7 +93,7 @@ object Version { val qualifiersMap = qualifiers.map(q => q.value -> q).toMap object Tokenizer { - sealed trait Separator + sealed abstract class Separator case object Dot extends Separator case object Hyphen extends Separator case object Underscore extends Separator diff --git a/core/shared/src/main/scala/coursier/core/Versions.scala b/core/shared/src/main/scala/coursier/core/Versions.scala index ae4877200..5398f262c 100644 --- a/core/shared/src/main/scala/coursier/core/Versions.scala +++ b/core/shared/src/main/scala/coursier/core/Versions.scala @@ -82,21 +82,23 @@ object VersionInterval { val zero = VersionInterval(None, None, fromIncluded = false, toIncluded = false) } -sealed trait VersionConstraint { - def interval: VersionInterval - def repr: String -} +sealed abstract class VersionConstraint( + val interval: VersionInterval, + val repr: String +) + object VersionConstraint { /** Currently treated as minimum... */ - case class Preferred(version: Version) extends VersionConstraint { - def interval: VersionInterval = VersionInterval(Some(version), Option.empty, fromIncluded = true, toIncluded = false) - def repr: String = version.repr - } - case class Interval(interval: VersionInterval) extends VersionConstraint { - def repr: String = interval.repr - } - case object None extends VersionConstraint { - val interval = VersionInterval.zero - def repr: String = "" // Once parsed, "(,)" becomes "" because of this - } -} \ No newline at end of file + final case class Preferred(version: Version) extends VersionConstraint( + VersionInterval(Some(version), Option.empty, fromIncluded = true, toIncluded = false), + version.repr + ) + final case class Interval(interval0: VersionInterval) extends VersionConstraint( + interval0, + interval0.repr + ) + case object None extends VersionConstraint( + VersionInterval.zero, + "" // Once parsed, "(,)" becomes "" because of this + ) +} diff --git a/core/shared/src/main/scala/coursier/ivy/Pattern.scala b/core/shared/src/main/scala/coursier/ivy/Pattern.scala index 5054bd6dc..820fad6d0 100644 --- a/core/shared/src/main/scala/coursier/ivy/Pattern.scala +++ b/core/shared/src/main/scala/coursier/ivy/Pattern.scala @@ -23,7 +23,7 @@ object Pattern { def apply(content: String): Map[String, String] => String \/ String } object PatternPart { - case class Literal(override val effectiveStart: Int, override val effectiveEnd: Int) extends PatternPart(effectiveStart, effectiveEnd) { + final case class Literal(override val effectiveStart: Int, override val effectiveEnd: Int) extends PatternPart(effectiveStart, effectiveEnd) { def apply(content: String): Map[String, String] => String \/ String = { assert(content.length == effectiveEnd - effectiveStart) val matches = variableRegex.findAllMatchIn(content).toList @@ -54,7 +54,7 @@ object Pattern { helper(0, matches, new StringBuilder) } } - case class Optional(start0: Int, end0: Int) extends PatternPart(start0 + 1, end0 - 1) { + final case class Optional(start0: Int, end0: Int) extends PatternPart(start0 + 1, end0 - 1) { override def start = start0 override def end = end0 @@ -78,7 +78,7 @@ object Pattern { } -case class Pattern( +final case class Pattern( pattern: String, properties: Map[String, String] ) { diff --git a/core/shared/src/main/scala/coursier/package.scala b/core/shared/src/main/scala/coursier/package.scala index d15ba3985..15ab6efb4 100644 --- a/core/shared/src/main/scala/coursier/package.scala +++ b/core/shared/src/main/scala/coursier/package.scala @@ -70,6 +70,7 @@ package object coursier { conflicts: Set[Dependency] = Set.empty, projectCache: Map[ModuleVersion, (Artifact.Source, Project)] = Map.empty, errorCache: Map[ModuleVersion, Seq[String]] = Map.empty, + finalDependencies: Map[Dependency, Seq[Dependency]] = Map.empty, filter: Option[Dependency => Boolean] = None, profileActivation: Option[(String, core.Activation, Map[String, String]) => Boolean] = None ): Resolution = @@ -80,6 +81,7 @@ package object coursier { conflicts, projectCache, errorCache, + finalDependencies, filter, profileActivation ) diff --git a/core/shared/src/main/scala/coursier/util/Properties.scala b/core/shared/src/main/scala/coursier/util/Properties.scala index 365c182ea..d521c1ed7 100644 --- a/core/shared/src/main/scala/coursier/util/Properties.scala +++ b/core/shared/src/main/scala/coursier/util/Properties.scala @@ -1,11 +1,11 @@ package coursier.util -import java.util.Properties +import java.util.{ Properties => JProperties } object Properties { private lazy val props = { - val p = new Properties() + val p = new JProperties() p.load( getClass .getClassLoader diff --git a/coursier-standalone b/coursier-standalone index 5419cf784..14c18fecb 100755 Binary files a/coursier-standalone and b/coursier-standalone differ diff --git a/project/generate-standalone-launcher.sh b/project/generate-standalone-launcher.sh index 791e9f2d6..2109a34f3 100755 --- a/project/generate-standalone-launcher.sh +++ b/project/generate-standalone-launcher.sh @@ -23,6 +23,10 @@ cat >> coursier.pro << EOF -keep class coursier.cli.Coursier { public static void main(java.lang.String[]); } + +-keep class coursier.cli.IsolatedClassLoader { + public java.lang.String[] getIsolationTargets(); +} EOF # -noverify added in launcher below because of errors like diff --git a/project/plugins.sbt b/project/plugins.sbt index 0d8c0281b..3e1a804b9 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,3 +4,4 @@ addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.1.0") addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.0") addSbtPlugin("com.github.alexarchambault" % "coursier-sbt-plugin" % "1.0.0-M4") +addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2") diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index db05027ee..76ef8b9ac 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -90,8 +90,7 @@ object CentralTests extends TestSuite { 'logback{ async { val dep = Dependency(Module("ch.qos.logback", "logback-classic"), "1.1.3") - val res = await(resolve(Set(dep))) - .copy(projectCache = Map.empty, errorCache = Map.empty) // No validating these here + val res = await(resolve(Set(dep))).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -106,8 +105,7 @@ object CentralTests extends TestSuite { 'asm{ async { val dep = Dependency(Module("org.ow2.asm", "asm-commons"), "5.0.2") - val res = await(resolve(Set(dep))) - .copy(projectCache = Map.empty, errorCache = Map.empty) // No validating these here + val res = await(resolve(Set(dep))).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -123,7 +121,7 @@ object CentralTests extends TestSuite { async { val dep = Dependency(Module("joda-time", "joda-time"), "[2.2,2.8]") val res0 = await(resolve(Set(dep))) - val res = res0.copy(projectCache = Map.empty, errorCache = Map.empty) + val res = res0.clearCaches val expected = Resolution( rootDependencies = Set(dep), diff --git a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala index c83a9ddd5..a47c54967 100644 --- a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala @@ -203,7 +203,7 @@ object ResolutionTests extends TestSuite { val dep = Dependency(Module("acme", "config"), "1.3.0") val res = await(resolve0( Set(dep) - )) + )).clearFinalDependenciesCache val expected = Resolution( rootDependencies = Set(dep), @@ -220,7 +220,7 @@ object ResolutionTests extends TestSuite { val trDep = Dependency(Module("acme", "play-json"), "2.4.0") val res = await(resolve0( Set(dep) - )) + )).clearFinalDependenciesCache val expected = Resolution( rootDependencies = Set(dep), @@ -243,7 +243,7 @@ object ResolutionTests extends TestSuite { ) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -264,7 +264,7 @@ object ResolutionTests extends TestSuite { ) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -285,7 +285,7 @@ object ResolutionTests extends TestSuite { ) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -300,7 +300,7 @@ object ResolutionTests extends TestSuite { val dep = Dependency(Module("hudsucker", "mail"), "10.0") val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -319,7 +319,7 @@ object ResolutionTests extends TestSuite { ) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -337,7 +337,7 @@ object ResolutionTests extends TestSuite { Dependency(Module("org.gnome", "desktop"), "7.0")) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -354,7 +354,7 @@ object ResolutionTests extends TestSuite { Dependency(Module("gov.nsa", "secure-pgp"), "10.0", exclusions = Set(("*", "crypto")))) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -369,7 +369,7 @@ object ResolutionTests extends TestSuite { val dep = Dependency(Module("com.thoughtworks.paranamer", "paranamer"), "2.6") val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -386,7 +386,7 @@ object ResolutionTests extends TestSuite { Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -405,7 +405,7 @@ object ResolutionTests extends TestSuite { Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -426,7 +426,7 @@ object ResolutionTests extends TestSuite { Dependency(Module("org.escalier", "librairie-standard"), "2.11.6")) val res = await(resolve0( Set(dep) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = Set(dep), @@ -447,7 +447,7 @@ object ResolutionTests extends TestSuite { val res = await(resolve0( Set(dep), filter = Some(_ => true) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches.clearFilter val expected = Resolution( rootDependencies = Set(dep), @@ -470,7 +470,7 @@ object ResolutionTests extends TestSuite { val res = await(resolve0( deps, filter = Some(_ => true) - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches.clearFilter val expected = Resolution( rootDependencies = deps, @@ -492,7 +492,7 @@ object ResolutionTests extends TestSuite { val res = await(resolve0( deps, forceVersions = depOverrides - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = deps, @@ -516,7 +516,7 @@ object ResolutionTests extends TestSuite { val res = await(resolve0( deps, forceVersions = depOverrides - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = deps, @@ -542,7 +542,7 @@ object ResolutionTests extends TestSuite { val res = await(resolve0( deps, forceVersions = depOverrides - )).copy(filter = None, projectCache = Map.empty, errorCache = Map.empty) + )).clearCaches val expected = Resolution( rootDependencies = deps, diff --git a/tests/shared/src/test/scala/coursier/test/package.scala b/tests/shared/src/test/scala/coursier/test/package.scala index 30fa8f3ea..7fe13dce0 100644 --- a/tests/shared/src/test/scala/coursier/test/package.scala +++ b/tests/shared/src/test/scala/coursier/test/package.scala @@ -6,6 +6,24 @@ package object test { def withCompileScope: Dependency = underlying.copy(configuration = "compile") } + implicit class ResolutionOps(val underlying: Resolution) extends AnyVal { + + // The content of these fields is typically not validated in the tests. + // It can be cleared with these method to it easier to compare `underlying` + // to an expected value. + + def clearFinalDependenciesCache: Resolution = + underlying.copy(finalDependenciesCache = Map.empty) + def clearCaches: Resolution = + underlying.copy( + projectCache = Map.empty, + errorCache = Map.empty, + finalDependenciesCache = Map.empty + ) + def clearFilter: Resolution = + underlying.copy(filter = None) + } + object Profile { type Activation = core.Activation object Activation {