From 3a1ad44c45f1182a478b3db8cc16ee381da02fb0 Mon Sep 17 00:00:00 2001 From: William Benton Date: Fri, 13 Dec 2013 11:39:09 -0600 Subject: [PATCH] Support Ivy 2.3.0-final. This entailed modifying ResolutionCache and the CustomPomParser to reflect changes to the ResolutionCacheManager interface and DefaultExtendsDescriptor class between Ivy 2.3.0-rc1 and 2.3.0-rc2. Specifically, 1. ResolutionCacheManager now includes two additional methods that needed implementations in ResolutionCache: getResolvedModuleDescriptor(mrid: ModuleRevisionId) and saveResolvedModuleDescriptor(md: ModuleDescriptor). I adapted the implementations for these (which are expressed primarily in terms of other interface methods) from Ivy 2.3.0's DefaultResolutionCacheManager. 2. Instead of taking a ModuleRevisionIdentifier and a resolved ModuleRevisionIdentifier as its first two arguments, the DefaultExtendsDescriptor constructor now takes a ModuleDescriptor. This was a trivial change. Note that ResolutionCache.getResolvedModuleDescriptor does not appear to be used by Ivy as sbt uses Ivy and there is thus no test coverage for its implementation. Also note that the DefaultResolutionCacheManager object created in Update.configureResolutionCache now requires a reference to an IvySettings object; DRCM expects this to be non-null. --- ivy/src/main/scala/sbt/CustomPomParser.scala | 2 +- ivy/src/main/scala/sbt/Ivy.scala | 2 +- ivy/src/main/scala/sbt/ResolutionCache.scala | 27 +++++++++++++++++++- launch/src/main/scala/xsbt/boot/Update.scala | 4 ++- project/Util.scala | 2 +- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/ivy/src/main/scala/sbt/CustomPomParser.scala b/ivy/src/main/scala/sbt/CustomPomParser.scala index 34147d933..7023ab8d9 100644 --- a/ivy/src/main/scala/sbt/CustomPomParser.scala +++ b/ivy/src/main/scala/sbt/CustomPomParser.scala @@ -203,7 +203,7 @@ object CustomPomParser val unique = IvySbt.mergeDuplicateDefinitions(withExtra) unique foreach dmd.addDependency - for( ed <- md.getInheritedDescriptors) dmd.addInheritedDescriptor( new DefaultExtendsDescriptor( mrid, resolvedMrid, ed.getLocation, ed.getExtendsTypes) ) + for( ed <- md.getInheritedDescriptors) dmd.addInheritedDescriptor( new DefaultExtendsDescriptor( md, ed.getLocation, ed.getExtendsTypes) ) for( conf <- md.getConfigurations) { dmd.addConfiguration(conf) for(art <- md.getArtifacts(conf.getName)) { diff --git a/ivy/src/main/scala/sbt/Ivy.scala b/ivy/src/main/scala/sbt/Ivy.scala index 6154bdbe8..e1dca53ae 100644 --- a/ivy/src/main/scala/sbt/Ivy.scala +++ b/ivy/src/main/scala/sbt/Ivy.scala @@ -310,7 +310,7 @@ private object IvySbt private[this] def configureResolutionCache(settings: IvySettings, localOnly: Boolean, resCacheDir: Option[File]) { val base = resCacheDir getOrElse settings.getDefaultResolutionCacheBasedir - settings.setResolutionCacheManager(new ResolutionCache(base)) + settings.setResolutionCacheManager(new ResolutionCache(base, settings)) } // set the artifact resolver to be the main resolver. // this is because sometimes the artifact resolver saved in the cache is not correct diff --git a/ivy/src/main/scala/sbt/ResolutionCache.scala b/ivy/src/main/scala/sbt/ResolutionCache.scala index ab693445d..d79f25a4c 100644 --- a/ivy/src/main/scala/sbt/ResolutionCache.scala +++ b/ivy/src/main/scala/sbt/ResolutionCache.scala @@ -1,18 +1,24 @@ package sbt import java.io.File +import java.io.FileInputStream +import java.util.Properties import org.apache.ivy.core +import org.apache.ivy.plugins.parser import core.IvyPatternHelper +import core.settings.IvySettings import core.cache.{CacheMetadataOptions, DefaultRepositoryCacheManager, DefaultResolutionCacheManager, ResolutionCacheManager} import core.module.id.ModuleRevisionId +import core.module.descriptor.ModuleDescriptor import ResolutionCache.{Name, ReportDirectory, ResolvedName, ResolvedPattern} +import parser.xml.XmlModuleDescriptorParser /** Replaces the standard Ivy resolution cache in order to: * 1. Separate cached resolved Ivy files from resolution reports, making the resolution reports easier to find. * 2. Have them per-project for easier cleaning (possible with standard cache, but central to this custom one). * 3. Cache location includes extra attributes so that cross builds of a plugin do not overwrite each other. */ -private[sbt] final class ResolutionCache(base: File) extends ResolutionCacheManager +private[sbt] final class ResolutionCache(base: File, settings: IvySettings) extends ResolutionCacheManager { private[this] def resolvedFileInCache(m: ModuleRevisionId, name: String, ext: String): File = { val p = ResolvedPattern @@ -35,6 +41,25 @@ private[sbt] final class ResolutionCache(base: File) extends ResolutionCacheMana new File(reportBase, resolveId + "-" + conf + ".xml") def getConfigurationResolveReportsInCache(resolveId: String): Array[File] = IO.listFiles(reportBase).filter(_.getName.startsWith(resolveId + "-")) + + // XXX: this method is required by ResolutionCacheManager in Ivy 2.3.0 final, + // but it is apparently unused by Ivy as sbt uses Ivy. Therefore, it is + // unexercised in tests. Note that the implementation of this method in Ivy 2.3.0's + // DefaultResolutionCache also resolves parent properties for a given mrid + def getResolvedModuleDescriptor(mrid: ModuleRevisionId): ModuleDescriptor = { + val ivyFile = getResolvedIvyFileInCache(mrid) + if (!ivyFile.exists()) { + throw new IllegalStateException("Ivy file not found in cache for " + mrid + "!") + } + + return XmlModuleDescriptorParser.getInstance().parseDescriptor(settings, ivyFile.toURI().toURL(), false) + } + + def saveResolvedModuleDescriptor(md: ModuleDescriptor): Unit = { + val mrid = md.getResolvedModuleRevisionId + val cachedIvyFile = getResolvedIvyFileInCache(mrid) + md.toIvyFile(cachedIvyFile) + } } private[sbt] object ResolutionCache { diff --git a/launch/src/main/scala/xsbt/boot/Update.scala b/launch/src/main/scala/xsbt/boot/Update.scala index a39a70fa9..92e1bec92 100644 --- a/launch/src/main/scala/xsbt/boot/Update.scala +++ b/launch/src/main/scala/xsbt/boot/Update.scala @@ -286,7 +286,9 @@ final class Update(config: UpdateConfiguration) private[this] def configureResolutionCache(settings: IvySettings) { resolutionCacheBase.mkdirs() - settings.setResolutionCacheManager(new DefaultResolutionCacheManager(resolutionCacheBase)) + val drcm = new DefaultResolutionCacheManager(resolutionCacheBase) + drcm.setSettings(settings) + settings.setResolutionCacheManager(drcm) } private[this] def configureRepositoryCache(settings: IvySettings) { diff --git a/project/Util.scala b/project/Util.scala index 9b7595a3c..a5b0cbb4f 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -168,7 +168,7 @@ object Common def lib(m: ModuleID) = libraryDependencies += m lazy val jlineDep = "jline" % "jline" % "2.11" lazy val jline = lib(jlineDep) - lazy val ivy = lib("org.apache.ivy" % "ivy" % "2.3.0-rc1") + lazy val ivy = lib("org.apache.ivy" % "ivy" % "2.3.0") lazy val httpclient = lib("commons-httpclient" % "commons-httpclient" % "3.1") lazy val jsch = lib("com.jcraft" % "jsch" % "0.1.46" intransitive() ) lazy val sbinary = libraryDependencies <+= Util.nightly211(n => "org.scala-tools.sbinary" % "sbinary" % "0.4.2" cross(if(n) CrossVersion.full else CrossVersion.binary))