Refactoring code.

* remove debugging statements
* Move each class so it's one name-per-file
* Migrate out of org.apache namespace into sbt.mavenint
This commit is contained in:
Josh Suereth 2015-01-12 14:48:23 -05:00
parent cacc454af5
commit 42424b4cdb
20 changed files with 425 additions and 392 deletions

View File

@ -1,9 +1,9 @@
package sbt;
package sbt.mavenint;
/**
* Extra properties we dump from Aether into the properties list.
*/
public class SbtExtraProperties {
public class SbtPomExtraProperties {
public static final String MAVEN_PACKAGING_KEY = "sbt.pom.packaging";
public static final String SCALA_VERSION_KEY = "sbt.pom.scalaversion";

View File

@ -12,8 +12,7 @@ import org.apache.ivy.util.extendable.ExtendableItem
import java.io.{ File, InputStream }
import java.net.URL
import java.util.regex.Pattern
import org.apache.maven.repository.internal.{ PomExtraDependencyAttributes }
import sbt.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties }
@deprecated("0.13.8", "We now use an Aether-based pom parser.")
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser {
@ -36,8 +35,8 @@ object CustomPomParser {
ReplaceMavenConfigurationMappings.init()
/** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution.*/
val InfoKeyPrefix = SbtExtraProperties.POM_INFO_KEY_PREFIX
val ApiURLKey = SbtExtraProperties.POM_API_KEY
val InfoKeyPrefix = SbtPomExtraProperties.POM_INFO_KEY_PREFIX
val ApiURLKey = SbtPomExtraProperties.POM_API_KEY
val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey
val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey

View File

@ -9,7 +9,7 @@ package sbt
import java.io.File
import org.apache.maven.repository.internal.PomExtraDependencyAttributes
import sbt.mavenint.PomExtraDependencyAttributes
// Node needs to be renamed to XNode because the task subproject contains a Node type that will shadow
// scala.xml.Node when generating aggregated API documentation

View File

@ -5,6 +5,8 @@ package sbt
import java.net.URL
import sbt.mavenint.SbtPomExtraProperties
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 =
organization + ":" + name + ":" + revision +
@ -15,7 +17,7 @@ final case class ModuleID(organization: String, name: String, revision: String,
def extraString: String = extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")")
/** Returns the extra attributes except for ones marked as information only (ones that typically would not be used for dependency resolution). */
def extraDependencyAttributes: Map[String, String] = extraAttributes.filterKeys(!_.startsWith(SbtExtraProperties.POM_INFO_KEY_PREFIX))
def extraDependencyAttributes: Map[String, String] = extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX))
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else CrossVersion.Disabled)

View File

@ -1,4 +1,4 @@
package org.apache.maven.repository.internal
package sbt.mavenint
import java.util.Properties
import java.util.regex.Pattern
@ -31,7 +31,7 @@ object PomExtraDependencyAttributes {
* A map of module id to extra dependency attributes associated with dependencies on that module.
*/
def readFromAether(props: java.util.Map[String, AnyRef]): Map[ModuleRevisionId, Map[String, String]] = {
import collection.JavaConverters._
import scala.collection.JavaConverters._
(props.asScala get ExtraAttributesKey) match {
case None => Map.empty
case Some(str) =>
@ -71,7 +71,7 @@ object PomExtraDependencyAttributes {
}
def qualifiedExtra(item: ExtendableItem): Map[String, String] = {
import collection.JavaConverters._
import scala.collection.JavaConverters._
item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap
}
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
@ -83,7 +83,7 @@ object PomExtraDependencyAttributes {
// This makes the id suitable as a key to associate a dependency parsed from a <dependency> element
// with the extra attributes from the <properties> section
def simplify(id: ModuleRevisionId): ModuleRevisionId = {
import collection.JavaConverters._
import scala.collection.JavaConverters._
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include = false).asJava)
}

View File

@ -3,6 +3,8 @@ package sbt
import java.io.File
import java.net.{ MalformedURLException, URL }
import sbt.mavenint.SbtPomExtraProperties
private[sbt] object APIMappings {
def extract(cp: Seq[Attributed[File]], log: Logger): Seq[(File, URL)] =
cp.flatMap(entry => extractFromEntry(entry, log))
@ -15,7 +17,7 @@ private[sbt] object APIMappings {
private[this] def extractFromID(entry: File, mid: ModuleID, log: Logger): Option[(File, URL)] =
for {
urlString <- mid.extraAttributes.get(SbtExtraProperties.POM_API_KEY)
urlString <- mid.extraAttributes.get(SbtPomExtraProperties.POM_API_KEY)
u <- parseURL(urlString, entry, log)
} yield (entry, u)

View File

@ -5,8 +5,8 @@ package sbt
import Attributed.data
import Scope.{ fillTaskAxis, GlobalScope, ThisScope }
import org.apache.maven.repository.internal.PomExtraDependencyAttributes
import sbt.Compiler.InputsWithPrevious
import sbt.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties }
import xsbt.api.Discovery
import xsbti.compile.CompileOrder
import Project.{ inConfig, inScope, inTask, richInitialize, richInitializeTask, richTaskSessionVar }
@ -1216,7 +1216,7 @@ object Classpaths {
private[sbt] def defaultProjectID: Initialize[ModuleID] = Def.setting {
val base = ModuleID(organization.value, moduleName.value, version.value).cross(crossVersion in projectID value).artifacts(artifacts.value: _*)
apiURL.value match {
case Some(u) if autoAPIMappings.value => base.extra(SbtExtraProperties.POM_API_KEY -> u.toExternalForm)
case Some(u) if autoAPIMappings.value => base.extra(SbtPomExtraProperties.POM_API_KEY -> u.toExternalForm)
case _ => base
}
}

View File

@ -81,7 +81,8 @@ import org.eclipse.aether.spi.log.Logger;
import org.eclipse.aether.spi.log.LoggerFactory;
import org.eclipse.aether.spi.log.NullLoggerFactory;
import org.eclipse.aether.transfer.ArtifactNotFoundException;
import sbt.SbtExtraProperties;
import sbt.mavenint.PomExtraDependencyAttributes;
import sbt.mavenint.SbtPomExtraProperties;
/**
* A hacked version of maven's default artifact descriptor reader which we use in place of the standard aether adapter.
@ -260,12 +261,12 @@ public class SbtArtifactDescriptorReader
}
List<License> licenses = model.getLicenses();
properties.put( SbtExtraProperties.LICENSE_COUNT_KEY, licenses.size() );
properties.put( SbtPomExtraProperties.LICENSE_COUNT_KEY, licenses.size() );
for ( int i = 0; i < licenses.size(); i++ )
{
License license = licenses.get( i );
properties.put( SbtExtraProperties.makeLicenseName(i), license.getName() );
properties.put( SbtExtraProperties.makeLicenseUrl(i), license.getUrl() );
properties.put( SbtPomExtraProperties.makeLicenseName(i), license.getName() );
properties.put( SbtPomExtraProperties.makeLicenseUrl(i), license.getUrl() );
properties.put( "license." + i + ".comments", license.getComments() );
properties.put( "license." + i + ".distribution", license.getDistribution() );
}
@ -273,15 +274,15 @@ public class SbtArtifactDescriptorReader
// SBT ADDED - Here we push in the pom packaging type for Ivy expectations.
final String packaging =
(model.getPackaging() == null) ? "jar" : model.getPackaging();
properties.put(SbtExtraProperties.MAVEN_PACKAGING_KEY, packaging);
properties.put(SbtPomExtraProperties.MAVEN_PACKAGING_KEY, packaging);
// SBT ADDED - Here we inject the sbt/scala version we parse out of the pom.
final Properties mprops = model.getProperties();
if(mprops.containsKey(SbtExtraProperties.POM_SBT_VERSION)) {
final String sbtVersion = mprops.getProperty(SbtExtraProperties.POM_SBT_VERSION);
properties.put(SbtExtraProperties.SBT_VERSION_KEY, sbtVersion);
if(mprops.containsKey(SbtPomExtraProperties.POM_SBT_VERSION)) {
final String sbtVersion = mprops.getProperty(SbtPomExtraProperties.POM_SBT_VERSION);
properties.put(SbtPomExtraProperties.SBT_VERSION_KEY, sbtVersion);
}
if(mprops.containsKey(SbtExtraProperties.POM_SCALA_VERSION)) {
properties.put(SbtExtraProperties.SCALA_VERSION_KEY, mprops.getProperty(SbtExtraProperties.POM_SCALA_VERSION));
if(mprops.containsKey(SbtPomExtraProperties.POM_SCALA_VERSION)) {
properties.put(SbtPomExtraProperties.SCALA_VERSION_KEY, mprops.getProperty(SbtPomExtraProperties.POM_SCALA_VERSION));
}
// SBT-Added - Here we inject the additional dependency attributes (for transitive plugin resolution).

View File

@ -1,160 +0,0 @@
package org.apache.ivy.plugins.resolver
import java.net.URI
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.repository.url.URLResource
import org.apache.ivy.util.Message
import org.apache.ivy.util.url.URLHandlerRegistry
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.impl.{ MetadataGeneratorFactory, ArtifactDescriptorReader, RepositoryConnectorProvider, DefaultServiceLocator }
import org.eclipse.aether.metadata.Metadata
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory
import org.eclipse.aether.spi.connector.layout.{ RepositoryLayoutFactory, RepositoryLayoutProvider, RepositoryLayout }
import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum
import org.eclipse.aether.{
RepositorySystem,
RepositorySystemSession
}
import org.eclipse.aether.repository.{ RemoteRepository, LocalRepository }
import org.eclipse.aether.RepositorySystemSession
import org.apache.maven.repository.internal._
import org.eclipse.aether.spi.connector.transport._
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
import java.io.File
/** Helper methods for dealing with starting up Aether. */
object MavenRepositorySystemFactory {
def newRepositorySystemImpl: RepositorySystem = {
// For now we just log Aether instantiation issues. These should probably cause fatal errors.
val locator = MavenRepositorySystemUtils.newServiceLocator()
locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler {
override def serviceCreationFailed(tpe: Class[_], impl: Class[_], exception: Throwable): Unit = {
Message.error(s"Failed to create $tpe, of class $impl")
}
})
// Here we register the Ivy <-> Aether transport bridge
locator.addService(classOf[TransporterFactory], classOf[MyTransportFactory])
// This connects the download mechanism to our transports. Why is it needed? no clue.
locator.addService(classOf[RepositoryConnectorFactory], classOf[BasicRepositoryConnectorFactory])
// Plugins cause issues here, as their layout is super odd. Here we inject a new plugin layout
locator.addService(classOf[RepositoryLayoutFactory], classOf[SbtPluginLayoutFactory])
// Here we add the metadata services so aether will automatically add maven-metadata.xml files.
locator.addService(classOf[MetadataGeneratorFactory], classOf[SnapshotMetadataGeneratorFactory])
locator.addService(classOf[MetadataGeneratorFactory], classOf[VersionsMetadataGeneratorFactory])
// Add our hook for parsing pom.xml files.
locator.setService(classOf[ArtifactDescriptorReader], classOf[SbtArtifactDescriptorReader])
// Finally, use the DI to create our repository system.
locator.getService(classOf[RepositorySystem])
}
def newSessionImpl(system: RepositorySystem, localRepoDir: File): RepositorySystemSession = {
val session = MavenRepositorySystemUtils.newSession()
val localRepo = new LocalRepository(localRepoDir)
session setLocalRepositoryManager (system.newLocalRepositoryManager(session, localRepo))
// Here we set a descriptor policy that FORCES the pom.xml to exist, otherwise Ivy's resolution
// algorithm freaks out. What we could do is also do the ivy lame-thing of checking for a JAR
// instead of a pom.xml, but let's see if this is actually a problem in practice.
val descriptorPolicy = new org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy(
/* ignoreMissing */ false, /* ignoreInvalid. */ true)
session.setArtifactDescriptorPolicy(descriptorPolicy)
session
}
def defaultLocalRepo: java.io.File = {
new java.io.File(s"${sys.props("user.home")}/.m2/repository")
}
}
/** Override aether's default transport with Ivy-ones. */
class MyTransportFactory extends TransporterFactory {
override def newInstance(session: RepositorySystemSession, repository: RemoteRepository): Transporter =
repository.getProtocol match {
case "http" | "https" => new HttpTransport(repository)
case "file" => new FileTransport(repository)
case other => throw new IllegalArgumentException(s"Unsupported transport protocol: $other")
}
override def getPriority: Float = 1.0f
}
/** Aether Http <-> Ivy Http adapter. Aether's is better, but Ivy's has configuration hooks in sbt. */
class HttpTransport(repository: RemoteRepository) extends AbstractTransporter {
class NotFoundException(msg: String) extends Exception(msg)
private def toURL(task: TransportTask): java.net.URL =
try new java.net.URL(s"${repository.getUrl}/${task.getLocation.toASCIIString}")
catch {
case e: IllegalArgumentException => throw new IllegalArgumentException(s" URL (${task.getLocation}) is not absolute.")
}
private def toResource(task: TransportTask): Resource = new URLResource(toURL(task))
override def implPeek(peek: PeekTask): Unit = {
if (!toResource(peek).exists()) throw new NotFoundException(s"Could not find ${peek.getLocation}")
}
override def implClose(): Unit = ()
override def implGet(out: GetTask): Unit = {
if (!toResource(out).exists()) throw new NotFoundException(s"Could not find ${out.getLocation}")
URLHandlerRegistry.getDefault.download(toURL(out), out.getDataFile, null)
}
override def implPut(put: PutTask): Unit = {
val to = toURL(put)
Option(put.getDataFile) match {
case Some(file) => URLHandlerRegistry.getDefault.upload(file, to, null)
case None =>
// TODO - Ivy does not support uploading not from a file. This isn't very efficient in ANY way,
// so if we rewrite the URL handler for Ivy we should fix this as well.
sbt.IO.withTemporaryFile("tmp", "upload") { file =>
val in = put.newInputStream()
try sbt.IO.transfer(in, file)
finally in.close()
URLHandlerRegistry.getDefault.upload(file, to, null)
}
}
}
override def classify(err: Throwable): Int =
err match {
// TODO - Implement
case _: NotFoundException => Transporter.ERROR_NOT_FOUND
case _ => Transporter.ERROR_OTHER
}
}
class FileTransport(repository: RemoteRepository) extends AbstractTransporter {
class NotFoundException(msg: String) extends Exception(msg)
private def toURL(task: TransportTask): java.net.URL =
try new java.net.URL(s"${repository.getUrl}/${task.getLocation.toASCIIString}")
catch {
case e: IllegalArgumentException => throw new IllegalArgumentException(s" URL (${task.getLocation}) is not absolute.")
}
private def toResource(task: TransportTask): Resource = new URLResource(toURL(task))
private def toFile(task: TransportTask): java.io.File =
new java.io.File(toURL(task).toURI)
override def implPeek(peek: PeekTask): Unit = {
if (!toFile(peek).exists()) throw new NotFoundException(s"Could not find ${peek.getLocation}")
}
override def implClose(): Unit = ()
override def implGet(out: GetTask): Unit = {
val from = toFile(out)
if (!from.exists()) throw new NotFoundException(s"Could not find ${out.getLocation}")
sbt.IO.copyFile(from, out.getDataFile, true)
}
override def implPut(put: PutTask): Unit = {
val to = toFile(put)
Option(put.getDataFile) match {
case Some(from) =>
sbt.IO.copyFile(from, to, true)
case None =>
// Here it's most likely a SHA or somethign where we read from memory.
val in = put.newInputStream
try sbt.IO.transfer(in, to)
finally in.close()
}
}
override def classify(err: Throwable): Int =
err match {
// TODO - Implement
case _: NotFoundException => Transporter.ERROR_NOT_FOUND
case _ => Transporter.ERROR_OTHER
}
}

View File

@ -1,7 +1,7 @@
package sbt
import UpdateOptions.ResolverConverter
import org.apache.ivy.plugins.resolver.{ MavenCacheRepositoryResolver, MavenRemoteRepositoryResolver }
import sbt.mavenint.{ MavenCacheRepositoryResolver, MavenRemoteRepositoryResolver }
object MavenResolverConverter {
val converter: ResolverConverter = {

View File

@ -0,0 +1,48 @@
package sbt.mavenint
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.repository.url.URLResource
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.spi.connector.transport._
/**
* A bridge file transportation protocol which uses some Ivy/sbt mechanisms.
*/
class FileTransport(repository: RemoteRepository) extends AbstractTransporter {
class NotFoundException(msg: String) extends Exception(msg)
private def toURL(task: TransportTask): java.net.URL =
try new java.net.URL(s"${repository.getUrl}/${task.getLocation.toASCIIString}")
catch {
case e: IllegalArgumentException => throw new IllegalArgumentException(s" URL (${task.getLocation}) is not absolute.")
}
private def toResource(task: TransportTask): Resource = new URLResource(toURL(task))
private def toFile(task: TransportTask): java.io.File =
new java.io.File(toURL(task).toURI)
override def implPeek(peek: PeekTask): Unit = {
if (!toFile(peek).exists()) throw new NotFoundException(s"Could not find ${peek.getLocation}")
}
override def implClose(): Unit = ()
override def implGet(out: GetTask): Unit = {
val from = toFile(out)
if (!from.exists()) throw new NotFoundException(s"Could not find ${out.getLocation}")
sbt.IO.copyFile(from, out.getDataFile, true)
}
override def implPut(put: PutTask): Unit = {
val to = toFile(put)
Option(put.getDataFile) match {
case Some(from) =>
sbt.IO.copyFile(from, to, true)
case None =>
// Here it's most likely a SHA or somethign where we read from memory.
val in = put.newInputStream
try sbt.IO.transfer(in, to)
finally in.close()
}
}
override def classify(err: Throwable): Int =
err match {
// TODO - Have we caught enough exceptions here?
case _: NotFoundException => Transporter.ERROR_NOT_FOUND
case _ => Transporter.ERROR_OTHER
}
}

View File

@ -0,0 +1,47 @@
package sbt.mavenint
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.repository.url.URLResource
import org.apache.ivy.util.url.URLHandlerRegistry
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.spi.connector.transport._
/** Aether Http <-> Ivy Http adapter. Aether's is better, but Ivy's has configuration hooks in sbt. */
class HttpTransport(repository: RemoteRepository) extends AbstractTransporter {
class NotFoundException(msg: String) extends Exception(msg)
private def toURL(task: TransportTask): java.net.URL =
try new java.net.URL(s"${repository.getUrl}/${task.getLocation.toASCIIString}")
catch {
case e: IllegalArgumentException => throw new IllegalArgumentException(s" URL (${task.getLocation}) is not absolute.")
}
private def toResource(task: TransportTask): Resource = new URLResource(toURL(task))
override def implPeek(peek: PeekTask): Unit = {
if (!toResource(peek).exists()) throw new NotFoundException(s"Could not find ${peek.getLocation}")
}
override def implClose(): Unit = ()
override def implGet(out: GetTask): Unit = {
if (!toResource(out).exists()) throw new NotFoundException(s"Could not find ${out.getLocation}")
URLHandlerRegistry.getDefault.download(toURL(out), out.getDataFile, null)
}
override def implPut(put: PutTask): Unit = {
val to = toURL(put)
Option(put.getDataFile) match {
case Some(file) => URLHandlerRegistry.getDefault.upload(file, to, null)
case None =>
// TODO - Ivy does not support uploading not from a file. This isn't very efficient in ANY way,
// so if we rewrite the URL handler for Ivy we should fix this as well.
sbt.IO.withTemporaryFile("tmp", "upload") { file =>
val in = put.newInputStream()
try sbt.IO.transfer(in, file)
finally in.close()
URLHandlerRegistry.getDefault.upload(file, to, null)
}
}
}
override def classify(err: Throwable): Int =
err match {
// TODO - Have we caught all the important exceptions here.
case _: NotFoundException => Transporter.ERROR_NOT_FOUND
case _ => Transporter.ERROR_OTHER
}
}

View File

@ -0,0 +1,80 @@
package sbt
package mavenint
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.core.settings.IvySettings
import org.eclipse.aether.artifact.{ DefaultArtifact => AetherArtifact }
import org.eclipse.aether.installation.{ InstallRequest => AetherInstallRequest }
import org.eclipse.aether.metadata.{ DefaultMetadata, Metadata }
import org.eclipse.aether.resolution.{
ArtifactDescriptorRequest => AetherDescriptorRequest,
ArtifactRequest => AetherArtifactRequest,
MetadataRequest => AetherMetadataRequest
}
import sbt.ivyint.CustomMavenResolver
import scala.collection.JavaConverters._
/**
* A resolver instance which can resolve from a maven CACHE.
*
* 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 MavenRepositoryResolver(settings) with CustomMavenResolver {
setName(repo.name)
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl
sbt.IO.createDirectory(repo.rootFile)
protected val session = MavenRepositorySystemFactory.newSessionImpl(system, repo.rootFile)
protected def setRepository(request: AetherMetadataRequest): AetherMetadataRequest = request
protected def addRepositories(request: AetherDescriptorRequest): AetherDescriptorRequest = request
protected def addRepositories(request: AetherArtifactRequest): AetherArtifactRequest = request
protected def publishArtifacts(artifacts: Seq[AetherArtifact]): Unit = {
val request = new AetherInstallRequest()
artifacts foreach request.addArtifact
system.install(session, request)
}
// TODO - Share this with non-local repository code, since it's MOSTLY the same.
protected def getPublicationTime(mrid: ModuleRevisionId): Option[Long] = {
val metadataRequest = new AetherMetadataRequest()
metadataRequest.setMetadata(
new DefaultMetadata(
mrid.getOrganisation,
mrid.getName,
mrid.getRevision,
MavenRepositoryResolver.MAVEN_METADATA_XML,
Metadata.Nature.RELEASE_OR_SNAPSHOT))
val metadataResultOpt =
try system.resolveMetadata(session, java.util.Arrays.asList(metadataRequest)).asScala.headOption
catch {
case e: org.eclipse.aether.resolution.ArtifactResolutionException => None
}
try metadataResultOpt match {
case Some(md) if md.isResolved =>
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader
import org.codehaus.plexus.util.ReaderFactory
val readMetadata = {
val reader = ReaderFactory.newXmlReader(md.getMetadata.getFile)
try new MetadataXpp3Reader().read(reader, false)
finally reader.close()
}
val timestampOpt =
for {
v <- Option(readMetadata.getVersioning)
sp <- Option(v.getSnapshot)
ts <- Option(sp.getTimestamp)
t <- MavenRepositoryResolver.parseTimeString(ts)
} yield t
val lastUpdatedOpt =
for {
v <- Option(readMetadata.getVersioning)
lu <- Option(v.getLastUpdated)
d <- MavenRepositoryResolver.parseTimeString(lu)
} yield d
// TODO - Only look at timestamp *IF* the version is for a snapshot.
timestampOpt orElse lastUpdatedOpt
case _ => None
}
}
override def toString = s"${repo.name}: ${repo.root}"
}

View File

@ -0,0 +1,95 @@
package sbt
package mavenint
import org.apache.ivy.core.IvyContext
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.core.settings.IvySettings
import org.eclipse.aether.artifact.{ DefaultArtifact => AetherArtifact }
import org.eclipse.aether.deployment.{ DeployRequest => AetherDeployRequest }
import org.eclipse.aether.metadata.{ DefaultMetadata, Metadata }
import org.eclipse.aether.resolution.{
ArtifactDescriptorRequest => AetherDescriptorRequest,
ArtifactDescriptorResult => AetherDescriptorResult,
ArtifactRequest => AetherArtifactRequest,
MetadataRequest => AetherMetadataRequest
}
import sbt.ivyint.CustomRemoteMavenResolver
import scala.collection.JavaConverters._
/**
* A resolver instance which can resolve from a REMOTE maven repository.
*
* Note: This creates its *own* local cache directory for cache metadata. using its name.
*
*/
class MavenRemoteRepositoryResolver(val repo: MavenRepository, settings: IvySettings)
extends MavenRepositoryResolver(settings) with CustomRemoteMavenResolver {
setName(repo.name)
override def toString = s"${repo.name}: ${repo.root}"
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl
// Note: All maven repository resolvers will use the SAME maven cache.
// We're not sure if we care whether or not this means that the wrong resolver may report finding an artifact.
// The key is not to duplicate files repeatedly across many caches.
private val localRepo = new java.io.File(settings.getDefaultIvyUserDir, s"maven-cache")
sbt.IO.createDirectory(localRepo)
protected val session = MavenRepositorySystemFactory.newSessionImpl(system, localRepo)
private val aetherRepository = {
new org.eclipse.aether.repository.RemoteRepository.Builder(repo.name, SbtRepositoryLayout.LAYOUT_NAME, repo.root).build()
}
// TODO - Check if isUseCacheOnly is used correctly.
private def isUseCacheOnly: Boolean =
Option(IvyContext.getContext).flatMap(x => Option(x.getResolveData)).flatMap(x => Option(x.getOptions)).map(_.isUseCacheOnly).getOrElse(false)
protected def addRepositories(request: AetherDescriptorRequest): AetherDescriptorRequest =
if (isUseCacheOnly) request else request.addRepository(aetherRepository)
protected def addRepositories(request: AetherArtifactRequest): AetherArtifactRequest =
if (isUseCacheOnly) request else request.addRepository(aetherRepository)
/** Actually publishes aether artifacts. */
protected def publishArtifacts(artifacts: Seq[AetherArtifact]): Unit = {
val request = new AetherDeployRequest()
request.setRepository(aetherRepository)
artifacts foreach request.addArtifact
system.deploy(session, request)
}
protected def getPublicationTime(mrid: ModuleRevisionId): Option[Long] = {
val metadataRequest = new AetherMetadataRequest()
metadataRequest.setMetadata(
new DefaultMetadata(
mrid.getOrganisation,
mrid.getName,
mrid.getRevision,
MavenRepositoryResolver.MAVEN_METADATA_XML,
Metadata.Nature.RELEASE_OR_SNAPSHOT))
if (!isUseCacheOnly) metadataRequest.setRepository(aetherRepository)
val metadataResultOpt =
try system.resolveMetadata(session, java.util.Arrays.asList(metadataRequest)).asScala.headOption
catch {
case e: org.eclipse.aether.resolution.ArtifactResolutionException => None
}
try metadataResultOpt match {
case Some(md) if md.isResolved =>
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader
import org.codehaus.plexus.util.ReaderFactory
val readMetadata = {
val reader = ReaderFactory.newXmlReader(md.getMetadata.getFile)
try new MetadataXpp3Reader().read(reader, false)
finally reader.close()
}
val timestampOpt =
for {
v <- Option(readMetadata.getVersioning)
sp <- Option(v.getSnapshot)
ts <- Option(sp.getTimestamp)
t <- MavenRepositoryResolver.parseTimeString(ts)
} yield t
val lastUpdatedOpt =
for {
v <- Option(readMetadata.getVersioning)
lu <- Option(v.getLastUpdated)
d <- MavenRepositoryResolver.parseTimeString(lu)
} yield d
// TODO - Only look at timestamp *IF* the version is for a snapshot.
timestampOpt orElse lastUpdatedOpt
case _ => None
}
}
}

View File

@ -1,48 +1,41 @@
package org.apache.ivy.plugins.resolver
package sbt.mavenint
import java.io.{ File, IOException }
import java.text.ParseException
import java.io.File
import java.util.Date
import org.apache.ivy.core.IvyContext
import org.apache.ivy.core.cache.{ ArtifactOrigin, ModuleDescriptorWriter }
import org.apache.ivy.core.module.descriptor._
import org.apache.ivy.core.module.id.{ ModuleId, ArtifactId, ModuleRevisionId }
import org.apache.ivy.core.report.{ ArtifactDownloadReport, DownloadStatus, MetadataArtifactDownloadReport, DownloadReport }
import org.apache.ivy.core.resolve.{ ResolvedModuleRevision, ResolveData, DownloadOptions }
import org.apache.ivy.core.module.id.{ ModuleId, ModuleRevisionId }
import org.apache.ivy.core.report.{ ArtifactDownloadReport, DownloadReport, DownloadStatus, MetadataArtifactDownloadReport }
import org.apache.ivy.core.resolve.{ DownloadOptions, ResolveData, ResolvedModuleRevision }
import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.plugins.matcher.ExactPatternMatcher
import org.apache.ivy.plugins.parser.m2.{ PomModuleDescriptorBuilder, ReplaceMavenConfigurationMappings }
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter
import org.apache.ivy.plugins.resolver.MavenRepositoryResolver.JarPackaging
import org.apache.ivy.plugins.resolver.AbstractResolver
import org.apache.ivy.plugins.resolver.util.ResolvedResource
import org.apache.ivy.util.Message
import org.apache.maven.repository.internal.{ PomExtraDependencyAttributes, SbtRepositoryLayout }
import org.eclipse.aether.{ RepositorySystemSession, RepositorySystem }
import org.eclipse.aether.artifact.{ DefaultArtifact => AetherArtifact }
import org.eclipse.aether.metadata.{ Metadata, DefaultMetadata }
import org.eclipse.aether.resolution.{
ArtifactDescriptorRequest => AetherDescriptorRequest,
ArtifactDescriptorResult => AetherDescriptorResult,
MetadataRequest => AetherMetadataRequest,
ArtifactRequest => AetherArtifactRequest,
ArtifactResolutionException
}
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, SbtExtraProperties }
import org.eclipse.aether.metadata.{ DefaultMetadata, Metadata }
import org.eclipse.aether.resolution.{ ArtifactDescriptorRequest => AetherDescriptorRequest, ArtifactDescriptorResult => AetherDescriptorResult, ArtifactRequest => AetherArtifactRequest, ArtifactResolutionException, MetadataRequest => AetherMetadataRequest }
import org.eclipse.aether.{ RepositorySystem, RepositorySystemSession }
import sbt.ivyint.{ CustomMavenResolver, CustomRemoteMavenResolver }
import sbt.mavenint.MavenRepositoryResolver.JarPackaging
import sbt.{ MavenCache, MavenRepository }
import scala.collection.JavaConverters._
object MavenRepositoryResolver {
val MAVEN_METADATA_XML = "maven-metadata.xml"
val CLASSIFIER_ATTRIBUTE = "e:classifier"
// TODO - This may be duplciated in more than one location. We need to consolidate.
val JarPackagings = Set("eclipse-plugin", "hk2-jar", "orbit", "scala-jar", "jar", "bundle")
object JarPackaging {
def unapply(in: String): Boolean = JarPackagings.contains(in)
}
// Example: 2014 12 18 09 33 56
val LAST_UPDATE_FORMAT = new java.text.SimpleDateFormat("yyyyMMddhhmmss")
def parseTimeString(in: String): Option[Long] =
@ -50,157 +43,15 @@ object MavenRepositoryResolver {
catch {
case _: java.text.ParseException => None
}
val DEFAULT_ARTIFACT_CONFIGURATION = "master"
}
/**
* A resolver instance which can resolve from a REMOTE maven repository.
*
* Note: This creates its *own* local cache directory for cache metadata. using its name.
* An abstract repository resolver which has the basic hooks for mapping from Maven (Aether) notions into Ivy notions.
*
* THis is used to implement local-cache resolution from ~/.m2 caches or resolving from remote repositories.
*/
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
// Note: All maven repository resolvers will use the SAME maven cache.
// We're not sure if we care whether or not this means that the wrong resolver may report finding an artifact.
// The key is not to duplicate files repeatedly across many caches.
private val localRepo = new java.io.File(settings.getDefaultIvyUserDir, s"maven-cache")
sbt.IO.createDirectory(localRepo)
protected val session = MavenRepositorySystemFactory.newSessionImpl(system, localRepo)
private val aetherRepository = {
new org.eclipse.aether.repository.RemoteRepository.Builder(repo.name, SbtRepositoryLayout.LAYOUT_NAME, repo.root).build()
}
// TODO - Check if isUseCacheOnly is used correctly.
private def isUseCacheOnly: Boolean =
Option(IvyContext.getContext).flatMap(x => Option(x.getResolveData)).flatMap(x => Option(x.getOptions)).map(_.isUseCacheOnly).getOrElse(false)
protected def addRepositories(request: AetherDescriptorRequest): AetherDescriptorRequest =
if (isUseCacheOnly) request else request.addRepository(aetherRepository)
protected def addRepositories(request: AetherArtifactRequest): AetherArtifactRequest =
if (isUseCacheOnly) request else request.addRepository(aetherRepository)
/** Actually publishes aether artifacts. */
protected def publishArtifacts(artifacts: Seq[AetherArtifact]): Unit = {
val request = new AetherDeployRequest()
request.setRepository(aetherRepository)
artifacts foreach request.addArtifact
system.deploy(session, request)
}
protected def getPublicationTime(mrid: ModuleRevisionId): Option[Long] = {
val metadataRequest = new AetherMetadataRequest()
metadataRequest.setMetadata(
new DefaultMetadata(
mrid.getOrganisation,
mrid.getName,
mrid.getRevision,
MavenRepositoryResolver.MAVEN_METADATA_XML,
Metadata.Nature.RELEASE_OR_SNAPSHOT))
if (!isUseCacheOnly) metadataRequest.setRepository(aetherRepository)
val metadataResultOpt =
try system.resolveMetadata(session, java.util.Arrays.asList(metadataRequest)).asScala.headOption
catch {
case e: org.eclipse.aether.resolution.ArtifactResolutionException => None
}
try metadataResultOpt match {
case Some(md) if md.isResolved =>
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader
import org.codehaus.plexus.util.ReaderFactory
val readMetadata = {
val reader = ReaderFactory.newXmlReader(md.getMetadata.getFile)
try new MetadataXpp3Reader().read(reader, false)
finally reader.close()
}
val timestampOpt =
for {
v <- Option(readMetadata.getVersioning)
sp <- Option(v.getSnapshot)
ts <- Option(sp.getTimestamp)
t <- MavenRepositoryResolver.parseTimeString(ts)
} yield t
val lastUpdatedOpt =
for {
v <- Option(readMetadata.getVersioning)
lu <- Option(v.getLastUpdated)
d <- MavenRepositoryResolver.parseTimeString(lu)
} yield d
// TODO - Only look at timestamp *IF* the version is for a snapshot.
timestampOpt orElse lastUpdatedOpt
case _ => None
}
}
}
/**
* A resolver instance which can resolve from a maven CACHE.
*
* 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) with CustomMavenResolver {
setName(repo.name)
protected val system = MavenRepositorySystemFactory.newRepositorySystemImpl
sbt.IO.createDirectory(repo.rootFile)
protected val session = MavenRepositorySystemFactory.newSessionImpl(system, repo.rootFile)
protected def setRepository(request: AetherMetadataRequest): AetherMetadataRequest = request
protected def addRepositories(request: AetherDescriptorRequest): AetherDescriptorRequest = request
protected def addRepositories(request: AetherArtifactRequest): AetherArtifactRequest = request
protected def publishArtifacts(artifacts: Seq[AetherArtifact]): Unit = {
val request = new AetherInstallRequest()
artifacts foreach request.addArtifact
system.install(session, request)
}
// TODO - Share this with non-local repository code, since it's MOSTLY the same.
protected def getPublicationTime(mrid: ModuleRevisionId): Option[Long] = {
val metadataRequest = new AetherMetadataRequest()
metadataRequest.setMetadata(
new DefaultMetadata(
mrid.getOrganisation,
mrid.getName,
mrid.getRevision,
MavenRepositoryResolver.MAVEN_METADATA_XML,
Metadata.Nature.RELEASE_OR_SNAPSHOT))
val metadataResultOpt =
try system.resolveMetadata(session, java.util.Arrays.asList(metadataRequest)).asScala.headOption
catch {
case e: org.eclipse.aether.resolution.ArtifactResolutionException => None
}
try metadataResultOpt match {
case Some(md) if md.isResolved =>
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader
import org.codehaus.plexus.util.ReaderFactory
val readMetadata = {
val reader = ReaderFactory.newXmlReader(md.getMetadata.getFile)
try new MetadataXpp3Reader().read(reader, false)
finally reader.close()
}
val timestampOpt =
for {
v <- Option(readMetadata.getVersioning)
sp <- Option(v.getSnapshot)
ts <- Option(sp.getTimestamp)
t <- MavenRepositoryResolver.parseTimeString(ts)
} yield t
val lastUpdatedOpt =
for {
v <- Option(readMetadata.getVersioning)
lu <- Option(v.getLastUpdated)
d <- MavenRepositoryResolver.parseTimeString(lu)
} yield d
// TODO - Only look at timestamp *IF* the version is for a snapshot.
timestampOpt orElse lastUpdatedOpt
case _ => None
}
}
override def toString = s"${repo.name}: ${repo.root}"
}
/** An exception we can throw if we encounter issues. */
class MavenResolutionException(msg: String) extends RuntimeException(msg) {}
abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends AbstractResolver {
abstract class MavenRepositoryResolver(settings: IvySettings) extends AbstractResolver {
/** Our instance of the aether repository system. */
protected val system: RepositorySystem
@ -237,7 +88,7 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
// Handles appending licenses to the module descriptor fromthe pom.
private def addLicenseInfo(md: DefaultModuleDescriptor, map: java.util.Map[String, AnyRef]) = {
val count = map.get(SbtExtraProperties.LICENSE_COUNT_KEY) match {
val count = map.get(SbtPomExtraProperties.LICENSE_COUNT_KEY) match {
case null => 0
case x: java.lang.Integer => x.intValue
case x: String => x.toInt
@ -245,8 +96,8 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
}
for {
i <- 0 until count
name <- Option(map.get(SbtExtraProperties.makeLicenseName(i))).map(_.toString)
url <- Option(map.get(SbtExtraProperties.makeLicenseUrl(i))).map(_.toString)
name <- Option(map.get(SbtPomExtraProperties.makeLicenseName(i))).map(_.toString)
url <- Option(map.get(SbtPomExtraProperties.makeLicenseUrl(i))).map(_.toString)
} md.addLicense(new License(name, url))
}
@ -294,7 +145,7 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
// Here we rip out license info.
addLicenseInfo(md, result.getProperties)
md.addExtraInfo(SbtExtraProperties.MAVEN_PACKAGING_KEY, packaging)
md.addExtraInfo(SbtPomExtraProperties.MAVEN_PACKAGING_KEY, packaging)
Message.debug(s"Setting publication date to ${new Date(lastModifiedTime)}")
// TODO - Figure out the differences between these items.
md.setPublicationDate(new Date(lastModifiedTime))
@ -344,10 +195,10 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
def getArtifactProperties(dd: ModuleRevisionId): java.util.Map[String, String] = {
val m = new java.util.HashMap[String, String]
Option(dd.getExtraAttribute(PomExtraDependencyAttributes.ScalaVersionKey)) foreach { sv =>
m.put(SbtExtraProperties.POM_SCALA_VERSION, sv)
m.put(SbtPomExtraProperties.POM_SCALA_VERSION, sv)
}
getSbtVersion(dd) foreach { sv =>
m.put(SbtExtraProperties.POM_SBT_VERSION, sv)
m.put(SbtPomExtraProperties.POM_SBT_VERSION, sv)
}
m
}
@ -439,11 +290,6 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
/** Adds the dependency mediators required based on the managed dependency instances from this pom. */
def addManagedDependenciesFromAether(result: AetherDescriptorResult, md: DefaultModuleDescriptor) {
for (d <- result.getManagedDependencies.asScala) {
if (d.getArtifact.getArtifactId == "stringtemplate") {
Message.warn(s"Found managed stringtemplate in $md !")
}
md.addDependencyDescriptorMediator(
ModuleId.newInstance(d.getArtifact.getGroupId, d.getArtifact.getArtifactId),
ExactPatternMatcher.INSTANCE,
@ -513,12 +359,7 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
// TOOD - We may need to fix the configuration mappings here.
dd.addDependencyArtifact(optionalizedScope, depArtifact)
}
// TODO - is toSystem call correct?
md.addDependency(dd)
if (d.getArtifact.getArtifactId == "stringtemplate") {
Message.warn(s"Found stringtemplate dependency! $dd")
}
}
}
@ -529,8 +370,8 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
}
private def getPackagingFromPomProperties(props: java.util.Map[String, AnyRef]): String =
if (props.containsKey(SbtExtraProperties.MAVEN_PACKAGING_KEY))
props.get(SbtExtraProperties.MAVEN_PACKAGING_KEY).toString
if (props.containsKey(SbtPomExtraProperties.MAVEN_PACKAGING_KEY))
props.get(SbtPomExtraProperties.MAVEN_PACKAGING_KEY).toString
else "jar"
override def download(artifacts: Array[Artifact], dopts: DownloadOptions): DownloadReport = {
@ -671,7 +512,8 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
override def equals(a: Any): Boolean =
a match {
case x: AbstractMavenRepositoryResolver => x.getName == getName
case _ => false
case x: MavenRepositoryResolver => x.getName == getName
case _ => false
}
override def hashCode: Int = getName.hashCode
}

View File

@ -0,0 +1,62 @@
package sbt.mavenint
import java.io.File
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.repository.url.URLResource
import org.apache.ivy.util.Message
import org.apache.ivy.util.url.URLHandlerRegistry
import org.apache.maven.repository.internal.{ MavenRepositorySystemUtils, SbtArtifactDescriptorReader, SnapshotMetadataGeneratorFactory, VersionsMetadataGeneratorFactory }
import org.eclipse.aether.{ RepositorySystem, RepositorySystemSession }
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
import org.eclipse.aether.impl.{ ArtifactDescriptorReader, DefaultServiceLocator, MetadataGeneratorFactory }
import org.eclipse.aether.repository.{ LocalRepository, RemoteRepository }
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory
import org.eclipse.aether.spi.connector.transport.{ TransporterFactory, _ }
/** Helper methods for dealing with starting up Aether. */
object MavenRepositorySystemFactory {
def newRepositorySystemImpl: RepositorySystem = {
// For now we just log Aether instantiation issues. These should probably cause fatal errors.
val locator = MavenRepositorySystemUtils.newServiceLocator()
locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler {
override def serviceCreationFailed(tpe: Class[_], impl: Class[_], exception: Throwable): Unit = {
Message.error(s"Failed to create $tpe, of class $impl")
}
})
// Here we register the Ivy <-> Aether transport bridge
locator.addService(classOf[TransporterFactory], classOf[MyTransportFactory])
// This connects the download mechanism to our transports. Why is it needed? no clue.
locator.addService(classOf[RepositoryConnectorFactory], classOf[BasicRepositoryConnectorFactory])
// Plugins cause issues here, as their layout is super odd. Here we inject a new plugin layout
locator.addService(classOf[RepositoryLayoutFactory], classOf[SbtPluginLayoutFactory])
// Here we add the metadata services so aether will automatically add maven-metadata.xml files.
locator.addService(classOf[MetadataGeneratorFactory], classOf[SnapshotMetadataGeneratorFactory])
locator.addService(classOf[MetadataGeneratorFactory], classOf[VersionsMetadataGeneratorFactory])
// Add our hook for parsing pom.xml files.
locator.setService(classOf[ArtifactDescriptorReader], classOf[SbtArtifactDescriptorReader])
// Finally, use the DI to create our repository system.
locator.getService(classOf[RepositorySystem])
}
def newSessionImpl(system: RepositorySystem, localRepoDir: File): RepositorySystemSession = {
val session = MavenRepositorySystemUtils.newSession()
val localRepo = new LocalRepository(localRepoDir)
session setLocalRepositoryManager (system.newLocalRepositoryManager(session, localRepo))
// Here we set a descriptor policy that FORCES the pom.xml to exist, otherwise Ivy's resolution
// algorithm freaks out. What we could do is also do the ivy lame-thing of checking for a JAR
// instead of a pom.xml, but let's see if this is actually a problem in practice.
val descriptorPolicy = new org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy(
/* ignoreMissing */ false, /* ignoreInvalid. */ true)
session.setArtifactDescriptorPolicy(descriptorPolicy)
session
}
def defaultLocalRepo: java.io.File = {
new java.io.File(s"${sys.props("user.home")}/.m2/repository")
}
}

View File

@ -0,0 +1,4 @@
package sbt.mavenint
/** An exception we can throw if we encounter issues. */
class MavenResolutionException(msg: String) extends RuntimeException(msg) {}

View File

@ -0,0 +1,16 @@
package sbt.mavenint
import org.eclipse.aether.RepositorySystemSession
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.spi.connector.transport.{ Transporter, TransporterFactory }
/** Override aether's default transport with Ivy-ones. */
class MyTransportFactory extends TransporterFactory {
override def newInstance(session: RepositorySystemSession, repository: RemoteRepository): Transporter =
repository.getProtocol match {
case "http" | "https" => new HttpTransport(repository)
case "file" => new FileTransport(repository)
case other => throw new IllegalArgumentException(s"Unsupported transport protocol: $other")
}
override def getPriority: Float = 1.0f
}

View File

@ -1,15 +1,14 @@
package org.apache.maven.repository.internal
package sbt.mavenint
import org.apache.ivy.util.Message
import org.eclipse.aether.spi.connector.layout.{ RepositoryLayout, RepositoryLayoutFactory }
import org.eclipse.aether.RepositorySystemSession
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.transfer.NoRepositoryLayoutException
import org.eclipse.aether.metadata.Metadata
import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum
import org.eclipse.aether.artifact.Artifact
import java.net.URI
import sbt.SbtExtraProperties
import org.eclipse.aether.RepositorySystemSession
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.metadata.Metadata
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum
import org.eclipse.aether.spi.connector.layout.{ RepositoryLayout, RepositoryLayoutFactory }
import org.eclipse.aether.transfer.NoRepositoryLayoutException
import scala.util.matching.Regex
@ -32,15 +31,13 @@ object SbtRepositoryLayout extends RepositoryLayout {
// get location is ALMOST the same for Metadata + artifact... but subtle differences are important.
def getLocation(artifact: Artifact, upload: Boolean): URI = {
import collection.JavaConverters._
val sbtVersion = Option(artifact.getProperties.get(SbtExtraProperties.POM_SBT_VERSION))
val scalaVersion = Option(artifact.getProperties.get(SbtExtraProperties.POM_SCALA_VERSION))
val sbtVersion = Option(artifact.getProperties.get(SbtPomExtraProperties.POM_SBT_VERSION))
val scalaVersion = Option(artifact.getProperties.get(SbtPomExtraProperties.POM_SCALA_VERSION))
val path = new StringBuilder(128)
path.append(artifact.getGroupId.replace('.', '/')).append('/')
(sbtVersion zip scalaVersion).headOption match {
case Some((sbt, scala)) =>
if (artifact.getArtifactId contains "_sbt_") {
// TODO - Write this handler.
val SbtNameVersionSplit(name, sbt2) = artifact.getArtifactId
path.append(name).append('_').append(scala).append('_').append(sbt).append('/')
} else path.append(artifact.getArtifactId).append('_').append(scala).append('_').append(sbt).append('/')
@ -69,8 +66,8 @@ object SbtRepositoryLayout extends RepositoryLayout {
val SbtNameVersionSplit = new Regex("(.*)_sbt_(.*)")
def getLocation(metadata: Metadata, upload: Boolean): URI = {
val sbtVersion = Option(metadata.getProperties.get(SbtExtraProperties.POM_SBT_VERSION))
val scalaVersion = Option(metadata.getProperties.get(SbtExtraProperties.POM_SCALA_VERSION))
val sbtVersion = Option(metadata.getProperties.get(SbtPomExtraProperties.POM_SBT_VERSION))
val scalaVersion = Option(metadata.getProperties.get(SbtPomExtraProperties.POM_SCALA_VERSION))
val path = new StringBuilder(128)
path.append(metadata.getGroupId.replace('.', '/')).append('/')
(sbtVersion zip scalaVersion).headOption match {
@ -78,7 +75,6 @@ object SbtRepositoryLayout extends RepositoryLayout {
if (metadata.getArtifactId contains "_sbt_") {
val SbtNameVersionSplit(name, sbt2) = metadata.getArtifactId
path.append(name).append('_').append(scala).append('_').append(sbt).append('/')
// TODO - Write this handler.
} else path.append(metadata.getArtifactId).append('_').append(scala).append('_').append(sbt).append('/')
case None =>
// TODO - Should we automatically append the _<scala-verison> here? Proabbly not for now.

View File

@ -1,9 +1,8 @@
package sbt
import java.io.FileInputStream
import org.apache.maven.repository.internal.PomExtraDependencyAttributes
import org.specs2._
import sbt.mavenint.PomExtraDependencyAttributes
class MavenResolutionSpec extends BaseIvySpecification {
def is = args(sequential = true) ^ s2""".stripMargin