Merge pull request #1620 from sbt/fix/1620

sbt resolves dependencies every compile when using %% with dependencyOverrides
This commit is contained in:
Josh Suereth 2014-12-15 16:04:18 -05:00
commit c8fc6d0223
7 changed files with 168 additions and 10 deletions

View File

@ -34,12 +34,42 @@ final class InlineIvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resol
checksums: Seq[String], resolutionCacheDir: Option[File], log: Logger) =
this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, UpdateOptions(), log)
override def toString: String = s"InlineIvyConfiguration($paths, $resolvers, $otherResolvers, " +
s"$moduleConfigurations, $localOnly, $checksums, $resolutionCacheDir, $updateOptions)"
type This = InlineIvyConfiguration
def baseDirectory = paths.baseDirectory
def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums,
resolutionCacheDir, updateOptions, log)
def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums,
resolutionCacheDir, updateOptions, log)
override def equals(o: Any): Boolean = o match {
case o: InlineIvyConfiguration =>
this.paths == o.paths &&
this.resolvers == o.resolvers &&
this.otherResolvers == o.otherResolvers &&
this.moduleConfigurations == o.moduleConfigurations &&
this.localOnly == o.localOnly &&
this.checksums == o.checksums &&
this.resolutionCacheDir == o.resolutionCacheDir &&
this.updateOptions == o.updateOptions
case _ => false
}
override def hashCode: Int =
{
var hash = 1
hash = hash * 31 + this.paths.##
hash = hash * 31 + this.resolvers.##
hash = hash * 31 + this.otherResolvers.##
hash = hash * 31 + this.moduleConfigurations.##
hash = hash * 31 + this.localOnly.##
hash = hash * 31 + this.checksums.##
hash = hash * 31 + this.resolutionCacheDir.##
hash = hash * 31 + this.updateOptions.##
hash
}
}
final class ExternalIvyConfiguration(val baseDirectory: File, val uri: URI, val lock: Option[xsbti.GlobalLock],
val extraResolvers: Seq[Resolver], val updateOptions: UpdateOptions, val log: Logger) extends IvyConfiguration {
@ -108,18 +138,18 @@ object InlineConfiguration {
final class InlineConfigurationWithExcludes private[sbt] (val module: ModuleID,
val moduleInfo: ModuleInfo,
val dependencies: Seq[ModuleID],
val overrides: Set[ModuleID] = Set.empty,
val overrides: Set[ModuleID],
val excludes: Seq[SbtExclusionRule],
val ivyXML: NodeSeq = NodeSeq.Empty,
val configurations: Seq[Configuration] = Nil,
val defaultConfiguration: Option[Configuration] = None,
val ivyScala: Option[IvyScala] = None,
val validate: Boolean = false,
val conflictManager: ConflictManager = ConflictManager.default) extends ModuleSettings {
val ivyXML: NodeSeq,
val configurations: Seq[Configuration],
val defaultConfiguration: Option[Configuration],
val ivyScala: Option[IvyScala],
val validate: Boolean,
val conflictManager: ConflictManager) extends ModuleSettings {
def withConfigurations(configurations: Seq[Configuration]) = copy(configurations = configurations)
def noScala = copy(ivyScala = None)
def copy(module: ModuleID = this.module,
private[sbt] def copy(module: ModuleID = this.module,
moduleInfo: ModuleInfo = this.moduleInfo,
dependencies: Seq[ModuleID] = this.dependencies,
overrides: Set[ModuleID] = this.overrides,
@ -133,6 +163,41 @@ final class InlineConfigurationWithExcludes private[sbt] (val module: ModuleID,
InlineConfigurationWithExcludes(module, moduleInfo, dependencies, overrides, excludes, ivyXML,
configurations, defaultConfiguration, ivyScala, validate, conflictManager)
override def toString: String =
s"InlineConfigurationWithExcludes($module, $moduleInfo, $dependencies, $overrides, $excludes, " +
s"$ivyXML, $configurations, $defaultConfiguration, $ivyScala, $validate, $conflictManager)"
override def equals(o: Any): Boolean = o match {
case o: InlineConfigurationWithExcludes =>
this.module == o.module &&
this.moduleInfo == o.moduleInfo &&
this.dependencies == o.dependencies &&
this.overrides == o.overrides &&
this.excludes == o.excludes &&
this.ivyXML == o.ivyXML &&
this.configurations == o.configurations &&
this.defaultConfiguration == o.defaultConfiguration &&
this.ivyScala == o.ivyScala &&
this.validate == o.validate &&
this.conflictManager == o.conflictManager
case _ => false
}
override def hashCode: Int =
{
var hash = 1
hash = hash * 31 + this.module.##
hash = hash * 31 + this.dependencies.##
hash = hash * 31 + this.overrides.##
hash = hash * 31 + this.excludes.##
hash = hash * 31 + this.ivyXML.##
hash = hash * 31 + this.configurations.##
hash = hash * 31 + this.defaultConfiguration.##
hash = hash * 31 + this.ivyScala.##
hash = hash * 31 + this.validate.##
hash = hash * 31 + this.conflictManager.##
hash
}
}
object InlineConfigurationWithExcludes {
def apply(module: ModuleID,

View File

@ -15,6 +15,19 @@ sealed trait Resolver {
final class RawRepository(val resolver: DependencyResolver) extends Resolver {
def name = resolver.getName
override def toString = "Raw(" + resolver.toString + ")"
override def equals(o: Any): Boolean = o match {
case o: RawRepository =>
this.name == o.name
case _ => false
}
override def hashCode: Int =
{
var hash = 1
hash = hash * 31 + this.name.##
hash
}
}
sealed case class ChainedResolver(name: String, resolvers: Seq[Resolver]) extends Resolver
sealed case class MavenRepository(name: String, root: String) extends Resolver {

View File

@ -40,6 +40,23 @@ final class UpdateOptions private[sbt] (
latestSnapshots,
consolidatedResolution,
cachedResolution)
override def equals(o: Any): Boolean = o match {
case o: UpdateOptions =>
this.circularDependencyLevel == o.circularDependencyLevel &&
this.latestSnapshots == o.latestSnapshots &&
this.cachedResolution == o.cachedResolution
case _ => false
}
override def hashCode: Int =
{
var hash = 1
hash = hash * 31 + this.circularDependencyLevel.##
hash = hash * 31 + this.latestSnapshots.##
hash = hash * 31 + this.cachedResolution.##
hash
}
}
object UpdateOptions {

View File

@ -16,7 +16,32 @@ import org.apache.ivy.plugins.resolver.{ ChainResolver, BasicResolver, Dependenc
import org.apache.ivy.plugins.resolver.util.{ HasLatestStrategy, ResolvedResource }
import org.apache.ivy.util.{ Message, MessageLogger, StringUtils => IvyStringUtils }
class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], settings: IvySettings, updateOptions: UpdateOptions, log: Logger) extends ChainResolver {
private[sbt] case class SbtChainResolver(
name: String,
resolvers: Seq[DependencyResolver],
settings: IvySettings,
updateOptions: UpdateOptions,
log: Logger) extends ChainResolver {
override def equals(o: Any): Boolean = o match {
case o: SbtChainResolver =>
this.name == o.name &&
this.resolvers == o.resolvers &&
this.settings == o.settings &&
this.updateOptions == o.updateOptions
case _ => false
}
override def hashCode: Int =
{
var hash = 1
hash = hash * 31 + this.name.##
hash = hash * 31 + this.resolvers.##
hash = hash * 31 + this.settings.##
hash = hash * 31 + this.updateOptions.##
hash
}
// TODO - We need to special case the project resolver so it always "wins" when resolving with inter-project dependencies.
// Initialize ourselves.

View File

@ -112,7 +112,12 @@ object CacheIvy {
m => ((m.organization, m.name, m.revision, m.configurations), (m.isChanging, m.isTransitive, m.isForce, m.explicitArtifacts, m.exclusions, m.extraAttributes, m.crossVersion)),
{ case ((o, n, r, cs), (ch, t, f, as, excl, x, cv)) => ModuleID(o, n, r, cs, ch, t, f, as, excl, x, cv) }
)
implicit def moduleSetIC: InputCache[Set[ModuleID]] = basicInput(defaultEquiv, immutableSetFormat)
// For some reason sbinary seems to detect unserialized instance Set[ModuleID] to be not equal. #1620
implicit def moduleSetIC: InputCache[Set[ModuleID]] =
{
implicit def toSeq(ms: Set[ModuleID]): Seq[ModuleID] = ms.toSeq.sortBy { _.toString }
wrapIn
}
implicit def configurationFormat(implicit sf: Format[String]): Format[Configuration] =
wrap[Configuration, String](_.name, s => new Configuration(s))

View File

@ -0,0 +1,31 @@
lazy val check = taskKey[Unit]("Runs the check")
def commonSettings: Seq[Def.Setting[_]] =
Seq(
ivyPaths := new IvyPaths( (baseDirectory in ThisBuild).value, Some((baseDirectory in LocalRootProject).value / "ivy-cache")),
scalaVersion := "2.10.4",
resolvers += Resolver.sonatypeRepo("snapshots")
)
// #1620
lazy val root = (project in file(".")).
settings(
dependencyOverrides in ThisBuild += "com.github.nscala-time" %% "nscala-time" % "1.0.0",
libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "1.0.0",
check := {
import sbt.Cache._, sbt.CacheIvy.updateIC
implicit val updateCache = updateIC
type In = IvyConfiguration :+: ModuleSettings :+: UpdateConfiguration :+: HNil
val s = (streams in update).value
val cacheFile = s.cacheDirectory / updateCacheName.value
val module = ivyModule.value
val config = updateConfiguration.value
val f: In => Unit =
Tracked.inputChanged(cacheFile / "inputs") { (inChanged: Boolean, in: In) =>
if (inChanged) {
sys.error(s"Update cache is invalidated: ${module.owner.configuration}, ${module.moduleSettings}, $config")
}
}
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)
}
)

View File

@ -0,0 +1,2 @@
> compile
> check