From ea9a2931f69e87fdcf5a8bce02940a30ea4ab56c Mon Sep 17 00:00:00 2001 From: William Benton Date: Fri, 13 Dec 2013 11:39:09 -0600 Subject: [PATCH 1/2] 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 34147d9..7023ab8 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 6154bdb..e1dca53 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 ab69344..1243420 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 a39a70f..6c8c9f3 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 afddf87..13f99a0 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -167,7 +167,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)) -- 1.8.3.4 (Apple Git-47)