From 0270ac078ff23adf9b1edc6d5e9ffd52ff9059d1 Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Wed, 16 Nov 2011 14:04:16 +0530 Subject: [PATCH] Support for enhanced cross build suffix in dependencies. Closes #267 Overloading `%%` for library dependency to allow using a library built with an alternative version of Scala that is different from the Scala version used in the current build (but hopefully binary compatible). This is useful in cases, where the binary build of a dependency with the exact Scala version isn't yet available but an otherwise binary compatible build (maybe with a previous Scala release) is available. --- ivy/DependencyBuilders.scala | 15 ++++++++------- ivy/Ivy.scala | 2 +- ivy/IvyActions.scala | 4 ++-- ivy/IvyInterface.scala | 12 ++++++------ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/ivy/DependencyBuilders.scala b/ivy/DependencyBuilders.scala index 00168d7c1..68a30b122 100644 --- a/ivy/DependencyBuilders.scala +++ b/ivy/DependencyBuilders.scala @@ -4,7 +4,7 @@ package sbt package impl - import StringUtilities.{appendable,nonEmpty} +import StringUtilities.nonEmpty trait DependencyBuilders { @@ -27,20 +27,21 @@ trait DependencyBuilders final class GroupID private[sbt] (groupID: String) { - def % (artifactID: String) = groupArtifact(artifactID, false) - def %% (artifactID: String) = groupArtifact(artifactID, true) - private def groupArtifact(artifactID: String, cross: Boolean) = + def % (artifactID: String) = groupArtifact(artifactID, None) + def %% (artifactID: String, crossVersion: String => String = identity) = groupArtifact(artifactID, Some(crossVersion)) + def %% (artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, Some(Map(alternatives: _*) orElse { case s => s })) + private def groupArtifact(artifactID: String, cross: Option[String => String]) = { nonEmpty(artifactID, "Artifact ID") new GroupArtifactID(groupID, artifactID, cross) } } -final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: Boolean) -{ +final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: Option[String => String]) +{ def % (revision: String): ModuleID = { nonEmpty(revision, "Revision") - ModuleID(groupID, artifactID, revision).cross(crossVersion) + ModuleID(groupID, artifactID, revision).cross(!crossVersion.isEmpty, crossVersion.getOrElse(identity)) } } final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID) diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala index 3cac60e0b..19252fb28 100644 --- a/ivy/Ivy.scala +++ b/ivy/Ivy.scala @@ -314,7 +314,7 @@ private object IvySbt as.map(art => substituteCross(art, cross)) def substituteCross(m: ModuleID, cross: String): ModuleID = if(m.crossVersion) - m.copy(name = crossName(m.name, cross), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross)) + m.copy(name = crossName(m.name, m.crossVersionRemap(cross)), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross)) else m diff --git a/ivy/IvyActions.scala b/ivy/IvyActions.scala index ff53041ef..07b2740d1 100644 --- a/ivy/IvyActions.scala +++ b/ivy/IvyActions.scala @@ -205,7 +205,7 @@ object IvyActions report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy(_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) } private[this] def restrictedCopy(m: ModuleID, confs: Boolean) = - ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None) + ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, crossVersionRemap = m.crossVersionRemap, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None) private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) = { val resolveOptions = new ResolveOptions @@ -268,4 +268,4 @@ object IvyActions } } -final class ResolveException(val messages: Seq[String], val failed: Seq[ModuleID]) extends RuntimeException(messages.mkString("\n")) \ No newline at end of file +final class ResolveException(val messages: Seq[String], val failed: Seq[ModuleID]) extends RuntimeException(messages.mkString("\n")) diff --git a/ivy/IvyInterface.scala b/ivy/IvyInterface.scala index 9f5b0c630..7bf72b0dc 100644 --- a/ivy/IvyInterface.scala +++ b/ivy/IvyInterface.scala @@ -9,14 +9,14 @@ import scala.xml.NodeSeq import org.apache.ivy.plugins.resolver.{DependencyResolver, IBiblioResolver} import org.apache.ivy.util.url.CredentialsStore -final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: Boolean = false) +final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: Boolean = false, crossVersionRemap: String => String = identity) { override def toString = organization + ":" + name + ":" + revision + (configurations match { case Some(s) => ":" + s; case None => "" }) + (if(extraAttributes.isEmpty) "" else " " + extraString) def extraString = extraAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")") - def cross(v: Boolean) = copy(crossVersion = v) + def cross(v: Boolean, verRemap: String => String = identity) = copy(crossVersion = v, crossVersionRemap = verRemap) // () required for chaining def notTransitive() = intransitive() def intransitive() = copy(isTransitive = false) @@ -282,7 +282,7 @@ object Resolver def resolveAll(patterns: Seq[String]) = patterns.map(p => resolvePattern(base, p)) Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible) } - private[sbt] def resolvePattern(base: String, pattern: String): String = + private[sbt] def resolvePattern(base: String, pattern: String): String = { val normBase = base.replace('\\', '/') if(normBase.endsWith("/") || pattern.startsWith("/")) normBase + pattern else normBase + "/" + pattern @@ -423,14 +423,14 @@ object Artifact { import artifact._ val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c } - val base = if(module.crossVersion) IvySbt.crossName(artifact.name, scalaVersion) else artifact.name + val base = if(module.crossVersion) IvySbt.crossName(artifact.name, module.crossVersionRemap(scalaVersion)) else artifact.name base + "-" + module.revision + classifierStr + "." + artifact.extension } def cross(enable: Boolean, scalaVersion: String): String = if(enable) "_" + scalaVersion else "" val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs) val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType) - def classifierConf(classifier: String): Configuration = classifierConfMap.getOrElse(classifier, Optional) + def classifierConf(classifier: String): Configuration = classifierConfMap.getOrElse(classifier, Optional) def classifierType(classifier: String): String = classifierTypeMap.getOrElse(classifier, DefaultType) def classified(name: String, classifier: String): Artifact = Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), classifierConf(classifier) :: Nil, None) @@ -440,4 +440,4 @@ object ModuleConfiguration { def apply(org: String, resolver: Resolver): ModuleConfiguration = apply(org, "*", "*", resolver) def apply(org: String, name: String, resolver: Resolver): ModuleConfiguration = ModuleConfiguration(org, name, "*", resolver) -} \ No newline at end of file +}