From 92cc5339eb28d9e2f8bbe6b1b9e16fbbc5ab6c12 Mon Sep 17 00:00:00 2001 From: jvican Date: Thu, 11 May 2017 17:32:19 +0200 Subject: [PATCH] Fix sbt/sbt#2650: Degrade log level and clarify To ensure that SNAPSHOTs are always the latest, we go through all the resolved modules and check their timestamps. Good. However, if in the process of reparsing/redownloading the module descriptor we fail (or it's not found in that resolver at all), then we cannot refresh the resolved module that could have been internalized or heavily cached in memory by ivy. We do this for correctness. This patch does two things: 1. Adds more comments. 2. Warns only when there are parsing errors in ivy files. 3. Adds debug info in the rest of the cases. This removes the pain of seeing `Unable to parse` that could be caused by other reasons that are not related to parsing at all and which would not affect the algorithm at hand. For instance, if we get a URLResource, that's totally fine -- there is no way we could parse the ivy file. Ivy uses URLResources in several cases where the artifact origin URL is specified. --- .../ivyint/SbtChainResolver.scala | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala index f07930105..2f0789c45 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala @@ -306,34 +306,45 @@ private[sbt] case class SbtChainResolver( } } - // Ivy seem to not want to use the module descriptor found at the latest resolver + /* Ivy keeps module descriptors in memory, so we need to make sure that the + * resolved module revision is in fact the one found in the latest resolver. */ private[this] def reparseModuleDescriptor( dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver, - rmr: ResolvedModuleRevision - ): ResolvedModuleRevision = - // TODO - Redownloading/parsing the ivy file is not really the best way to make this correct. - // We should figure out a better alternative, or directly attack the resolvers Ivy uses to - // give them correct behavior around -SNAPSHOT. + previouslyResolved: ResolvedModuleRevision + ): ResolvedModuleRevision = { + // TODO: Figure out better alternative or directly attack the + // resolvers ivy uses to get correct behaviour for SNAPSHOT Option(resolver.findIvyFileRef(dd, data)) flatMap { ivyFile => ivyFile.getResource match { case r: FileResource => + val urlDescriptor = r.getFile.toURI.toURL try { - val parser = rmr.getDescriptor.getParser - val md = parser.parseDescriptor(settings, r.getFile.toURI.toURL, r, false) - Some(new ResolvedModuleRevision(resolver, resolver, md, rmr.getReport, true)) + val parser = previouslyResolved.getDescriptor.getParser + val md = parser.parseDescriptor(settings, urlDescriptor, r, false) + val report = previouslyResolved.getReport + // Note that we always set force for SNAPSHOT resolution... + Some(new ResolvedModuleRevision(resolver, resolver, md, report, true)) } catch { - case _: ParseException => None + case _: ParseException => + Message.warn(s"The descriptor in $urlDescriptor from $resolver could not be parsed.") + Some(previouslyResolved) } - case _ => None + case unhandledResource => + val unhandledClassName = unhandledResource.getClass.getName + val tip = s"Returning previously resolved $previouslyResolved." + Message.debug(s"Latest snapshots option does not handle `$unhandledClassName`. $tip") + Some(previouslyResolved) } } getOrElse { - Message.warn( - s"Unable to reparse ${dd.getDependencyRevisionId} from $resolver, using ${rmr.getPublicationDate}" - ) - rmr + val previousRevision = dd.getDependencyRevisionId + val date = previouslyResolved.getPublicationDate + // Change from warn to debug -- see https://github.com/sbt/sbt/issues/2650. + Message.debug(s"Unable to find new descriptor for $previousRevision at $date in $resolver.") + previouslyResolved } + } /** Ported from BasicResolver#findFirstAirfactRef. */ private[this] def findFirstArtifactRef(