package sbt
import org.apache.ivy.{core, plugins, util}
import core.module.id.ModuleRevisionId
import core.module.descriptor.{DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor}
import core.module.descriptor.{DefaultDependencyDescriptor, DependencyDescriptor}
import plugins.parser.{m2, ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings}
import m2.{PomModuleDescriptorBuilder, PomModuleDescriptorParser}
import plugins.repository.Resource
import plugins.namespace.NamespaceTransformer
import util.extendable.ExtendableItem
import java.io.{File, InputStream}
import java.net.URL
import java.util.regex.Pattern
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser
{
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) =
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, validate))
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, res: Resource, validate: Boolean) =
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, res, validate))
override def toIvyFile(is: InputStream, res: Resource, destFile: File, md: ModuleDescriptor) = delegate.toIvyFile(is, res, destFile, md)
override def accept(res: Resource) = delegate.accept(res)
override def getType() = delegate.getType()
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) = delegate.getMetadataArtifact(mrid, res)
}
object CustomPomParser
{
val SbtVersionKey = "sbtVersion"
val ScalaVersionKey = "scalaVersion"
val ExtraAttributesKey = "extraDependencyAttributes"
val JarPackagings = Set("eclipse-plugin", "hk2-jar")
val default = new CustomPomParser(PomModuleDescriptorParser.getInstance, defaultTransform)
lazy val registerDefault: Unit = ModuleDescriptorParserRegistry.getInstance.addParser(default)
def defaultTransform(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
{
import collection.JavaConverters._
val properties = PomModuleDescriptorBuilder.extractPomProperties(md.getExtraInfo).asInstanceOf[java.util.Map[String,String]].asScala.toMap
val filtered = shouldBeUnqualified(properties)
val extraDepAttributes = getDependencyExtra(filtered)
val convertArtifacts = artifactExtIncorrect(md)
val unqualify = (filtered - ExtraAttributesKey) map { case (k,v) => ("e:" + k, v) }
if(unqualify.isEmpty && extraDepAttributes.isEmpty && !convertArtifacts)
md
else
addExtra(unqualify, extraDepAttributes, parser, md)
}
private[this] def artifactExtIncorrect(md: ModuleDescriptor): Boolean =
md.getConfigurations.exists(conf => md.getArtifacts(conf.getName).exists(art => JarPackagings(art.getExt)))
private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] =
m.filter { case (SbtVersionKey | ScalaVersionKey | ExtraAttributesKey,_) => true; case _ => false }
private[this] def condAddExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
if(properties.isEmpty) id else addExtra(properties, id)
private[this] def addExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
{
import collection.JavaConverters._
val oldExtra = qualifiedExtra(id)
val newExtra = (oldExtra ++ properties).asJava
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, newExtra)
}
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
}
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 writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
s.flatMap { dd =>
val revId = dd.getDependencyRevisionId
if(filterCustomExtra(revId, include=true).isEmpty)
Nil
else
revId.encodeToString :: Nil
}
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
LinesP.split(s).map(_.trim).filter(!_.isEmpty).map(ModuleRevisionId.decode)
private[this] val LinesP = Pattern.compile("(?m)^")
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
def simplify(id: ModuleRevisionId): ModuleRevisionId =
{
import collection.JavaConverters._
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include=false).asJava)
}
private[this] def addExtra(dep: DependencyDescriptor, extra: Map[ModuleRevisionId, Map[String, String]]): DependencyDescriptor =
{
val extras = if(extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId)
extras match {
case None => dep
case Some(extraAttrs) => transform(dep, revId => addExtra(extraAttrs, revId))
}
}
private[this] def transform(dep: DependencyDescriptor, f: ModuleRevisionId => ModuleRevisionId): DependencyDescriptor =
DefaultDependencyDescriptor.transformInstance(dep, namespaceTransformer(dep.getDependencyRevisionId, f), false)
private[this] def extraTransformer(txId: ModuleRevisionId, extra: Map[String, String]): NamespaceTransformer =
namespaceTransformer(txId, revId => addExtra(extra, revId) )
private[this] def namespaceTransformer(txId: ModuleRevisionId, f: ModuleRevisionId => ModuleRevisionId): NamespaceTransformer =
new NamespaceTransformer {
def transform(revId: ModuleRevisionId): ModuleRevisionId = if(revId == txId) f(revId) else revId
def isIdentity = false
}
import collection.JavaConverters._
def addExtra(properties: Map[String, String], dependencyExtra: Map[ModuleRevisionId, Map[String,String]], parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
{
val dmd = new DefaultModuleDescriptor(parser, md.getResource)
val mrid = addExtra(properties, md.getModuleRevisionId)
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
dmd.setModuleRevisionId(mrid)
dmd.setResolvedModuleRevisionId(resolvedMrid)
dmd.setDefault(md.isDefault)
dmd.setHomePage(md.getHomePage)
dmd.setDescription(md.getDescription)
dmd.setLastModified(md.getLastModified)
dmd.setStatus(md.getStatus())
dmd.setPublicationDate(md.getPublicationDate())
dmd.setResolvedPublicationDate(md.getResolvedPublicationDate())
for(l <- md.getLicenses) dmd.addLicense(l)
for( (key,value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String,String]].asScala ) dmd.addExtraInfo(key, value)
for( (key, value) <- md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].asScala ) dmd.addExtraAttributeNamespace(key, value)
IvySbt.addExtraNamespace(dmd)
for( dd <- md.getDependencies ) dmd.addDependency(addExtra(dd, dependencyExtra))
for( ed <- md.getInheritedDescriptors) dmd.addInheritedDescriptor( new DefaultExtendsDescriptor( mrid, resolvedMrid, ed.getLocation, ed.getExtendsTypes) )
for( conf <- md.getConfigurations) {
dmd.addConfiguration(conf)
for(art <- md.getArtifacts(conf.getName)) {
val ext = art.getExt
val newExt = if( JarPackagings(ext) ) "jar" else ext
val nart = new DefaultArtifact(mrid, art.getPublicationDate, art.getName, art.getType, newExt, art.getUrl, art.getQualifiedExtraAttributes)
dmd.addArtifact(conf.getName, nart)
}
}
dmd
}
}