Merge pull request #1795 from sbt/wip/aether-resolver-plugin

Turn Aether integration into sbt-maven-resolver
This commit is contained in:
Josh Suereth 2015-01-12 13:41:59 -05:00
commit cacc454af5
25 changed files with 133 additions and 79 deletions

View File

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

View File

@ -1,6 +1,4 @@
package org.apache.maven.repository.internal; package sbt;
/** /**
* Extra properties we dump from Aether into the properties list. * Extra properties we dump from Aether into the properties list.

View File

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

View File

@ -13,7 +13,7 @@ import java.io.{ File, InputStream }
import java.net.URL import java.net.URL
import java.util.regex.Pattern import java.util.regex.Pattern
import org.apache.maven.repository.internal.{ SbtExtraProperties, PomExtraDependencyAttributes } import org.apache.maven.repository.internal.{ PomExtraDependencyAttributes }
@deprecated("0.13.8", "We now use an Aether-based pom parser.") @deprecated("0.13.8", "We now use an Aether-based pom parser.")
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser { final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser {

View File

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

View File

@ -20,6 +20,7 @@ import org.apache.ivy.Ivy
import org.apache.ivy.core.settings.IvySettings import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.core.module.descriptor.{ DependencyArtifactDescriptor, DependencyDescriptor, License, ModuleDescriptor, ExcludeRule } import org.apache.ivy.core.module.descriptor.{ DependencyArtifactDescriptor, DependencyDescriptor, License, ModuleDescriptor, ExcludeRule }
import org.apache.ivy.plugins.resolver.{ ChainResolver, DependencyResolver, IBiblioResolver } import org.apache.ivy.plugins.resolver.{ ChainResolver, DependencyResolver, IBiblioResolver }
import ivyint.CustomRemoteMavenResolver
class MakePom(val log: Logger) { 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") @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 repositories = if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
val mavenRepositories = val mavenRepositories =
repositories.flatMap { 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 MavenRepository(m.repo.name, m.repo.root) :: Nil
case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.root => case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.root =>
MavenRepository(m.getName, m.getRoot) :: Nil MavenRepository(m.getName, m.getRoot) :: Nil

View File

@ -5,8 +5,6 @@ package sbt
import java.net.URL import java.net.URL
import org.apache.maven.repository.internal.SbtExtraProperties
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled) { final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled) {
override def toString: String = override def toString: String =
organization + ":" + name + ":" + revision + organization + ":" + name + ":" + revision +

View File

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

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) val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
artifactOpt match { artifactOpt match {
case None if resolver.getName == "inter-project" => // do nothing 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.... // 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... // 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") case None => throw new RuntimeException(s"\t${resolver.getName}: no ivy file nor artifact found for $rmr")

View File

@ -3,8 +3,6 @@ package sbt
import java.io.File import java.io.File
import java.net.{ MalformedURLException, URL } import java.net.{ MalformedURLException, URL }
import org.apache.maven.repository.internal.SbtExtraProperties
private[sbt] object APIMappings { private[sbt] object APIMappings {
def extract(cp: Seq[Attributed[File]], log: Logger): Seq[(File, URL)] = def extract(cp: Seq[Attributed[File]], log: Logger): Seq[(File, URL)] =
cp.flatMap(entry => extractFromEntry(entry, log)) cp.flatMap(entry => extractFromEntry(entry, log))

View File

@ -5,7 +5,7 @@ package sbt
import Attributed.data import Attributed.data
import Scope.{ fillTaskAxis, GlobalScope, ThisScope } import Scope.{ fillTaskAxis, GlobalScope, ThisScope }
import org.apache.maven.repository.internal.{ SbtExtraProperties, PomExtraDependencyAttributes } import org.apache.maven.repository.internal.PomExtraDependencyAttributes
import sbt.Compiler.InputsWithPrevious import sbt.Compiler.InputsWithPrevious
import xsbt.api.Discovery import xsbt.api.Discovery
import xsbti.compile.CompileOrder import xsbti.compile.CompileOrder

View File

@ -9,36 +9,36 @@
### Improvements ### Improvements
### Aether Resolution ### Maven resolver plugin
sbt 0.13.8 adds the ability to use Eclipse Aether to resolve maven dependencies. This is designed to work within Ivy sbt 0.13.8 adds an extention point in the dependency resolution to customize Maven resolvers.
so that both Aether + Ivy dependencies cohesively depend on each other. This allows us to write sbt-maven-resolver auto plugin, which internally uses Eclipse Aether
to resolve Maven dependencies instead of Apache Ivy.
The key called `updateOptions` has been expanded to enable Aether resolutions via the following setting: To enable this plugin, add the following to `project/maven.sbt` (or `project/plugin.sbt` the file name doesn't matter):
updateOptions := updateOptions.value.withAetherResolution(true) libraryDependencies += Defaults.sbtPluginExtra("org.scala-sbt" % "sbt-maven-resolver" % sbtVersion.value,
sbtBinaryVersion.value, scalaBinaryVersion.value)
This will create a new `~/.ivy2/maven-cache` directory which contains the Aether cache of files. You may notice some This will create a new `~/.ivy2/maven-cache` directory, which contains the Aether cache of files.
file will be re-downloaded for the new cache layout. Additionally, sbt will now be able to fully construct You may notice some file will be re-downloaded for the new cache layout.
Additionally, sbt will now be able to fully construct
`maven-metadata.xml` files when publishing to remote repositories or when publishing to the local `~/.m2/repository`. `maven-metadata.xml` files when publishing to remote repositories or when publishing to the local `~/.m2/repository`.
This should help erase many of the deficiencies encountered when using Maven and sbt together. This should help erase many of the deficiencies encountered when using Maven and sbt together.
Note: The setting must be places on EVERY subproject within a build if you wish to fully use Aether for all projects. **Notes and known limitations**:
Known limitations: - sbt-maven-resolver requires sbt 0.13.8 and above.
- The current implementation does not support Ivy-style dynamic revisions, such as "2.10.+" or "latest.snapshot". This
* The current implementation does not support ivy-style version numbers, such as "2.10.+" or "latest.snapshot". This
is a fixable situation, but the version range query and Ivy -> Maven version range translation code has not been migrated. is a fixable situation, but the version range query and Ivy -> Maven version range translation code has not been migrated.
### Bug fixes ### Bug fixes
- sbt doens't honor Maven's uniqueVersions (use aether resolver to fix). [#1322][1322] by [@jsuereth][@jsuereth] - sbt doens't honor Maven's uniqueVersions (use sbt-maven-resolver to fix). [#1322][1322] by [@jsuereth][@jsuereth]
- sbt doens't see new SNAPSHOT dependency versions in local maven repos (use withLatestSnapshots + aether resolver to fix) [#321][321] by [@jsuereth][@jsuereth] - sbt doens't see new SNAPSHOT dependency versions in local maven repos (use withLatestSnapshots + sbt-maven-resolver to fix) [#321][321] by [@jsuereth][@jsuereth]
- Property in pom's version field results to wrong dependency resolution (use aether resolver to fix). [#647][647] by [@jsuereth][@jsuereth] - Property in pom's version field results to wrong dependency resolution (use sbt-maven-resolver to fix). [#647][647] by [@jsuereth][@jsuereth]
- Maven local resolver with parent POM (use aether resolver). [#1616][1616] by [@jsuereth][@jsuereth] - Maven local resolver with parent POM (use sbt-maven-resolver). [#1616][1616] by [@jsuereth][@jsuereth]
// Possibly fixed, need verification. // Possibly fixed, need verification.
- 1676 - SNAPSHOT dependency not updated ??? - 1676 - SNAPSHOT dependency not updated ???
- 679 - Incorrect Maven Snapshot file resolution ???? - 679 - Incorrect Maven Snapshot file resolution ????

View File

@ -81,6 +81,7 @@ import org.eclipse.aether.spi.log.Logger;
import org.eclipse.aether.spi.log.LoggerFactory; import org.eclipse.aether.spi.log.LoggerFactory;
import org.eclipse.aether.spi.log.NullLoggerFactory; import org.eclipse.aether.spi.log.NullLoggerFactory;
import org.eclipse.aether.transfer.ArtifactNotFoundException; import org.eclipse.aether.transfer.ArtifactNotFoundException;
import sbt.SbtExtraProperties;
/** /**
* A hacked version of maven's default artifact descriptor reader which we use in place of the standard aether adapter. * A hacked version of maven's default artifact descriptor reader which we use in place of the standard aether adapter.

View File

@ -15,7 +15,7 @@ import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter
import org.apache.ivy.plugins.resolver.MavenRepositoryResolver.JarPackaging import org.apache.ivy.plugins.resolver.MavenRepositoryResolver.JarPackaging
import org.apache.ivy.plugins.resolver.util.ResolvedResource import org.apache.ivy.plugins.resolver.util.ResolvedResource
import org.apache.ivy.util.Message import org.apache.ivy.util.Message
import org.apache.maven.repository.internal.{ PomExtraDependencyAttributes, SbtRepositoryLayout, SbtExtraProperties } import org.apache.maven.repository.internal.{ PomExtraDependencyAttributes, SbtRepositoryLayout }
import org.eclipse.aether.{ RepositorySystemSession, RepositorySystem } import org.eclipse.aether.{ RepositorySystemSession, RepositorySystem }
import org.eclipse.aether.artifact.{ DefaultArtifact => AetherArtifact } import org.eclipse.aether.artifact.{ DefaultArtifact => AetherArtifact }
import org.eclipse.aether.metadata.{ Metadata, DefaultMetadata } import org.eclipse.aether.metadata.{ Metadata, DefaultMetadata }
@ -29,7 +29,8 @@ import org.eclipse.aether.resolution.{
import org.eclipse.aether.deployment.{ DeployRequest => AetherDeployRequest } import org.eclipse.aether.deployment.{ DeployRequest => AetherDeployRequest }
import org.eclipse.aether.installation.{ InstallRequest => AetherInstallRequest } import org.eclipse.aether.installation.{ InstallRequest => AetherInstallRequest }
import org.apache.ivy.core.cache.{ ModuleDescriptorWriter, ArtifactOrigin } import org.apache.ivy.core.cache.{ ModuleDescriptorWriter, ArtifactOrigin }
import sbt.{ MavenCache, MavenRepository } import sbt.{ MavenCache, MavenRepository, SbtExtraProperties }
import sbt.ivyint.{ CustomMavenResolver, CustomRemoteMavenResolver }
import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
object MavenRepositoryResolver { object MavenRepositoryResolver {
@ -60,7 +61,8 @@ object MavenRepositoryResolver {
* Note: This creates its *own* local cache directory for cache metadata. using its name. * 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) setName(repo.name)
override def toString = s"${repo.name}: ${repo.root}" override def toString = s"${repo.name}: ${repo.root}"
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl 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. * 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) setName(repo.name)
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl
sbt.IO.createDirectory(repo.rootFile) sbt.IO.createDirectory(repo.rootFile)

View File

@ -9,6 +9,7 @@ import org.eclipse.aether.metadata.Metadata
import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum
import org.eclipse.aether.artifact.Artifact import org.eclipse.aether.artifact.Artifact
import java.net.URI import java.net.URI
import sbt.SbtExtraProperties
import scala.util.matching.Regex import scala.util.matching.Regex

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

@ -55,7 +55,7 @@ class MavenResolutionSpec extends BaseIvySpecification {
import ShowLines._ import ShowLines._
def defaultUpdateOptions = UpdateOptions().withAetherResolution(true) def defaultUpdateOptions = UpdateOptions().withResolverConverter(MavenResolverConverter.converter)
def resolveMajorConflicts = { def resolveMajorConflicts = {
val m = module(ModuleID("com.example", "foo", "0.1.0", Some("compile")), val m = module(ModuleID("com.example", "foo", "0.1.0", Some("compile")),

View File

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

View File

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

View File

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

View File

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

View File

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