mirror of https://github.com/sbt/sbt.git
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:
parent
cacc454af5
commit
42424b4cdb
|
|
@ -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";
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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}"
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package sbt.mavenint
|
||||
|
||||
/** An exception we can throw if we encounter issues. */
|
||||
class MavenResolutionException(msg: String) extends RuntimeException(msg) {}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue