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 =
new UpdateOptions(
circularDependencyLevel = CircularDependencyLevel.Warn,
latestSnapshots = true,
latestSnapshots = false,
consolidatedResolution = 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.
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
if (useLatest) {
Message.verbose(s"${getName} is changing. Checking all resolvers on the chain")
}
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)
// If we don't have any previously resolved date, we try to pull the value from the cache.
val resolvedOrCached =
resolved orElse {
Message.verbose(getName + ": Checking cache for: " + dd)
@ -71,50 +79,41 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
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] =
if (useLatest) None
else resolvedOrCached
// Cast resolvers to something useful. TODO - we dropping anything here?
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 =>
// 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)
else {
// We actually do resolution.
val resolver = x
val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy))
try {
val previouslyResolved = temp
// 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)
temp = Option(resolver.getDependency(dd, data))
val retval = Right(
Right(
if (temp eq previouslyResolved) None
else if (useLatest) temp map { x =>
(reparseModuleDescriptor(dd, data, resolver, x), resolver)
}
else temp map { x => (forcedRevision(x), resolver) }
)
retval match {
case Right(Some((rmr, _))) =>
rmr.getDescriptor.getPublicationDate match {
case null =>
(resolver.findIvyFileRef(dd, data), rmr.getDescriptor) match {
case (null, _) =>
// In this instance, the dependency is specified by a direct URL or some other sort of "non-ivy" file
if (dd.isChanging)
Message.warn(s"Resolving a changing dependency (${rmr.getId}) with no ivy/pom file!, resolution order is undefined!")
case (ivf, dmd: DefaultModuleDescriptor) =>
val lmd = new java.util.Date(ivf.getLastModified)
Message.debug(s"Getting no publication date from resolver: ${resolver} for ${rmr.getId}, setting to: ${lmd}")
dmd.setPublicationDate(lmd)
case _ =>
Message.warn(s"Getting null publication date from resolver: ${resolver} for ${rmr.getId}, resolution order is undefined!")
}
case _ => // All other cases ok
}
case _ =>
}
retval
} catch {
case ex: Exception =>
Message.verbose("problem occurred while resolving " + dd + " with " + resolver
@ -130,7 +129,24 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
val foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
val sorted =
if (useLatest) (foundRevisions.sortBy {
case (rmr, _) =>
case (rmr, resolver) =>
// Just issue warning about issues with publication date, and fake one on it for now.
rmr.getDescriptor.getPublicationDate match {
case null =>
(resolver.findIvyFileRef(dd, data), rmr.getDescriptor) match {
case (null, _) =>
// In this instance, the dependency is specified by a direct URL or some other sort of "non-ivy" file
if (dd.isChanging)
Message.warn(s"Resolving a changing dependency (${rmr.getId}) with no ivy/pom file!, resolution order is undefined!")
case (ivf, dmd: DefaultModuleDescriptor) =>
val lmd = new java.util.Date(ivf.getLastModified)
Message.debug(s"Getting no publication date from resolver: ${resolver} for ${rmr.getId}, setting to: ${lmd}")
dmd.setPublicationDate(lmd)
case _ =>
Message.warn(s"Getting null publication date from resolver: ${resolver} for ${rmr.getId}, resolution order is undefined!")
}
case _ => // All other cases ok
}
rmr.getDescriptor.getPublicationDate match {
case null => 0L
case d => d.getTime
@ -141,8 +157,7 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
artifactOpt match {
case None if resolver.getName == "inter-project" => // do nothing
case None => throw new RuntimeException("\t" + resolver.getName
+ ": no ivy file nor artifact found for " + rmr)
case None => throw new RuntimeException(s"\t${resolver.getName}: no ivy file nor artifact found for $rmr")
case Some(artifactRef) =>
val systemMd = toSystem(rmr.getDescriptor)
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
@ -150,7 +165,8 @@ class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], setting
}
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
mrOpt match {
case None if errors.size == 1 =>