Turn Aether integration into sbt-maven-resolver

This commit is contained in:
Eugene Yokota 2015-01-08 18:02:59 -05:00
parent 16a64d70ef
commit f36a5b88d8
16 changed files with 101 additions and 49 deletions

View File

@ -215,7 +215,7 @@ lazy val ivyProj = (project in file("ivy")).
settings(baseSettings: _*).
settings(
name := "Ivy",
libraryDependencies ++= Seq(ivy, jsch, json4sNative, jawnParser, jawnJson4s) ++ aetherLibs,
libraryDependencies ++= Seq(ivy, jsch, json4sNative, jawnParser, jawnJson4s),
testExclusive)
// Runner for uniform test interface
@ -412,6 +412,15 @@ lazy val sbtProj = (project in sbtPath).
normalizedName := "sbt"
)
lazy val mavenResolverPluginProj = (project in file("sbt-maven-resolver")).
dependsOn(sbtProj).
settings(baseSettings: _*).
settings(
name := "sbt-maven-resolver",
libraryDependencies ++= aetherLibs,
sbtPlugin := true
)
def scriptedTask: Initialize[InputTask[Unit]] = InputTask(scriptedSource(dir => (s: State) => scriptedParser(dir))) { result =>
(proguard in Proguard, fullClasspath in scriptedSbtProj in Test, scalaInstance in scriptedSbtProj, publishAll, scriptedSource, result) map {
(launcher, scriptedSbtClasspath, scriptedSbtInstance, _, sourcePath, args) =>
@ -435,7 +444,7 @@ def allProjects = Seq(launchInterfaceProj, launchProj, testSamples, interfacePro
compileInterfaceProj, compileIncrementalProj, compilePersistProj, compilerProj,
compilerIntegrationProj, compilerIvyProj,
scriptedBaseProj, scriptedSbtProj, scriptedPluginProj,
actionsProj, commandProj, mainSettingsProj, mainProj, sbtProj)
actionsProj, commandProj, mainSettingsProj, mainProj, sbtProj, mavenResolverPluginProj)
def projectsWithMyProvided = allProjects.map(p => p.copy(configurations = (p.configurations.filter(_ != Provided)) :+ myProvided))
lazy val nonRoots = projectsWithMyProvided.map(p => LocalProject(p.id))

View File

@ -19,6 +19,8 @@ import org.apache.ivy.util.{ FileUtil, ChecksumHelper }
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact }
private[sbt] object ConvertResolver {
import UpdateOptions.ResolverConverter
/**
* This class contains all the reflective lookups used in the
* checksum-friendly URL publishing shim.
@ -94,37 +96,34 @@ private[sbt] object ConvertResolver {
}
}
private[sbt] val USE_AETHER_PROPERTY = "sbt.use.aether"
private def isUseAetherForResolution(settings: IvySettings): Boolean =
settings.getVariable(USE_AETHER_PROPERTY) == "true"
/** Converts the given sbt resolver into an Ivy resolver. */
@deprecated("0.13.8", "Use the variant with updateOptions")
def apply(r: Resolver, settings: IvySettings, log: Logger): DependencyResolver =
apply(r, settings, UpdateOptions(), log)
/** Converts the given sbt resolver into an Ivy resolver..*/
def apply(r: Resolver, settings: IvySettings, log: Logger) =
{
/** Converts the given sbt resolver into an Ivy resolver. */
def apply(r: Resolver, settings: IvySettings, updateOptions: UpdateOptions, log: Logger): DependencyResolver =
(updateOptions.resolverConverter orElse defaultConvert)((r, settings, log))
/** The default implementation of converter. */
lazy val defaultConvert: ResolverConverter = {
case (r, settings, log) =>
r match {
case repo: MavenRepository =>
{
if (isUseAetherForResolution(settings)) {
repo match {
case cache: MavenCache => new org.apache.ivy.plugins.resolver.MavenCacheRepositoryResolver(cache, settings)
case _ => new org.apache.ivy.plugins.resolver.MavenRemoteRepositoryResolver(repo, settings)
val pattern = Collections.singletonList(Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern))
final class PluginCapableResolver extends IBiblioResolver with ChecksumFriendlyURLResolver with DescriptorRequired {
def setPatterns() {
// done this way for access to protected methods.
setArtifactPatterns(pattern)
setIvyPatterns(pattern)
}
} else {
val pattern = Collections.singletonList(Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern))
final class PluginCapableResolver extends IBiblioResolver with ChecksumFriendlyURLResolver with DescriptorRequired {
def setPatterns() {
// done this way for access to protected methods.
setArtifactPatterns(pattern)
setIvyPatterns(pattern)
}
}
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
}
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
}
// TODO: HTTP repository is no longer recommended. #1541
// Remove `JavaNet1Repository` when we bump up the API.
@ -176,7 +175,7 @@ private[sbt] object ConvertResolver {
case repo: ChainedResolver => IvySbt.resolverChain(repo.name, repo.resolvers, false, settings, log)
case repo: RawRepository => repo.resolver
}
}
}
private sealed trait DescriptorRequired extends BasicResolver {
override def getDependency(dd: DependencyDescriptor, data: ResolveData) =

View File

@ -73,7 +73,6 @@ final class IvySbt(val configuration: IvyConfiguration) {
is.setBaseDir(baseDirectory)
is.setCircularDependencyStrategy(configuration.updateOptions.circularDependencyLevel.ivyStrategy)
CustomPomParser.registerDefault
is.setVariable(ConvertResolver.USE_AETHER_PROPERTY, s"${configuration.updateOptions.aetherResolution}")
configuration match {
case e: ExternalIvyConfiguration =>
@ -289,7 +288,7 @@ private[sbt] object IvySbt {
def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, log: Logger): DependencyResolver =
resolverChain(name, resolvers, localOnly, settings, UpdateOptions(), log)
def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, updateOptions: UpdateOptions, log: Logger): DependencyResolver = {
def mapResolvers(rs: Seq[Resolver]) = rs.map(r => ConvertResolver(r, settings, log))
def mapResolvers(rs: Seq[Resolver]) = rs.map(r => ConvertResolver(r, settings, updateOptions, log))
val (projectResolvers, rest) = resolvers.partition(_.name == "inter-project")
if (projectResolvers.isEmpty) new ivyint.SbtChainResolver(name, mapResolvers(rest), settings, updateOptions, log)
else {

View File

@ -20,6 +20,7 @@ import org.apache.ivy.Ivy
import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.core.module.descriptor.{ DependencyArtifactDescriptor, DependencyDescriptor, License, ModuleDescriptor, ExcludeRule }
import org.apache.ivy.plugins.resolver.{ ChainResolver, DependencyResolver, IBiblioResolver }
import ivyint.CustomRemoteMavenResolver
class MakePom(val log: Logger) {
@deprecated("Use `write(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, XNode => XNode, MavenRepository => Boolean, Boolean, File)` instead", "0.11.2")
@ -333,7 +334,7 @@ class MakePom(val log: Logger) {
val repositories = if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
val mavenRepositories =
repositories.flatMap {
case m: org.apache.ivy.plugins.resolver.MavenRemoteRepositoryResolver if m.repo.root != DefaultMavenRepository.root =>
case m: CustomRemoteMavenResolver if m.repo.root != DefaultMavenRepository.root =>
MavenRepository(m.repo.name, m.repo.root) :: Nil
case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.root =>
MavenRepository(m.getName, m.getRoot) :: Nil

View File

@ -1,6 +1,8 @@
package sbt
import java.io.File
import org.apache.ivy.plugins.resolver.DependencyResolver
import org.apache.ivy.core.settings.IvySettings
/**
* Represents configurable options for update task.
@ -18,13 +20,8 @@ final class UpdateOptions private[sbt] (
val consolidatedResolution: Boolean,
/** If set to true, use cached resolution. */
val cachedResolution: Boolean,
/** If set to true, use aether for resolving maven artifacts. */
val aetherResolution: Boolean) {
/** Enables Aether for dependency resolution. */
def withAetherResolution(aetherResolution: Boolean): UpdateOptions =
copy(aetherResolution = aetherResolution)
/** Extention point for an alternative resolver converter. */
val resolverConverter: UpdateOptions.ResolverConverter) {
def withCircularDependencyLevel(circularDependencyLevel: CircularDependencyLevel): UpdateOptions =
copy(circularDependencyLevel = circularDependencyLevel)
def withLatestSnapshots(latestSnapshots: Boolean): UpdateOptions =
@ -36,24 +33,28 @@ final class UpdateOptions private[sbt] (
def withCachedResolution(cachedResoluton: Boolean): UpdateOptions =
copy(cachedResolution = cachedResoluton,
consolidatedResolution = cachedResolution)
/** Extention point for an alternative resolver converter. */
def withResolverConverter(resolverConverter: UpdateOptions.ResolverConverter): UpdateOptions =
copy(resolverConverter = resolverConverter)
private[sbt] def copy(
circularDependencyLevel: CircularDependencyLevel = this.circularDependencyLevel,
latestSnapshots: Boolean = this.latestSnapshots,
consolidatedResolution: Boolean = this.consolidatedResolution,
cachedResolution: Boolean = this.cachedResolution,
aetherResolution: Boolean = this.aetherResolution): UpdateOptions =
resolverConverter: UpdateOptions.ResolverConverter = this.resolverConverter): UpdateOptions =
new UpdateOptions(circularDependencyLevel,
latestSnapshots,
consolidatedResolution,
cachedResolution,
aetherResolution)
resolverConverter)
override def equals(o: Any): Boolean = o match {
case o: UpdateOptions =>
this.circularDependencyLevel == o.circularDependencyLevel &&
this.latestSnapshots == o.latestSnapshots &&
this.cachedResolution == o.cachedResolution
this.cachedResolution == o.cachedResolution &&
this.resolverConverter == o.resolverConverter
case _ => false
}
@ -63,17 +64,19 @@ final class UpdateOptions private[sbt] (
hash = hash * 31 + this.circularDependencyLevel.##
hash = hash * 31 + this.latestSnapshots.##
hash = hash * 31 + this.cachedResolution.##
hash = hash * 31 + this.resolverConverter.##
hash
}
}
object UpdateOptions {
type ResolverConverter = PartialFunction[(Resolver, IvySettings, Logger), DependencyResolver]
def apply(): UpdateOptions =
new UpdateOptions(
circularDependencyLevel = CircularDependencyLevel.Warn,
latestSnapshots = false,
consolidatedResolution = false,
cachedResolution = false,
// TODO - Disable this before release, but make sure test suite passes with it on.
aetherResolution = true)
resolverConverter = PartialFunction.empty)
}

View File

@ -0,0 +1,11 @@
package sbt
package ivyint
import org.apache.ivy.plugins.resolver.DependencyResolver
// These are placeholder traits for sbt-aether-resolver
trait CustomMavenResolver extends DependencyResolver {
}
trait CustomRemoteMavenResolver extends CustomMavenResolver {
def repo: MavenRepository
}

View File

@ -184,7 +184,7 @@ private[sbt] case class SbtChainResolver(
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
artifactOpt match {
case None if resolver.getName == "inter-project" => // do nothing
case None if resolver.isInstanceOf[AbstractMavenRepositoryResolver] =>
case None if resolver.isInstanceOf[CustomMavenResolver] =>
// do nothing for now....
// We want to see if the maven caching is sufficient and we do not need to duplicate within the ivy cache...
case None => throw new RuntimeException(s"\t${resolver.getName}: no ivy file nor artifact found for $rmr")

View File

@ -30,6 +30,7 @@ import org.eclipse.aether.deployment.{ DeployRequest => AetherDeployRequest }
import org.eclipse.aether.installation.{ InstallRequest => AetherInstallRequest }
import org.apache.ivy.core.cache.{ ModuleDescriptorWriter, ArtifactOrigin }
import sbt.{ MavenCache, MavenRepository }
import sbt.ivyint.{ CustomMavenResolver, CustomRemoteMavenResolver }
import scala.collection.JavaConverters._
object MavenRepositoryResolver {
@ -60,7 +61,8 @@ object MavenRepositoryResolver {
* Note: This creates its *own* local cache directory for cache metadata. using its name.
*
*/
class MavenRemoteRepositoryResolver(val repo: MavenRepository, settings: IvySettings) extends AbstractMavenRepositoryResolver(settings) {
class MavenRemoteRepositoryResolver(val repo: MavenRepository, settings: IvySettings)
extends AbstractMavenRepositoryResolver(settings) with CustomRemoteMavenResolver {
setName(repo.name)
override def toString = s"${repo.name}: ${repo.root}"
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl
@ -136,7 +138,8 @@ class MavenRemoteRepositoryResolver(val repo: MavenRepository, settings: IvySett
*
* Note: This should never hit somethign remote, as it just looks in the maven cache for things already resolved.
*/
class MavenCacheRepositoryResolver(val repo: MavenCache, settings: IvySettings) extends AbstractMavenRepositoryResolver(settings) {
class MavenCacheRepositoryResolver(val repo: MavenCache, settings: IvySettings)
extends AbstractMavenRepositoryResolver(settings) with CustomMavenResolver {
setName(repo.name)
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl
sbt.IO.createDirectory(repo.rootFile)

View File

@ -0,0 +1,13 @@
package sbt
import UpdateOptions.ResolverConverter
import org.apache.ivy.plugins.resolver.{ MavenCacheRepositoryResolver, MavenRemoteRepositoryResolver }
object MavenResolverConverter {
val converter: ResolverConverter = {
case (cache: MavenCache, settings, log) =>
new MavenCacheRepositoryResolver(cache, settings)
case (repo: MavenRepository, settings, log) =>
new MavenRemoteRepositoryResolver(repo, settings)
}
}

View File

@ -0,0 +1,13 @@
package sbt
package plugins
import Keys._
object MavenResolverPlugin extends AutoPlugin {
override def requires = IvyPlugin
override def trigger = allRequirements
override lazy val projectSettings: Seq[Setting[_]] = Seq(
updateOptions := updateOptions.value.withResolverConverter(MavenResolverConverter.converter)
)
}

View File

@ -14,14 +14,13 @@ lazy val main = project.
libraryDependencies += (projectID in library).value,
fullResolvers := fullResolvers.value.filterNot(_.name == "inter-project"),
// TODO - should this not be needed?
updateOptions := updateOptions.value.withLatestSnapshots(true).withAetherResolution(true)
updateOptions := updateOptions.value.withLatestSnapshots(true)
)
lazy val library = project.
settings(commonSettings: _*).
settings(
uniqueName,
updateOptions := updateOptions.value.withAetherResolution(true)
uniqueName
)
def uniqueName =

View File

@ -0,0 +1,2 @@
libraryDependencies += Defaults.sbtPluginExtra("org.scala-sbt" % "sbt-maven-resolver" % sbtVersion.value,
sbtBinaryVersion.value, scalaBinaryVersion.value)