From 8d0e4d2ef021aab5e94ed028ec96019f8ae2ca71 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 11 Nov 2016 02:44:56 -0500 Subject: [PATCH] Apply scalaVersion enforcement to Compile related configs Fixes #2786. Ref #2634. sbt 0.13.12 added Ivy mediator that enforces scalaOrganization and scalaVersion for Scala toolchain artifacts. This turns out to be a bit too aggressive because Ivy configurations can be used as an independent dependency graph that does not rely on the scalaVersion used by Compile configuration. By enforcing scalaVersion in those graph causes runtime failure. This change checks if the configuration extends Default, Compile, Provided, or Optional before enforcing scalaVersion. --- ivy/src/main/scala/sbt/Configuration.scala | 9 +++++++++ ivy/src/main/scala/sbt/Ivy.scala | 16 +++++++++++++++- ivy/src/main/scala/sbt/IvyScala.scala | 16 ++++++++++------ ivy/src/test/scala/ScalaOverrideTest.scala | 4 +++- notes/0.13.14/mediator_fix.md | 9 +++++++++ .../scala-organization/build.sbt | 1 - 6 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 notes/0.13.14/mediator_fix.md diff --git a/ivy/src/main/scala/sbt/Configuration.scala b/ivy/src/main/scala/sbt/Configuration.scala index d2307b89d..f502b7d10 100644 --- a/ivy/src/main/scala/sbt/Configuration.scala +++ b/ivy/src/main/scala/sbt/Configuration.scala @@ -51,6 +51,15 @@ object Configurations { private[sbt] def DefaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration private[sbt] def defaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) Configurations.Compile else Configurations.Default private[sbt] def removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*) + + /** Returns true if the configuration should be under the influence of scalaVersion. */ + private[sbt] def underScalaVersion(c: Configuration): Boolean = + c match { + case Default | Compile | IntegrationTest | Provided | Runtime | Test | Optional | + CompilerPlugin | CompileInternal | RuntimeInternal | TestInternal => true + case config => + config.extendsConfigs exists underScalaVersion + } } /** Represents an Ivy configuration. */ final case class Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) { diff --git a/ivy/src/main/scala/sbt/Ivy.scala b/ivy/src/main/scala/sbt/Ivy.scala index ef9b695e9..fdf3c6b88 100644 --- a/ivy/src/main/scala/sbt/Ivy.scala +++ b/ivy/src/main/scala/sbt/Ivy.scala @@ -174,7 +174,21 @@ final class IvySbt(val configuration: IvyConfiguration) { case pc: PomConfiguration => configurePom(pc) case ifc: IvyFileConfiguration => configureIvyFile(ifc) } - moduleSettings.ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration, configuration.log)) + + val configs = + moduleSettings match { + case ic: InlineConfiguration => ic.configurations + case ic: InlineConfigurationWithExcludes => ic.configurations + case ec: EmptyConfiguration => Nil + case pc: PomConfiguration => Configurations.default ++ Configurations.defaultInternal + case ifc: IvyFileConfiguration => Configurations.default ++ Configurations.defaultInternal + } + moduleSettings.ivyScala match { + case Some(is) => + val svc = configs.toVector filter Configurations.underScalaVersion map { _.name } + IvyScala.checkModule(baseModule, baseConfiguration, svc, configuration.log)(is) + case _ => // do nothing + } IvySbt.addExtraNamespace(baseModule) (baseModule, baseConfiguration) } diff --git a/ivy/src/main/scala/sbt/IvyScala.scala b/ivy/src/main/scala/sbt/IvyScala.scala index 8bf8cb780..19bb50207 100644 --- a/ivy/src/main/scala/sbt/IvyScala.scala +++ b/ivy/src/main/scala/sbt/IvyScala.scala @@ -49,24 +49,28 @@ final case class IvyScala(scalaFullVersion: String, scalaBinaryVersion: String, private object IvyScala { /** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */ - def checkModule(module: DefaultModuleDescriptor, conf: String, log: Logger)(check: IvyScala): Unit = { + def checkModule(module: DefaultModuleDescriptor, conf: String, scalaVersionConfigs: Vector[String], log: Logger)(check: IvyScala): Unit = { if (check.checkExplicit) checkDependencies(module, check.scalaOrganization, check.scalaBinaryVersion, check.configurations, log) if (check.filterImplicit) excludeScalaJars(module, check.configurations) if (check.overrideScalaVersion) - overrideScalaVersion(module, check.scalaOrganization, check.scalaFullVersion) + overrideScalaVersion(module, check.scalaOrganization, check.scalaFullVersion, scalaVersionConfigs) } - class OverrideScalaMediator(scalaOrganization: String, scalaVersion: String) extends DependencyDescriptorMediator { + class OverrideScalaMediator(scalaOrganization: String, scalaVersion: String, scalaVersionConfigs0: Vector[String]) extends DependencyDescriptorMediator { + private[this] val scalaVersionConfigs = scalaVersionConfigs0.toSet def mediate(dd: DependencyDescriptor): DependencyDescriptor = { + // Mediate only for the dependencies in scalaVersion configurations. https://github.com/sbt/sbt/issues/2786 + def configQualifies: Boolean = + (dd.getModuleConfigurations exists { scalaVersionConfigs }) val transformer = new NamespaceTransformer { def transform(mrid: ModuleRevisionId): ModuleRevisionId = { if (mrid == null) mrid else mrid.getName match { - case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID) => + case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID) if configQualifies => ModuleRevisionId.newInstance(scalaOrganization, name, mrid.getBranch, scalaVersion, mrid.getQualifiedExtraAttributes) case _ => mrid } @@ -79,8 +83,8 @@ private object IvyScala { } } - def overrideScalaVersion(module: DefaultModuleDescriptor, organization: String, version: String): Unit = { - val mediator = new OverrideScalaMediator(organization, version) + def overrideScalaVersion(module: DefaultModuleDescriptor, organization: String, version: String, scalaVersionConfigs: Vector[String]): Unit = { + val mediator = new OverrideScalaMediator(organization, version, scalaVersionConfigs) module.addDependencyDescriptorMediator(new ModuleId(Organization, "*"), ExactPatternMatcher.INSTANCE, mediator) if (organization != Organization) module.addDependencyDescriptorMediator(new ModuleId(organization, "*"), ExactPatternMatcher.INSTANCE, mediator) diff --git a/ivy/src/test/scala/ScalaOverrideTest.scala b/ivy/src/test/scala/ScalaOverrideTest.scala index 9165487bd..9daa3832d 100644 --- a/ivy/src/test/scala/ScalaOverrideTest.scala +++ b/ivy/src/test/scala/ScalaOverrideTest.scala @@ -14,10 +14,12 @@ object ScalaOverrideTest extends Specification { val OtherOrgID = "other.org" def check(org0: String, version0: String)(org1: String, name1: String, version1: String) = { - val osm = new OverrideScalaMediator(org0, version0) + val scalaConfigs = Configurations.default.toVector filter { Configurations.underScalaVersion } map { _.name } + val osm = new OverrideScalaMediator(org0, version0, scalaConfigs) val mrid = ModuleRevisionId.newInstance(org1, name1, version1) val dd = new DefaultDependencyDescriptor(mrid, false) + dd.addDependencyConfiguration("compile", "compile") val res = osm.mediate(dd) res.getDependencyRevisionId must_== ModuleRevisionId.newInstance(org0, name1, version0) diff --git a/notes/0.13.14/mediator_fix.md b/notes/0.13.14/mediator_fix.md new file mode 100644 index 000000000..ad0502a34 --- /dev/null +++ b/notes/0.13.14/mediator_fix.md @@ -0,0 +1,9 @@ +### Bug fixes + +- Fixes a regression in sbt 0.13.12 that was misfiring Scala version enforcement when configuration does not extend `Compile`. [#2827][2827]/[#2786][2786] by [@eed3si9n][@eed3si9n] + + [2786]: https://github.com/sbt/sbt/issues/2786 + [2827]: https://github.com/sbt/sbt/pull/2827 + [@eed3si9n]: https://github.com/eed3si9n + [@dwijnand]: https://github.com/dwijnand + [@Duhemm]: https://github.com/Duhemm diff --git a/sbt/src/sbt-test/dependency-management/scala-organization/build.sbt b/sbt/src/sbt-test/dependency-management/scala-organization/build.sbt index 217b3f4d7..2ee2d59da 100644 --- a/sbt/src/sbt-test/dependency-management/scala-organization/build.sbt +++ b/sbt/src/sbt-test/dependency-management/scala-organization/build.sbt @@ -49,6 +49,5 @@ checkDependencies := { m <- c.modules if !m.evicted } yield m.module.copy(extraAttributes = Map.empty)).toSet - assert(resolved == expected) }