From dba8bd28cf3350d69a5c0065488ccec2199d88a5 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Thu, 10 Oct 2013 21:36:11 -0400 Subject: [PATCH] Work around various issues with Maven local repositories. Fixes #321. * when mvn does a local 'install', it doesn't update the pom.xml last modified time if the pom.xml content hasn't changed * an ivy.xml includes publicationDate, so an ivy.xml will always be touched even if the other content hasn't changed * when Ivy checks if a snapshot is uptodate + it sees a SNAPSHOT, so it knows the module metadata and artifacts might change + it then checks the lastModified time of the metadata + if unchanged, it uses the cached information + if useOrigin is effectively false (either it is explicitly false or a resource is remote/isLocal=false), this means that a new artifact won't be retrieved * the Ivy IBiblioResolver + must be used for Maven repositories for proper behavior (no FileResolver, for example) + only returns URLResources, even for file: URLs + a FileResource is needed in combination with useOrigin to avoid copying artifacts from .m2/repository/ This commit fixes the above by setting a custom URLRepository on a constructed IBiblioResolver. This URLRepository returns FileResources for file: URLs and standard URLResources for others. The returned FileResource has isLocal=true and sbt sets useOrigin=true by default, so the artifacts are used from the origin. If it turns out a similar situation happens when mvn publishes to remote repositories, it is likely the fix for that would be to figure out how to disable the lastModified check on the metadata and always download the metadata. This would be slower, however. --- ivy/src/main/scala/sbt/ConvertResolver.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ivy/src/main/scala/sbt/ConvertResolver.scala b/ivy/src/main/scala/sbt/ConvertResolver.scala index 91fa137a2..58ba6d4ac 100644 --- a/ivy/src/main/scala/sbt/ConvertResolver.scala +++ b/ivy/src/main/scala/sbt/ConvertResolver.scala @@ -3,6 +3,7 @@ */ package sbt +import java.net.URL import java.util.Collections import org.apache.ivy.{core,plugins} import core.module.id.ModuleRevisionId @@ -11,6 +12,8 @@ import core.resolve.ResolveData import core.settings.IvySettings import plugins.resolver.{BasicResolver, DependencyResolver, IBiblioResolver} import plugins.resolver.{AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver} +import plugins.repository.url.{URLRepository => URLRepo} +import plugins.repository.file.{FileRepository => FileRepo, FileResource} private object ConvertResolver { @@ -29,6 +32,7 @@ private object ConvertResolver } } val resolver = new PluginCapableResolver + resolver.setRepository(new LocalIfFileRepo) initializeMavenStyle(resolver, repo.name, repo.root) resolver.setPatterns() // has to be done after initializeMavenStyle, which calls methods that overwrite the patterns resolver @@ -128,4 +132,16 @@ private object ConvertResolver patterns.ivyPatterns.foreach(p => resolver.addIvyPattern(settings substitute p)) patterns.artifactPatterns.foreach(p => resolver.addArtifactPattern(settings substitute p)) } + /** A custom Ivy URLRepository that returns FileResources for file URLs. + * This allows using the artifacts from the Maven local repository instead of copying them to the Ivy cache. */ + private[this] final class LocalIfFileRepo extends URLRepo { + private[this] val repo = new FileRepo + override def getResource(source: String) = { + val url = new URL(source) + if(url.getProtocol == IO.FileScheme) + new FileResource(repo, IO.toFile(url)) + else + super.getResource(source) + } + } }