Revert chain resolver by default, for older behavior.

The issue comes into play where we cannot accurately get a publication date from Maven artifacts, leading to the current
mechanism having undefined behavior and causing other bugs to pop up in resolution.
This commit is contained in:
Josh Suereth 2014-10-20 12:26:40 -04:00
parent 01f098cd28
commit 1a38b6902e
2 changed files with 45 additions and 29 deletions

View File

@ -46,7 +46,7 @@ object UpdateOptions {
def apply(): UpdateOptions = def apply(): UpdateOptions =
new UpdateOptions( new UpdateOptions(
circularDependencyLevel = CircularDependencyLevel.Warn, circularDependencyLevel = CircularDependencyLevel.Warn,
latestSnapshots = true, latestSnapshots = false,
consolidatedResolution = false, consolidatedResolution = false,
cachedResolution = false) cachedResolution = false)
} }

View File

@ -57,12 +57,20 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
// and if a previously resolved or cached revision has been found. // and if a previously resolved or cached revision has been found.
def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision = def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision =
{ {
// useLatest - Means we should always download the JARs from the internet, no matter what.
// This will only be true *IF* the depenendency is dynamic/changing *and* latestSnapshots is true.
// If you find multiple candidates,
// - If `isReturnFirst` is true, you return the first value found
// - If not, we will ATTEMPT to look at the publish date, which is not correctly discovered for Maven modules and
// leads to undefined behavior.
val useLatest = (dd.isChanging || (IvySbt.isChanging(dd.getDependencyRevisionId))) && updateOptions.latestSnapshots val useLatest = (dd.isChanging || (IvySbt.isChanging(dd.getDependencyRevisionId))) && updateOptions.latestSnapshots
if (useLatest) { if (useLatest) {
Message.verbose(s"${getName} is changing. Checking all resolvers on the chain") Message.verbose(s"${getName} is changing. Checking all resolvers on the chain")
} }
val data = new ResolveData(data0, doValidate(data0)) val data = new ResolveData(data0, doValidate(data0))
// Returns the value if we've already been resolved from some other branch of the resolution tree.
val resolved = Option(data.getCurrentResolvedModuleRevision) val resolved = Option(data.getCurrentResolvedModuleRevision)
// If we don't have any previously resolved date, we try to pull the value from the cache.
val resolvedOrCached = val resolvedOrCached =
resolved orElse { resolved orElse {
Message.verbose(getName + ": Checking cache for: " + dd) Message.verbose(getName + ": Checking cache for: " + dd)
@ -71,31 +79,58 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
forcedRevision(mr) forcedRevision(mr)
} }
} }
// Default value for resolution. We use this while we loop...
// If useLatest is true, we want to try to download from the internet so we DO NOT start with a valid value.
var temp: Option[ResolvedModuleRevision] = var temp: Option[ResolvedModuleRevision] =
if (useLatest) None if (useLatest) None
else resolvedOrCached else resolvedOrCached
// Cast resolvers to something useful. TODO - we dropping anything here?
val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x } val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x }
// Here we do an attempt to resolve the artifact from each of the resolvers in the chain.
// - If we have a return value already, AND isReturnFirst is true AND useLatest is false, we DO NOT resolve anything
// - If we do not, try to resolve.
// RETURNS: Left -> Error
// Right -> Some(resolved module) // Found in this resolver, can use this result.
// Right -> None // Do not use this resolver
val results = resolvers map { x => val results = resolvers map { x =>
// if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers // if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers, just return None for this guy.
if (isReturnFirst && temp.isDefined && !useLatest) Right(None) if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
else { else {
// We actually do resolution.
val resolver = x val resolver = x
val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy)) val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy))
try { try {
val previouslyResolved = temp val previouslyResolved = temp
// if the module qualifies as changing, then resolve all resolvers // if the module qualifies as changing, then resolve all resolvers
if (useLatest) data.setCurrentResolvedModuleRevision(None.orNull) if (useLatest) data.setCurrentResolvedModuleRevision(null)
else data.setCurrentResolvedModuleRevision(temp.orNull) else data.setCurrentResolvedModuleRevision(temp.orNull)
temp = Option(resolver.getDependency(dd, data)) temp = Option(resolver.getDependency(dd, data))
val retval = Right( Right(
if (temp eq previouslyResolved) None if (temp eq previouslyResolved) None
else if (useLatest) temp map { x => else if (useLatest) temp map { x =>
(reparseModuleDescriptor(dd, data, resolver, x), resolver) (reparseModuleDescriptor(dd, data, resolver, x), resolver)
} }
else temp map { x => (forcedRevision(x), resolver) } else temp map { x => (forcedRevision(x), resolver) }
) )
retval match { } catch {
case Right(Some((rmr, _))) => case ex: Exception =>
Message.verbose("problem occurred while resolving " + dd + " with " + resolver
+ ": " + IvyStringUtils.getStackTrace(ex))
Left(ex)
} finally {
oldLatest map { _ => doSetLatestStrategy(resolver, oldLatest) }
checkInterrupted
}
}
}
val errors = results collect { case Left(e) => e }
val foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
val sorted =
if (useLatest) (foundRevisions.sortBy {
case (rmr, resolver) =>
// Just issue warning about issues with publication date, and fake one on it for now.
rmr.getDescriptor.getPublicationDate match { rmr.getDescriptor.getPublicationDate match {
case null => case null =>
(resolver.findIvyFileRef(dd, data), rmr.getDescriptor) match { (resolver.findIvyFileRef(dd, data), rmr.getDescriptor) match {
@ -112,25 +147,6 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
} }
case _ => // All other cases ok case _ => // All other cases ok
} }
case _ =>
}
retval
} catch {
case ex: Exception =>
Message.verbose("problem occurred while resolving " + dd + " with " + resolver
+ ": " + IvyStringUtils.getStackTrace(ex))
Left(ex)
} finally {
oldLatest map { _ => doSetLatestStrategy(resolver, oldLatest) }
checkInterrupted
}
}
}
val errors = results collect { case Left(e) => e }
val foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
val sorted =
if (useLatest) (foundRevisions.sortBy {
case (rmr, _) =>
rmr.getDescriptor.getPublicationDate match { rmr.getDescriptor.getPublicationDate match {
case null => 0L case null => 0L
case d => d.getTime case d => d.getTime
@ -141,8 +157,7 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver) val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
artifactOpt match { artifactOpt match {
case None if resolver.getName == "inter-project" => // do nothing case None if resolver.getName == "inter-project" => // do nothing
case None => throw new RuntimeException("\t" + resolver.getName case None => throw new RuntimeException(s"\t${resolver.getName}: no ivy file nor artifact found for $rmr")
+ ": no ivy file nor artifact found for " + rmr)
case Some(artifactRef) => case Some(artifactRef) =>
val systemMd = toSystem(rmr.getDescriptor) val systemMd = toSystem(rmr.getDescriptor)
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef, getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
@ -150,7 +165,8 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
} }
rmr rmr
} }
else foundRevisions.reverse.headOption map { _._1 } else foundRevisions.reverse.headOption map { _._1 } // we have to reverse because resolvers are hit in reverse order.
// If the value is arleady in cache, SORTED will be a Seq(None, None, ...) which means we'll fall over to the prevously cached or resolved version.
val mrOpt: Option[ResolvedModuleRevision] = sorted orElse resolvedOrCached val mrOpt: Option[ResolvedModuleRevision] = sorted orElse resolvedOrCached
mrOpt match { mrOpt match {
case None if errors.size == 1 => case None if errors.size == 1 =>