Merge remote-tracking branch 'remotesbt/0.13' into 0.13

This commit is contained in:
Matej Urbas 2014-04-18 13:48:19 +01:00
commit ff549766a8
3 changed files with 82 additions and 40 deletions

View File

@ -10,13 +10,91 @@ import core.module.id.ModuleRevisionId
import core.module.descriptor.DependencyDescriptor
import core.resolve.ResolveData
import core.settings.IvySettings
import plugins.resolver.{BasicResolver, DependencyResolver, IBiblioResolver}
import plugins.resolver.{BasicResolver, DependencyResolver, IBiblioResolver, RepositoryResolver}
import plugins.resolver.{AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver}
import plugins.repository.url.{URLRepository => URLRepo}
import plugins.repository.file.{FileRepository => FileRepo, FileResource}
import java.io.File
import org.apache.ivy.util.ChecksumHelper
import org.apache.ivy.core.module.descriptor.{Artifact=>IArtifact}
private object ConvertResolver
{
/** This class contains all the reflective lookups used in the
* checksum-friendly URL publishing shim.
*/
private object ChecksumFriendlyURLResolver {
// TODO - When we dump JDK6 support we can remove this hackery
// import java.lang.reflect.AccessibleObject
type AccessibleObject = {
def setAccessible(value: Boolean): Unit
}
private def reflectiveLookup[A <: AccessibleObject](f: Class[_] => A): Option[A] =
try {
val cls = classOf[RepositoryResolver]
val thing = f(cls)
import scala.language.reflectiveCalls
thing.setAccessible(true)
Some(thing)
} catch {
case (_: java.lang.NoSuchFieldException) |
(_: java.lang.SecurityException) |
(_: java.lang.NoSuchMethodException) => None
}
private val signerNameField: Option[java.lang.reflect.Field] =
reflectiveLookup(_.getDeclaredField("signerName"))
private val putChecksumMethod: Option[java.lang.reflect.Method] =
reflectiveLookup(_.getDeclaredMethod("putChecksum",
classOf[IArtifact], classOf[File], classOf[String],
classOf[Boolean], classOf[String]))
private val putSignatureMethod: Option[java.lang.reflect.Method] =
reflectiveLookup(_.getDeclaredMethod("putSignature",
classOf[IArtifact], classOf[File], classOf[String],
classOf[Boolean]))
}
/**
* The default behavior of ivy's overwrite flags ignores the fact that a lot of repositories
* will autogenerate checksums *for* an artifact if it doesn't already exist. Therefore
* if we succeed in publishing an artifact, we need to just blast the checksums in place.
* This acts as a "shim" on RepositoryResolvers so that we can hook our methods into
* both the IBiblioResolver + URLResolver without having to duplicate the code in two
* places. However, this does mean our use of reflection is awesome.
*
* TODO - See about contributing back to ivy.
*/
private trait ChecksumFriendlyURLResolver extends RepositoryResolver {
import ChecksumFriendlyURLResolver._
private def signerName: String = signerNameField match {
case Some(field) => field.get(this).asInstanceOf[String]
case None => null
}
override protected def put(artifact: IArtifact, src: File, dest: String, overwrite: Boolean): Unit = {
// verify the checksum algorithms before uploading artifacts!
val checksums = getChecksumAlgorithms()
val repository = getRepository()
for {
checksum <- checksums
if !ChecksumHelper.isKnownAlgorithm(checksum)
} throw new IllegalArgumentException("Unknown checksum algorithm: " + checksum)
repository.put(artifact, src, dest, overwrite);
// Fix for sbt#1156 - Artifactory will auto-generate MD5/sha1 files, so
// we need to overwrite what it has.
for (checksum <- checksums) {
putChecksumMethod match {
case Some(method) => method.invoke(this, artifact, src, dest, true: java.lang.Boolean, checksum)
case None => // TODO - issue warning?
}
}
if (signerName != null) {
putSignatureMethod match {
case None => ()
case Some(method) => method.invoke(artifact, src, dest, true: java.lang.Boolean)
}
}
}
}
/** Converts the given sbt resolver into an Ivy resolver..*/
def apply(r: Resolver, settings: IvySettings, log: Logger) =
{
@ -25,7 +103,7 @@ private object ConvertResolver
case repo: MavenRepository =>
{
val pattern = Collections.singletonList(Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern))
final class PluginCapableResolver extends IBiblioResolver with DescriptorRequired {
final class PluginCapableResolver extends IBiblioResolver with ChecksumFriendlyURLResolver with DescriptorRequired {
def setPatterns() { // done this way for access to protected methods.
setArtifactPatterns(pattern)
setIvyPatterns(pattern)
@ -77,7 +155,7 @@ private object ConvertResolver
}
case repo: URLRepository =>
{
val resolver = new URLResolver with DescriptorRequired
val resolver = new URLResolver with ChecksumFriendlyURLResolver with DescriptorRequired
resolver.setName(repo.name)
initializePatterns(resolver, repo.patterns, settings)
resolver

View File

@ -7,7 +7,6 @@ import Resolver.PluginPattern
import java.io.File
import java.net.URI
import java.text.ParseException
import java.util.concurrent.Callable
import java.util.{Collection, Collections => CS}
import CS.singleton
@ -24,9 +23,7 @@ import core.settings.IvySettings
import plugins.latest.LatestRevisionStrategy
import plugins.matcher.PatternMatcher
import plugins.parser.m2.PomModuleDescriptorParser
import plugins.repository.ResourceDownloader
import plugins.resolver.{ChainResolver, DependencyResolver}
import plugins.resolver.util.ResolvedResource
import util.{Message, MessageLogger}
import util.extendable.ExtendableItem
@ -358,41 +355,8 @@ private object IvySbt
case pr: ProjectResolver => true
case _ => false
}
/** This is overridden to delete outofdate artifacts of changing modules that are not listed in the metadata.
* This occurs for artifacts with classifiers, for example. */
@throws(classOf[ParseException])
override def cacheModuleDescriptor(resolver: DependencyResolver, mdRef: ResolvedResource, dd: DependencyDescriptor, moduleArtifact: IArtifact, downloader: ResourceDownloader, options: CacheMetadataOptions): ResolvedModuleRevision =
{
val rmrRaw = super.cacheModuleDescriptor(null, mdRef, dd, moduleArtifact, downloader, options)
val rmr = resetArtifactResolver(rmrRaw)
val mrid = moduleArtifact.getModuleRevisionId
def shouldClear(): Boolean = rmr != null &&
( (rmr.getReport != null && rmr.getReport.isSearched && isChanging(dd, mrid)) ||
isProjectResolver(rmr.getResolver) )
// only handle changing modules whose metadata actually changed.
// Typically, the publication date in the metadata has to change to get here.
if(shouldClear()) {
// this is the locally cached metadata as originally retrieved (e.g. the pom)
val original = rmr.getReport.getOriginalLocalFile
if(original != null) {
// delete all files in subdirectories that are older than the original metadata file's publication date
// The publication date is used because the metadata will be redownloaded for changing files,
// so the last modified time changes, but the publication date doesn't
val pubDate = rmrRaw.getPublicationDate
val lm = if(pubDate eq null) original.lastModified else pubDate.getTime
val indirectFiles = PathFinder(original.getParentFile).*(DirectoryFilter).**(-DirectoryFilter).get.toList
val older = indirectFiles.filter(f => f.lastModified < lm).toList
Message.verbose("Deleting additional old artifacts from cache for changed module " + mrid + older.mkString(":\n\t", "\n\t", ""))
IO.delete(older)
}
}
rmr
}
// ignore the original resolver wherever possible to avoid issues like #704
override def saveResolvers(descriptor: ModuleDescriptor, metadataResolverName: String, artifactResolverName: String) {}
def isChanging(dd: DependencyDescriptor, requestedRevisionId: ModuleRevisionId): Boolean =
!localOnly && (dd.isChanging || requestedRevisionId.getRevision.contains("-SNAPSHOT"))
}
manager.setArtifactPattern(PluginPattern + manager.getArtifactPattern)
manager.setDataFilePattern(PluginPattern + manager.getDataFilePattern)

View File

@ -31,7 +31,7 @@ private final class IvyLoggerInterface(logger: Logger) extends MessageLogger
def warn(msg: String) = logger.warn(msg)
def error(msg: String) = if(SbtIvyLogger.acceptError(msg)) logger.error(msg)
private def emptyList = java.util.Collections.emptyList[T forSome { type T}]
private def emptyList = java.util.Collections.emptyList[String]
def getProblems = emptyList
def getWarns = emptyList
def getErrors = emptyList