diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index eff05ef36..b593c05ae 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -546,6 +546,7 @@ object Defaults extends BuildCommon { val zincDir = BuildPaths.getZincDirectory(st, g) val app = appConfiguration.value val launcher = app.provider.scalaProvider.launcher + val dr = scalaCompilerBridgeDependencyResolution.value val scalac = scalaCompilerBridgeBinaryJar.value match { case Some(jar) => @@ -561,7 +562,7 @@ object Defaults extends BuildCommon { globalLock = launcher.globalLock, componentProvider = app.provider.components, secondaryCacheDir = Option(zincDir), - dependencyResolution = bootDependencyResolution.value, + dependencyResolution = dr, compilerBridgeSource = scalaCompilerBridgeSource.value, scalaJarsTarget = zincDir, log = streams.value.log @@ -2391,7 +2392,7 @@ object Classpaths { ) }, dependencyResolution := LibraryManagement.dependencyResolutionTask.value, - csrConfiguration := LMCoursier.coursierConfigurationTask(true, false).value, + csrConfiguration := LMCoursier.updateClassifierConfigurationTask.value, updateClassifiers in TaskGlobal := (Def.task { val s = streams.value val is = ivySbt.value @@ -2430,7 +2431,7 @@ object Classpaths { ) ) ++ Seq( csrProject := CoursierInputsTasks.coursierProjectTask.value, - csrConfiguration := LMCoursier.coursierConfigurationTask(false, false).value, + csrConfiguration := LMCoursier.coursierConfigurationTask.value, csrResolvers := CoursierRepositoriesTasks.coursierResolversTask.value, csrRecursiveResolvers := CoursierRepositoriesTasks.coursierRecursiveResolversTask.value, csrSbtResolvers := CoursierRepositoriesTasks.coursierSbtResolversTask.value, @@ -2560,13 +2561,7 @@ object Classpaths { .plugins .pluginData .resolvers - // https://github.com/sbt/sbt/issues/4408 - (explicit, boot) match { - case (Some(ex), Some(b)) => (ex.toVector ++ b.toVector).distinct - case (Some(ex), None) => ex - case (None, Some(b)) => b - case _ => externalResolvers.value - } + explicit orElse boot getOrElse externalResolvers.value }, ivyConfiguration := InlineIvyConfiguration( lock = Option(lock(appConfiguration.value)), @@ -2599,7 +2594,7 @@ object Classpaths { ) }, dependencyResolution := LibraryManagement.dependencyResolutionTask.value, - csrConfiguration := LMCoursier.coursierConfigurationTask(false, true).value, + csrConfiguration := LMCoursier.updateSbtClassifierConfigurationTask.value, updateSbtClassifiers in TaskGlobal := (Def.task { val lm = dependencyResolution.value val s = streams.value @@ -2638,9 +2633,48 @@ object Classpaths { } } tag (Tags.Update, Tags.Network)).value ) + ) ++ + inTask(scalaCompilerBridgeScope)( + Seq( + dependencyResolution := LibraryManagement.dependencyResolutionTask.value, + csrConfiguration := LMCoursier.scalaCompilerBridgeConfigurationTask.value, + csrResolvers := CoursierRepositoriesTasks.coursierResolversTask.value, + externalResolvers := scalaCompilerBridgeResolvers.value, + ivyConfiguration := InlineIvyConfiguration( + lock = Option(lock(appConfiguration.value)), + log = Option(streams.value.log), + updateOptions = UpdateOptions(), + paths = Option(ivyPaths.value), + resolvers = scalaCompilerBridgeResolvers.value.toVector, + otherResolvers = Vector.empty, + moduleConfigurations = Vector.empty, + checksums = checksums.value.toVector, + managedChecksums = false, + resolutionCacheDir = Some(crossTarget.value / "bridge-resolution-cache"), + ) + ) ) ++ Seq( bootIvyConfiguration := (updateSbtClassifiers / ivyConfiguration).value, - bootDependencyResolution := (updateSbtClassifiers / dependencyResolution).value + bootDependencyResolution := (updateSbtClassifiers / dependencyResolution).value, + scalaCompilerBridgeResolvers := { + val boot = bootResolvers.value + val explicit = buildStructure.value + .units(thisProjectRef.value.build) + .unit + .plugins + .pluginData + .resolvers + val ext = externalResolvers.value.toVector + // https://github.com/sbt/sbt/issues/4408 + val xs = (explicit, boot) match { + case (Some(ex), Some(b)) => (ex.toVector ++ b.toVector).distinct + case (Some(ex), None) => ex.toVector + case (None, Some(b)) => b.toVector + case _ => Vector() + } + (xs ++ ext).distinct + }, + scalaCompilerBridgeDependencyResolution := (scalaCompilerBridgeScope / dependencyResolution).value ) def classifiersModuleTask: Initialize[Task[GetClassifiersModule]] = diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index dfb69d13e..fcf162d7a 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -183,6 +183,7 @@ object Keys { val fileInputOptions = settingKey[Seq[String]]("Options that take file input, which may invalidate the cache.").withRank(CSetting) val scalaCompilerBridgeBinaryJar = taskKey[Option[File]]("Optionally, the jar of the compiler bridge. When not None, this takes precedence over scalaCompilerBridgeSource").withRank(CSetting) val scalaCompilerBridgeSource = settingKey[ModuleID]("Configures the module ID of the sources of the compiler bridge when scalaCompilerBridgeBinaryJar is None").withRank(CSetting) + val scalaCompilerBridgeScope = taskKey[Unit]("The compiler bridge scope.").withRank(DTask) val scalaArtifacts = settingKey[Seq[String]]("Configures the list of artifacts which should match the Scala binary version").withRank(CSetting) val enableBinaryCompileAnalysis = settingKey[Boolean]("Writes the analysis file in binary format") val crossJavaVersions = settingKey[Seq[String]]("The java versions used during JDK cross testing").withRank(BPlusSetting) @@ -344,6 +345,7 @@ object Keys { // This setting was created to work around the limitation of derived tasks not being able to use task-scoped task: ivyConfiguration in updateSbtClassifiers val bootIvyConfiguration = taskKey[IvyConfiguration]("General dependency management (Ivy) settings, configured to retrieve sbt's components.").withRank(DTask) val bootDependencyResolution = taskKey[DependencyResolution]("Dependency resolution to retrieve sbt's components.").withRank(CTask) + val scalaCompilerBridgeDependencyResolution = taskKey[DependencyResolution]("Dependency resolution to retrieve the compiler bridge.").withRank(CTask) val moduleSettings = taskKey[ModuleSettings]("Module settings, which configure dependency management for a specific module, such as a project.").withRank(DTask) val unmanagedBase = settingKey[File]("The default directory for manually managed libraries.").withRank(ASetting) val updateConfiguration = settingKey[UpdateConfiguration]("Configuration for resolving and retrieving managed dependencies.").withRank(DSetting) @@ -403,6 +405,7 @@ object Keys { val projectResolver = taskKey[Resolver]("Resolver that handles inter-project dependencies.").withRank(DTask) val fullResolvers = taskKey[Seq[Resolver]]("Combines the project resolver, default resolvers, and user-defined resolvers.").withRank(CTask) val otherResolvers = taskKey[Seq[Resolver]]("Resolvers not included in the main resolver chain, such as those in module configurations.").withRank(CSetting) + val scalaCompilerBridgeResolvers = taskKey[Seq[Resolver]]("Resolvers used to resolve compiler bridges.").withRank(CSetting) val useJCenter = settingKey[Boolean]("Use JCenter as the default repository.").withRank(BSetting) val moduleConfigurations = settingKey[Seq[ModuleConfiguration]]("Defines module configurations, which override resolvers on a per-module basis.").withRank(BMinusSetting) val retrievePattern = settingKey[String]("Pattern used to retrieve managed dependencies to the current build.").withRank(DSetting) diff --git a/main/src/main/scala/sbt/internal/LMCoursier.scala b/main/src/main/scala/sbt/internal/LMCoursier.scala index 15eb75c01..e525efaf4 100644 --- a/main/src/main/scala/sbt/internal/LMCoursier.scala +++ b/main/src/main/scala/sbt/internal/LMCoursier.scala @@ -17,10 +17,12 @@ import lmcoursier.definitions.{ } import lmcoursier._ import sbt.librarymanagement._ +import lmcoursier.credentials.Credentials import Keys._ import sbt.internal.librarymanagement.{ CoursierArtifactsTasks, CoursierInputsTasks } import sbt.util.Logger import sbt.io.syntax._ +import xsbti.AppConfiguration private[sbt] object LMCoursier { def defaultCacheLocation: File = @@ -29,81 +31,148 @@ private[sbt] object LMCoursier { case _ => CoursierDependencyResolution.defaultCacheLocation } - def coursierConfigurationTask( - withClassifiers: Boolean, - sbtClassifiers: Boolean - ): Def.Initialize[Task[CoursierConfiguration]] = - Def.taskDyn { - val s = streams.value - val log = s.log - val resolversTask = - if (sbtClassifiers) - csrSbtResolvers - else - csrRecursiveResolvers - val classifiersTask: sbt.Def.Initialize[sbt.Task[Option[Seq[Classifier]]]] = - if (withClassifiers && !sbtClassifiers) - Def.task(Some(sbt.Keys.transitiveClassifiers.value.map(Classifier(_)))) - else - Def.task(None) - Def.task { - val rs = resolversTask.value - val scalaOrg = scalaOrganization.value - val scalaVer = scalaVersion.value - val interProjectDependencies0 = csrInterProjectDependencies.value.toVector - // during the resolution of sbt artifacts, such as compiler bridge source - // interproject dependencies should not be used (otherwise you can't compile sbt/zinc using sbt) - val interProjectDependencies: Vector[CProject] = - if (sbtClassifiers) Vector() - else interProjectDependencies0 - val excludeDeps = Inputs.exclusions( - allExcludeDependencies.value, - scalaVer, - scalaBinaryVersion.value, - streams.value.log - ) - val fallbackDeps = csrFallbackDependencies.value - val autoScalaLib = autoScalaLibrary.value && scalaModuleInfo.value.forall( - _.overrideScalaVersion - ) - val profiles = csrMavenProfiles.value - val credentials = CoursierInputsTasks.credentialsTask.value - - val createLogger = csrLogger.value - - val cache = csrCacheDirectory.value - - val internalSbtScalaProvider = appConfiguration.value.provider.scalaProvider - val sbtBootJars = internalSbtScalaProvider.jars() - val sbtScalaVersion = internalSbtScalaProvider.version() - val sbtScalaOrganization = "org.scala-lang" // always assuming sbt uses mainline scala - val classifiers = classifiersTask.value - Classpaths.warnResolversConflict(rs, log) - CoursierConfiguration() - .withResolvers(rs.toVector) - .withInterProjectDependencies(interProjectDependencies) - .withFallbackDependencies(fallbackDeps.toVector) - .withExcludeDependencies( - excludeDeps.toVector.map { - case (o, n) => - (o.value, n.value) - }.sorted - ) - .withAutoScalaLibrary(autoScalaLib) - .withSbtScalaJars(sbtBootJars.toVector) - .withSbtScalaVersion(sbtScalaVersion) - .withSbtScalaOrganization(sbtScalaOrganization) - .withClassifiers(classifiers.toVector.flatten.map(_.value)) - .withHasClassifiers(classifiers.nonEmpty) - .withMavenProfiles(profiles.toVector.sorted) - .withScalaOrganization(scalaOrg) - .withScalaVersion(scalaVer) - .withCredentials(credentials) - .withLogger(createLogger) - .withCache(cache) - .withLog(log) + def coursierConfiguration( + rs: Seq[Resolver], + interProjectDependencies: Seq[CProject], + fallbackDeps: Seq[FallbackDependency], + appConfig: AppConfiguration, + classifiers: Option[Seq[Classifier]], + profiles: Set[String], + scalaOrg: String, + scalaVer: String, + scalaBinaryVer: String, + autoScalaLib: Boolean, + scalaModInfo: Option[ScalaModuleInfo], + excludeDeps: Seq[InclExclRule], + credentials: Seq[Credentials], + createLogger: Option[CacheLogger], + cacheDirectory: File, + log: Logger + ): CoursierConfiguration = { + val coursierExcludeDeps = Inputs + .exclusions( + excludeDeps, + scalaVer, + scalaBinaryVer, + log + ) + .toVector + .map { + case (o, n) => + (o.value, n.value) } - } + .sorted + val autoScala = autoScalaLib && scalaModInfo.forall( + _.overrideScalaVersion + ) + val internalSbtScalaProvider = appConfig.provider.scalaProvider + val sbtBootJars = internalSbtScalaProvider.jars() + val sbtScalaVersion = internalSbtScalaProvider.version() + val sbtScalaOrganization = "org.scala-lang" // always assuming sbt uses mainline scala + Classpaths.warnResolversConflict(rs, log) + CoursierConfiguration() + .withResolvers(rs.toVector) + .withInterProjectDependencies(interProjectDependencies.toVector) + .withFallbackDependencies(fallbackDeps.toVector) + .withExcludeDependencies(coursierExcludeDeps) + .withAutoScalaLibrary(autoScala) + .withSbtScalaJars(sbtBootJars.toVector) + .withSbtScalaVersion(sbtScalaVersion) + .withSbtScalaOrganization(sbtScalaOrganization) + .withClassifiers(classifiers.toVector.flatten.map(_.value)) + .withHasClassifiers(classifiers.nonEmpty) + .withMavenProfiles(profiles.toVector.sorted) + .withScalaOrganization(scalaOrg) + .withScalaVersion(scalaVer) + .withCredentials(credentials) + .withLogger(createLogger) + .withCache(cacheDirectory) + .withLog(log) + } + + def coursierConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task { + coursierConfiguration( + csrRecursiveResolvers.value, + csrInterProjectDependencies.value.toVector, + csrFallbackDependencies.value, + appConfiguration.value, + None, + csrMavenProfiles.value, + scalaOrganization.value, + scalaVersion.value, + scalaBinaryVersion.value, + autoScalaLibrary.value, + scalaModuleInfo.value, + allExcludeDependencies.value, + CoursierInputsTasks.credentialsTask.value, + csrLogger.value, + csrCacheDirectory.value, + streams.value.log + ) + } + + def updateClassifierConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task { + coursierConfiguration( + csrRecursiveResolvers.value, + csrInterProjectDependencies.value.toVector, + csrFallbackDependencies.value, + appConfiguration.value, + Some(transitiveClassifiers.value.map(Classifier(_))), + csrMavenProfiles.value, + scalaOrganization.value, + scalaVersion.value, + scalaBinaryVersion.value, + autoScalaLibrary.value, + scalaModuleInfo.value, + allExcludeDependencies.value, + CoursierInputsTasks.credentialsTask.value, + csrLogger.value, + csrCacheDirectory.value, + streams.value.log + ) + } + + def updateSbtClassifierConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task { + coursierConfiguration( + csrSbtResolvers.value, + Vector(), + csrFallbackDependencies.value, + appConfiguration.value, + None, + csrMavenProfiles.value, + scalaOrganization.value, + scalaVersion.value, + scalaBinaryVersion.value, + autoScalaLibrary.value, + scalaModuleInfo.value, + allExcludeDependencies.value, + CoursierInputsTasks.credentialsTask.value, + csrLogger.value, + csrCacheDirectory.value, + streams.value.log + ) + } + + def scalaCompilerBridgeConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task { + coursierConfiguration( + csrResolvers.value, + Vector(), + csrFallbackDependencies.value, + appConfiguration.value, + None, + csrMavenProfiles.value, + scalaOrganization.value, + scalaVersion.value, + scalaBinaryVersion.value, + autoScalaLibrary.value, + scalaModuleInfo.value, + allExcludeDependencies.value, + CoursierInputsTasks.credentialsTask.value, + csrLogger.value, + csrCacheDirectory.value, + streams.value.log + ) + } def coursierLoggerTask: Def.Initialize[Task[Option[CacheLogger]]] = Def.task { val st = Keys.streams.value diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index a6f12b680..348f5c9fa 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -47,17 +47,18 @@ private[sbt] object LibraryManagement { coursierOpt.orElse(notIvyOpt).getOrElse(true) } - def dependencyResolutionTask: Def.Initialize[Task[DependencyResolution]] = Def.taskDyn { - if (Keys.useCoursier.value) { - Def.task { CoursierDependencyResolution(Keys.csrConfiguration.value) } - } else - Def.task { - IvyDependencyResolution( - Keys.ivyConfiguration.value, - CustomHttp.okhttpClient.value - ) - } - } + def dependencyResolutionTask: Def.Initialize[Task[DependencyResolution]] = + Def.taskDyn { + if (Keys.useCoursier.value) { + Def.task { CoursierDependencyResolution(Keys.csrConfiguration.value) } + } else + Def.task { + IvyDependencyResolution( + Keys.ivyConfiguration.value, + CustomHttp.okhttpClient.value + ) + } + } def cachedUpdate( lm: DependencyResolution, diff --git a/main/src/main/scala/sbt/internal/librarymanagement/CoursierRepositoriesTasks.scala b/main/src/main/scala/sbt/internal/librarymanagement/CoursierRepositoriesTasks.scala index 1e4994311..b0d4436f7 100644 --- a/main/src/main/scala/sbt/internal/librarymanagement/CoursierRepositoriesTasks.scala +++ b/main/src/main/scala/sbt/internal/librarymanagement/CoursierRepositoriesTasks.scala @@ -53,73 +53,58 @@ private[sbt] object CoursierRepositoriesTasks { resolvers } - private def resultTask( - bootResOpt: Option[Seq[Resolver]], - overrideFlag: Boolean - ): Def.Initialize[sbt.Task[Seq[Resolver]]] = - bootResOpt.filter(_ => overrideFlag) match { - case Some(r) => Def.task(r) - case None => - Def.taskDyn { - val extRes = externalResolvers.value - val isSbtPlugin = sbtPlugin.value - if (isSbtPlugin) - Def.task { - Seq( - sbtResolver.value, - Classpaths.sbtPluginReleases - ) ++ extRes - } else - Def.task(extRes) - } - } - // local-preloaded-ivy contains dangling ivy.xml without JAR files // https://github.com/sbt/sbt/issues/4661 private final val keepPreloaded = false // coursierKeepPreloaded.value - def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = - Def.taskDyn { - - val bootResOpt = bootResolvers.value - val overrideFlag = overrideBuildResolvers.value - - Def.task { - val result0 = resultTask(bootResOpt, overrideFlag).value - val reorderResolvers = true // coursierReorderResolvers.value - - val paths = ivyPaths.value - val result1 = - if (reorderResolvers) CResolvers.reorderResolvers(result0) - else result0 - val result2 = - paths.ivyHome match { - case Some(ivyHome) => - val ivyHomeUri = IO.toURI(ivyHome).getSchemeSpecificPart - result1 map { - case r: FileRepository => - val ivyPatterns = r.patterns.ivyPatterns map { - _.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri) - } - val artifactPatterns = r.patterns.artifactPatterns map { - _.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri) - } - val p = - r.patterns.withIvyPatterns(ivyPatterns).withArtifactPatterns(artifactPatterns) - r.withPatterns(p) - case r => r - } - case _ => result1 - } - - if (keepPreloaded) - result2 - else - result2.filter { r => - !r.name.startsWith("local-preloaded") - } - } + def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task { + val bootResOpt = bootResolvers.value + val overrideFlag = overrideBuildResolvers.value + val result0 = bootResOpt.filter(_ => overrideFlag) match { + case Some(r) => r + case None => + val extRes = externalResolvers.value + val isSbtPlugin = sbtPlugin.value + if (isSbtPlugin) + Seq( + sbtResolver.value, + Classpaths.sbtPluginReleases + ) ++ extRes + else extRes } + val reorderResolvers = true // coursierReorderResolvers.value + + val paths = ivyPaths.value + val result1 = + if (reorderResolvers) CResolvers.reorderResolvers(result0) + else result0 + val result2 = + paths.ivyHome match { + case Some(ivyHome) => + val ivyHomeUri = IO.toURI(ivyHome).getSchemeSpecificPart + result1 map { + case r: FileRepository => + val ivyPatterns = r.patterns.ivyPatterns map { + _.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri) + } + val artifactPatterns = r.patterns.artifactPatterns map { + _.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri) + } + val p = + r.patterns.withIvyPatterns(ivyPatterns).withArtifactPatterns(artifactPatterns) + r.withPatterns(p) + case r => r + } + case _ => result1 + } + + if (keepPreloaded) + result2 + else + result2.filter { r => + !r.name.startsWith("local-preloaded") + } + } private val pluginIvySnapshotsBase = Resolver.SbtRepositoryRoot.stripSuffix("/") + "/ivy-snapshots" diff --git a/sbt/src/sbt-test/plugins/hydra/Hello.scala b/sbt/src/sbt-test/plugins/hydra/Hello.scala new file mode 100644 index 000000000..98e54159b --- /dev/null +++ b/sbt/src/sbt-test/plugins/hydra/Hello.scala @@ -0,0 +1,5 @@ +package example + +object Hello extends App { + println("Hello!") +} diff --git a/sbt/src/sbt-test/plugins/hydra/build.sbt b/sbt/src/sbt-test/plugins/hydra/build.sbt new file mode 100644 index 000000000..92141d09c --- /dev/null +++ b/sbt/src/sbt-test/plugins/hydra/build.sbt @@ -0,0 +1,12 @@ +ThisBuild / scalaVersion := "2.12.8" + +lazy val check = taskKey[Unit]("") + +lazy val root = (project in file(".")) + .settings( + name := "hello", + check := { + val rs = scalaCompilerBridgeResolvers.value + assert(rs.exists(r => r.name == "Triplequote Maven Releases")) + } + ) diff --git a/sbt/src/sbt-test/plugins/hydra/project/HydraPlugin.scala b/sbt/src/sbt-test/plugins/hydra/project/HydraPlugin.scala new file mode 100644 index 000000000..68d4ffa99 --- /dev/null +++ b/sbt/src/sbt-test/plugins/hydra/project/HydraPlugin.scala @@ -0,0 +1,23 @@ +package sbtmyplugin + +import sbt._ +import sbt.Keys._ + +object HydraPlugin extends AutoPlugin { + override def requires: Plugins = plugins.JvmPlugin + override def trigger: PluginTrigger = allRequirements + + override lazy val projectSettings = Seq( + resolvers += "Triplequote Maven Releases" at "https://repo.triplequote.com/artifactory/libs-release/", + ) ++ inConfig(Compile)(compileSettings) ++ inConfig(Test)(compileSettings) + + private lazy val compileSettings: Seq[Def.Setting[_]] = inTask(compile)(compileInputsSettings) + + private def compileInputsSettings: Seq[Setting[_]] = Seq( + scalaCompilerBridgeSource := { + ModuleID("com.triplequote", "hydra-bridge_1_0", "2.1.4") + .withConfigurations(Some(Configurations.Compile.name)) + .sources() + } + ) +} diff --git a/sbt/src/sbt-test/plugins/hydra/test b/sbt/src/sbt-test/plugins/hydra/test new file mode 100644 index 000000000..15675b169 --- /dev/null +++ b/sbt/src/sbt-test/plugins/hydra/test @@ -0,0 +1 @@ +> check