From b0e86898d13341cb696757fac20156a668e23342 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Tue, 14 Feb 2012 21:59:12 -0500 Subject: [PATCH] support for dependency overrides --- ivy/Ivy.scala | 13 ++++++++++++- ivy/IvyConfigurations.scala | 2 +- main/Defaults.scala | 5 +++-- main/Keys.scala | 1 + main/actions/CacheIvy.scala | 5 +++-- .../dependency-management/override/build.sbt | 8 ++++++++ .../sbt-test/dependency-management/override/test | 4 ++++ 7 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 sbt/src/sbt-test/dependency-management/override/build.sbt create mode 100644 sbt/src/sbt-test/dependency-management/override/test diff --git a/ivy/Ivy.scala b/ivy/Ivy.scala index a9a5cf8f8..03b434ac4 100644 --- a/ivy/Ivy.scala +++ b/ivy/Ivy.scala @@ -15,6 +15,7 @@ import core.{IvyPatternHelper, LogOptions} import core.cache.{CacheMetadataOptions, DefaultRepositoryCacheManager} import core.module.descriptor.{Artifact => IArtifact, DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact} import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor, License} +import core.module.descriptor.{OverrideDependencyDescriptorMediator} import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId} import core.resolve.{IvyNode, ResolveData} import core.settings.IvySettings @@ -142,6 +143,7 @@ final class IvySbt(val configuration: IvyConfiguration) val parser = IvySbt.parseIvyXML(ivy.getSettings, IvySbt.wrapped(module, ivyXML), moduleID, defaultConf.name, validate) IvySbt.addDependencies(moduleID, dependencies, parser) IvySbt.addMainArtifact(moduleID) + IvySbt.addOverrides(moduleID, overrides, ivy.getSettings.getMatcher(PatternMatcher.EXACT_OR_REGEXP)) (moduleID, parser.getDefaultConf) } private def newConfiguredModuleID(module: ModuleID, moduleInfo: ModuleInfo, configurations: Iterable[Configuration]) = @@ -308,7 +310,7 @@ private object IvySbt val sub = CrossVersion(scalaFullVersion, scalaBinaryVersion) m match { case ec: EmptyConfiguration => ec.copy(module = sub(ec.module)) - case ic: InlineConfiguration => ic.copy(module = sub(ic.module), dependencies = ic.dependencies map sub) + case ic: InlineConfiguration => ic.copy(module = sub(ic.module), dependencies = ic.dependencies map sub, overrides = ic.overrides map sub) case _ => m } } @@ -430,6 +432,15 @@ private object IvySbt moduleID.addDependency(dependencyDescriptor) } } + def addOverrides(moduleID: DefaultModuleDescriptor, overrides: Set[ModuleID], matcher: PatternMatcher): Unit = + overrides foreach addOverride(moduleID, matcher) + def addOverride(moduleID: DefaultModuleDescriptor, matcher: PatternMatcher)(overrideDef: ModuleID): Unit = + { + val overrideID = new ModuleId(overrideDef.organization, overrideDef.name) + val overrideWith = new OverrideDependencyDescriptorMediator(null, overrideDef.revision) + moduleID.addDependencyDescriptorMediator(overrideID, matcher, overrideWith) + } + /** This method is used to add inline artifacts to the provided module. */ def addArtifacts(moduleID: DefaultModuleDescriptor, artifacts: Iterable[Artifact]): Unit = for(art <- mapArtifacts(moduleID, artifacts.toSeq); c <- art.getConfigurations) diff --git a/ivy/IvyConfigurations.scala b/ivy/IvyConfigurations.scala index 97e6eb7c2..317d20c67 100644 --- a/ivy/IvyConfigurations.scala +++ b/ivy/IvyConfigurations.scala @@ -62,7 +62,7 @@ final case class PomConfiguration(file: File, ivyScala: Option[IvyScala], valida { def noScala = copy(ivyScala = None) } -final case class InlineConfiguration(module: ModuleID, moduleInfo: ModuleInfo, dependencies: Seq[ModuleID], ivyXML: NodeSeq = NodeSeq.Empty, configurations: Seq[Configuration] = Nil, defaultConfiguration: Option[Configuration] = None, ivyScala: Option[IvyScala] = None, validate: Boolean = false) extends ModuleSettings +final case class InlineConfiguration(module: ModuleID, moduleInfo: ModuleInfo, dependencies: Seq[ModuleID], overrides: Set[ModuleID] = Set.empty, ivyXML: NodeSeq = NodeSeq.Empty, configurations: Seq[Configuration] = Nil, defaultConfiguration: Option[Configuration] = None, ivyScala: Option[IvyScala] = None, validate: Boolean = false) extends ModuleSettings { def withConfigurations(configurations: Seq[Configuration]) = copy(configurations = configurations) def noScala = copy(ivyScala = None) diff --git a/main/Defaults.scala b/main/Defaults.scala index 7011ba2e9..dc9e86989 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -732,6 +732,7 @@ object Classpaths otherResolvers <<= publishTo(_.toList), projectResolver <<= projectResolverTask, projectDependencies <<= projectDependenciesTask, + dependencyOverrides in GlobalScope :== Set.empty, libraryDependencies in GlobalScope :== Nil, libraryDependencies <++= (autoScalaLibrary, sbtPlugin, scalaVersion) apply autoLibraryDependency, allDependencies <<= (projectDependencies,libraryDependencies,sbtPlugin,sbtDependency) map { (projDeps, libDeps, isPlugin, sbtDep) => @@ -819,8 +820,8 @@ object Classpaths new IvySbt(conf) } def moduleSettings0: Initialize[Task[ModuleSettings]] = - (projectID, allDependencies, ivyXML, ivyConfigurations, defaultConfiguration, ivyScala, ivyValidate, projectInfo) map { - (pid, deps, ivyXML, confs, defaultConf, ivyS, validate, pinfo) => new InlineConfiguration(pid, pinfo, deps, ivyXML, confs, defaultConf, ivyS, validate) + (projectID, allDependencies, dependencyOverrides, ivyXML, ivyConfigurations, defaultConfiguration, ivyScala, ivyValidate, projectInfo) map { + (pid, deps, over, ivyXML, confs, defaultConf, ivyS, validate, pinfo) => new InlineConfiguration(pid, pinfo, deps, over, ivyXML, confs, defaultConf, ivyS, validate) } def sbtClassifiersTasks = inTask(updateSbtClassifiers)(Seq( diff --git a/main/Keys.scala b/main/Keys.scala index 3881f99e2..a0fe26a11 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -277,6 +277,7 @@ object Keys val offline = SettingKey[Boolean]("offline", "Configures sbt to work without a network connection where possible.") val ivyPaths = SettingKey[IvyPaths]("ivy-paths", "Configures paths used by Ivy for dependency management.") val libraryDependencies = SettingKey[Seq[ModuleID]]("library-dependencies", "Declares managed dependencies.") + val dependencyOverrides = SettingKey[Set[ModuleID]]("dependency-overrides", "Declares managed dependency overrides.") val allDependencies = TaskKey[Seq[ModuleID]]("all-dependencies", "Inter-project and library dependencies.") val projectDependencies = TaskKey[Seq[ModuleID]]("project-dependencies", "Inter-project dependencies.") val ivyXML = SettingKey[NodeSeq]("ivy-xml", "Defines inline Ivy XML for configuring dependency management.") diff --git a/main/actions/CacheIvy.scala b/main/actions/CacheIvy.scala index 468969cb2..dffd76c49 100644 --- a/main/actions/CacheIvy.scala +++ b/main/actions/CacheIvy.scala @@ -11,7 +11,7 @@ package sbt import Types.{:+:, idFun} import scala.xml.NodeSeq import sbinary.{DefaultProtocol,Format} - import DefaultProtocol.{immutableMapFormat, immutableSetFormat, optionsAreFormat} + import DefaultProtocol.{immutableMapFormat, optionsAreFormat} import RepositoryHelpers._ import Ordering._ @@ -96,6 +96,7 @@ object CacheIvy m => ((m.organization,m.name,m.revision,m.configurations), (m.isChanging, m.isTransitive, m.isForce, m.explicitArtifacts, m.exclusions, m.extraAttributes, m.crossVersion)), { case ((o,n,r,cs),(ch,t,f,as,excl,x,cv)) => ModuleID(o,n,r,cs,ch,t,f,as,excl,x,cv) } ) + implicit def moduleSetIC: InputCache[Set[ModuleID]] = basicInput(defaultEquiv, immutableSetFormat) implicit def configurationFormat(implicit sf: Format[String]): Format[Configuration] = wrap[Configuration, String](_.name, s => new Configuration(s)) @@ -121,7 +122,7 @@ object CacheIvy object L4 { implicit def moduleConfToHL = (m: ModuleConfiguration) => m.organization :+: m.name :+: m.revision :+: m.resolver :+: HNil implicit def emptyToHL = (e: EmptyConfiguration) => e.module :+: e.ivyScala :+: e.validate :+: HNil - implicit def inlineToHL = (c: InlineConfiguration) => c.module :+: c.dependencies :+: c.ivyXML :+: c.configurations :+: c.defaultConfiguration.map(_.name) :+: c.ivyScala :+: c.validate :+: HNil + implicit def inlineToHL = (c: InlineConfiguration) => c.module :+: c.dependencies :+: c.ivyXML :+: c.configurations :+: c.defaultConfiguration.map(_.name) :+: c.ivyScala :+: c.validate :+: c.overrides :+: HNil } import L4._ diff --git a/sbt/src/sbt-test/dependency-management/override/build.sbt b/sbt/src/sbt-test/dependency-management/override/build.sbt new file mode 100644 index 000000000..3fa61ec97 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/override/build.sbt @@ -0,0 +1,8 @@ +scalaVersion := "2.9.1" + +InputKey[Unit]("check") <<= inputTask { args => + (update, args) map { + case (report, Seq(expected, _*)) => + report.allModules.forall(_.revision == expected) + } +} diff --git a/sbt/src/sbt-test/dependency-management/override/test b/sbt/src/sbt-test/dependency-management/override/test new file mode 100644 index 000000000..28a26ffe3 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/override/test @@ -0,0 +1,4 @@ +> check 2.9.1 +> 'set dependencyOverrides += "org.scala-lang" % "scala-library" % "2.8.2"' +> check 2.8.2 +