Migrate pom extra attributes out of CustomPomParser for deprecation.

This commit is contained in:
Josh Suereth 2015-01-09 14:04:24 -05:00
parent 651f92e40c
commit 038fb98c7f
7 changed files with 101 additions and 47 deletions

View File

@ -29,7 +29,7 @@ import org.eclipse.aether.resolution.{
import org.eclipse.aether.deployment.{ DeployRequest => AetherDeployRequest }
import org.eclipse.aether.installation.{ InstallRequest => AetherInstallRequest }
import org.apache.ivy.core.cache.{ ModuleDescriptorWriter, ArtifactOrigin }
import sbt.{ CustomPomParser, MavenCache, MavenRepository }
import sbt.{ MavenCache, MavenRepository }
import scala.collection.JavaConverters._
object MavenRepositoryResolver {
@ -336,11 +336,11 @@ abstract class AbstractMavenRepositoryResolver(settings: IvySettings) extends Ab
}
def getSbtVersion(dd: ModuleRevisionId): Option[String] =
Option(dd.getExtraAttribute(CustomPomParser.SbtVersionKey))
Option(dd.getExtraAttribute(PomExtraDependencyAttributes.SbtVersionKey))
def getArtifactProperties(dd: ModuleRevisionId): java.util.Map[String, String] = {
val m = new java.util.HashMap[String, String]
Option(dd.getExtraAttribute(CustomPomParser.ScalaVersionKey)) foreach { sv =>
Option(dd.getExtraAttribute(PomExtraDependencyAttributes.ScalaVersionKey)) foreach { sv =>
m.put(SbtExtraProperties.POM_SCALA_VERSION, sv)
}
getSbtVersion(dd) foreach { sv =>

View File

@ -1,16 +1,29 @@
package org.apache.maven.repository.internal
import java.util.Properties
import java.util.regex.Pattern
import org.apache.ivy.core.module.descriptor.DependencyDescriptor
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.util.extendable.ExtendableItem
import sbt.CustomPomParser
/**
* This class contains all the logic for dealing with the extra attributes in pom files relating to extra attributes
* on dependency declarations.
*
* Specifically, if we have a dependency on an sbt plugin, there are two properties that need to propogate:
* - `sbtVersion`
* - `scalaVersion`
*
* These need to exist on the *dependency declaration*. Maven/Aether has no way to inject these into
* the <dependency> section of pom files, so we use Ivy's Extra attribute hackery to inject a lookup table
* of extra attributes by dependency id into POM files and later we read these back.
*/
object PomExtraDependencyAttributes {
// TODO - Move custom pom parser extra attribtues code into this class, rather than relying on
// custom pom parser (so we can deprecate it completely).
import CustomPomParser.{ ExtraAttributesKey, simplify, filterCustomExtra, readDependencyExtra }
val ExtraAttributesKey = "extraDependencyAttributes"
val SbtVersionKey = "sbtVersion"
val ScalaVersionKey = "scalaVersion"
/**
* Reads the extra dependency attributes out of a maven property.
* @param props The properties from an Aether resolution.
@ -44,4 +57,55 @@ object PomExtraDependencyAttributes {
case None =>
}
}
/**
* Reads the extra dependency information out of Ivy's notion of POM properties and returns
* the map of ID -> Extra Properties.
*/
def getDependencyExtra(m: Map[String, String]): Map[ModuleRevisionId, Map[String, String]] =
(m get ExtraAttributesKey) match {
case None => Map.empty
case Some(str) =>
def processDep(m: ModuleRevisionId) = (simplify(m), filterCustomExtra(m, include = true))
readDependencyExtra(str).map(processDep).toMap
}
def qualifiedExtra(item: ExtendableItem): Map[String, String] = {
import collection.JavaConverters._
item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap
}
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
// Reduces the id to exclude custom extra attributes
// 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._
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include = false).asJava)
}
/** parses the sequence of dependencies with extra attribute information, with one dependency per line */
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
LinesP.split(s).map(_.trim).filter(!_.isEmpty).map(ModuleRevisionId.decode)
private[this] val LinesP = Pattern.compile("(?m)^")
/**
* Creates the "extra" property values for DependencyDescriptors that can be written into a maven pom
* so we don't loose the information.
* @param s
* @return
*/
def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
s.flatMap { dd =>
val revId = dd.getDependencyRevisionId
if (filterCustomExtra(revId, include = true).isEmpty)
Nil
else
revId.encodeToString :: Nil
}
}

View File

@ -3,15 +3,18 @@ package org.apache.maven.repository.internal;
/**
* Created by jsuereth on 12/20/14.
* Extra properties we dump from Aether into the properties list.
*/
public class SbtExtraProperties {
public static final String MAVEN_PACKAGING_KEY = "sbt.pom.packaging";
public static final String SCALA_VERSION_KEY = "sbt.pom.scalaversion";
public static final String SBT_VERSION_KEY = "sbt.pom.sbtversion";
public static final String POM_INFO_KEY_PREFIX = "info.";
public static final String POM_SCALA_VERSION = "scalaVersion";
public static final String POM_SBT_VERSION = "sbtVersion";
public static final String POM_API_KEY = "info.apiURL";
public static final String LICENSE_COUNT_KEY = "license.count";

View File

@ -13,6 +13,8 @@ import java.io.{ File, InputStream }
import java.net.URL
import java.util.regex.Pattern
import org.apache.maven.repository.internal.{ SbtExtraProperties, PomExtraDependencyAttributes }
@deprecated("0.13.8", "We now use an Aether-based pom parser.")
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser {
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) =
@ -34,15 +36,16 @@ 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 = "info."
val ApiURLKey = "info.apiURL"
val InfoKeyPrefix = SbtExtraProperties.POM_INFO_KEY_PREFIX
val ApiURLKey = SbtExtraProperties.POM_API_KEY
val SbtVersionKey = "sbtVersion"
val ScalaVersionKey = "scalaVersion"
val ExtraAttributesKey = "extraDependencyAttributes"
val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey
val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey
val ExtraAttributesKey = PomExtraDependencyAttributes.ExtraAttributesKey
private[this] val unqualifiedKeys = Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
// packagings that should be jars, but that Ivy doesn't handle as jars
// TODO - move this elsewhere.
val JarPackagings = Set("eclipse-plugin", "hk2-jar", "orbit", "scala-jar")
val default = new CustomPomParser(PomModuleDescriptorParser.getInstance, defaultTransform)
@ -125,46 +128,24 @@ object CustomPomParser {
}
private[this] def getDependencyExtra(m: Map[String, String]): Map[ModuleRevisionId, Map[String, String]] =
(m get ExtraAttributesKey) match {
case None => Map.empty
case Some(str) =>
def processDep(m: ModuleRevisionId) = (simplify(m), filterCustomExtra(m, include = true))
readDependencyExtra(str).map(processDep).toMap
}
PomExtraDependencyAttributes.getDependencyExtra(m)
def qualifiedExtra(item: ExtendableItem): Map[String, String] =
{
import collection.JavaConverters._
item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap
}
def qualifiedExtra(item: ExtendableItem): Map[String, String] = PomExtraDependencyAttributes.qualifiedExtra(item)
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
s.flatMap { dd =>
val revId = dd.getDependencyRevisionId
if (filterCustomExtra(revId, include = true).isEmpty)
Nil
else
revId.encodeToString :: Nil
}
PomExtraDependencyAttributes.writeDependencyExtra(s)
// parses the sequence of dependencies with extra attribute information, with one dependency per line
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
LinesP.split(s).map(_.trim).filter(!_.isEmpty).map(ModuleRevisionId.decode)
def readDependencyExtra(s: String): Seq[ModuleRevisionId] = PomExtraDependencyAttributes.readDependencyExtra(s)
private[this] val LinesP = Pattern.compile("(?m)^")
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
def qualifiedIsExtra(k: String): Boolean = PomExtraDependencyAttributes.qualifiedIsExtra(k)
// Reduces the id to exclude custom extra attributes
// 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._
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include = false).asJava)
}
def simplify(id: ModuleRevisionId): ModuleRevisionId = PomExtraDependencyAttributes.simplify(id)
private[this] def addExtra(dep: DependencyDescriptor, extra: Map[ModuleRevisionId, Map[String, String]]): DependencyDescriptor =
{

View File

@ -8,6 +8,9 @@
package sbt
import java.io.File
import org.apache.maven.repository.internal.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
import scala.xml.{ Elem, Node => XNode, NodeSeq, PrettyPrinter, PrefixedAttribute }
@ -119,12 +122,12 @@ class MakePom(val log: Logger) {
def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq =
{
val extra = IvySbt.getExtraAttributes(module)
val depExtra = CustomPomParser.writeDependencyExtra(dependencies).mkString("\n")
val allExtra = if (depExtra.isEmpty) extra else extra.updated(CustomPomParser.ExtraAttributesKey, depExtra)
val depExtra = PomExtraDependencyAttributes.writeDependencyExtra(dependencies).mkString("\n")
val allExtra = if (depExtra.isEmpty) extra else extra.updated(PomExtraDependencyAttributes.ExtraAttributesKey, depExtra)
if (allExtra.isEmpty) NodeSeq.Empty else makeProperties(allExtra)
}
def makeProperties(extra: Map[String, String]): NodeSeq = {
def _extraAttributes(k: String) = if (k == CustomPomParser.ExtraAttributesKey) xmlSpacePreserve else scala.xml.Null
def _extraAttributes(k: String) = if (k == PomExtraDependencyAttributes.ExtraAttributesKey) xmlSpacePreserve else scala.xml.Null
<properties> {
for ((key, value) <- extra) yield (<x>{ value }</x>).copy(label = key, attributes = _extraAttributes(key))
} </properties>

View File

@ -5,6 +5,8 @@ package sbt
import java.net.URL
import org.apache.maven.repository.internal.SbtExtraProperties
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled) {
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(CustomPomParser.InfoKeyPrefix))
def extraDependencyAttributes: Map[String, String] = extraAttributes.filterKeys(!_.startsWith(SbtExtraProperties.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

@ -2,6 +2,7 @@ package sbt
import java.io.FileInputStream
import org.apache.maven.repository.internal.PomExtraDependencyAttributes
import org.specs2._
class MavenResolutionSpec extends BaseIvySpecification {
@ -37,11 +38,11 @@ class MavenResolutionSpec extends BaseIvySpecification {
def scalaContinuationPlugin = ModuleID("org.scala-lang.plugins", "continuations", "2.8.1", Some("plugin->default(compile)"))
def sbtPlugin =
ModuleID("com.github.mpeltonen", "sbt-idea", "1.6.0", Some("compile")).
extra(CustomPomParser.SbtVersionKey -> "0.13", CustomPomParser.ScalaVersionKey -> "2.10").
extra(PomExtraDependencyAttributes.SbtVersionKey -> "0.13", PomExtraDependencyAttributes.ScalaVersionKey -> "2.10").
copy(crossVersion = CrossVersion.Disabled)
def oldSbtPlugin =
ModuleID("com.github.mpeltonen", "sbt-idea", "1.6.0", Some("compile")).
extra(CustomPomParser.SbtVersionKey -> "0.12", CustomPomParser.ScalaVersionKey -> "2.9.2").
extra(PomExtraDependencyAttributes.SbtVersionKey -> "0.12", PomExtraDependencyAttributes.ScalaVersionKey -> "2.9.2").
copy(crossVersion = CrossVersion.Disabled)
def majorConflictLib = ModuleID("com.joestelmach", "natty", "0.3", Some("compile"))
// TODO - This snapshot and resolver should be something we own/control so it doesn't disappear on us.