From 100f1ac09c7c81d67f9636e9f5a64f536e250a52 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 21 Sep 2022 05:07:49 -0400 Subject: [PATCH] Use flatMapTask instead of taskDyn --- main-settings/src/main/scala/sbt/Def.scala | 14 +- main-settings/src/main/scala/sbt/Remove.scala | 4 +- .../src/main/scala/sbt/std/TaskMacro.scala | 2 +- main/src/main/scala-2/sbt/RemoteCache.scala | 77 ++++--- main/src/main/scala-2/sbt/nio/Settings.scala | 19 +- .../sbt/pluigins/SemanticdbPlugin.scala | 22 +- main/src/main/scala/sbt/Defaults.scala | 98 +++++---- .../sbt/coursierint/CoursierInputsTasks.scala | 49 +++-- .../CoursierRepositoriesTasks.scala | 21 +- .../scala/sbt/internal/ClassLoaders.scala | 31 +-- .../scala/sbt/internal/ClasspathImpl.scala | 163 ++++++++------- main/src/main/scala/sbt/internal/Clean.scala | 130 +++++++----- .../scala/sbt/internal/GlobalPlugin.scala | 2 + .../scala/sbt/internal/TaskSequential.scala | 3 +- .../WatchTransitiveDependencies.scala | 38 ++-- .../internal/librarymanagement/IvyXml.scala | 30 ++- .../internal/server/BuildServerProtocol.scala | 191 +++++++++++------- 17 files changed, 504 insertions(+), 390 deletions(-) diff --git a/main-settings/src/main/scala/sbt/Def.scala b/main-settings/src/main/scala/sbt/Def.scala index 4decefee3..9dedb0138 100644 --- a/main-settings/src/main/scala/sbt/Def.scala +++ b/main-settings/src/main/scala/sbt/Def.scala @@ -301,11 +301,17 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits: */ inline def taskValue: Task[A1] = InputWrapper.`wrapInit_\u2603\u2603`[Task[A1]](in) - // implicit def macroValueIInT[T]( - // @deprecated("unused", "") in: Initialize[InputTask[T]] - // ): InputEvaluated[T] = ??? + // implicit def macroValueIInT[T]( + // @deprecated("unused", "") in: Initialize[InputTask[T]] + // ): InputEvaluated[T] = ??? - // implicit def macroPrevious[T](@deprecated("unused", "") in: TaskKey[T]): MacroPrevious[T] = ??? + inline def flatMapTask[A2](f: A1 => Initialize[Task[A2]]): Initialize[Task[A2]] = + std.FullInstance.initializeTaskMonad.flatMap(in)(f) + + extension [A1](in: TaskKey[A1]) + // implicit def macroPrevious[T](@deprecated("unused", "") in: TaskKey[T]): MacroPrevious[T] = ??? + inline def previous(using JsonFormat[A1]): Option[A1] = + ${ TaskMacro.previousImpl[A1]('in) } // The following conversions enable the types Parser[T], Initialize[Parser[T]], and // Initialize[State => Parser[T]] to be used in the inputTask macro as an input with an ultimate diff --git a/main-settings/src/main/scala/sbt/Remove.scala b/main-settings/src/main/scala/sbt/Remove.scala index 6ab53e42b..250285225 100644 --- a/main-settings/src/main/scala/sbt/Remove.scala +++ b/main-settings/src/main/scala/sbt/Remove.scala @@ -24,12 +24,12 @@ object Remove { } trait Sequence[A, -B, T] extends Value[A, T] with Values[A, B] - implicit def removeSeq[T, V <: T]: Sequence[Seq[T], Seq[V], V] = + given removeSeq[T, V <: T]: Sequence[Seq[T], Seq[V], V] = new Sequence[Seq[T], Seq[V], V] { def removeValue(a: Seq[T], b: V): Seq[T] = a filterNot b.== def removeValues(a: Seq[T], b: Seq[V]): Seq[T] = a diff (b: Seq[T]) } - implicit def removeOption[T]: Sequence[Seq[T], Option[T], Option[T]] = + given removeOption[T]: Sequence[Seq[T], Option[T], Option[T]] = new Sequence[Seq[T], Option[T], Option[T]] { def removeValue(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a filterNot _.==) def removeValues(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a filterNot _.==) diff --git a/main-settings/src/main/scala/sbt/std/TaskMacro.scala b/main-settings/src/main/scala/sbt/std/TaskMacro.scala index 317c3f8a0..20ba60b8b 100644 --- a/main-settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main-settings/src/main/scala/sbt/std/TaskMacro.scala @@ -66,7 +66,7 @@ object TaskMacro: '{ Def.ifS[A1](Def.task($cond))(Def.task[A1]($thenp))(Def.task[A1]($elsep)) } - case '{ (${ stats }: a); if ($cond) then $thenp else $elsep } => + case '{ ${ stats }: a; if ($cond) then $thenp else $elsep } => '{ Def.ifS[A1](Def.task { $stats; $cond })(Def.task[A1]($thenp))(Def.task[A1]($elsep)) } diff --git a/main/src/main/scala-2/sbt/RemoteCache.scala b/main/src/main/scala-2/sbt/RemoteCache.scala index 1f3d51045..84432dc9d 100644 --- a/main/src/main/scala-2/sbt/RemoteCache.scala +++ b/main/src/main/scala-2/sbt/RemoteCache.scala @@ -69,34 +69,42 @@ object RemoteCache { ) lazy val projectSettings: Seq[Def.Setting[_]] = (Seq( - pushRemoteCache := (Def.taskDyn { - val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value - val configs = arts flatMap { art => - art.packaged.scopedKey.scope match { - case Scope(_, Select(c), _, _) => Some(c) - case _ => None + pushRemoteCache := ((Def + .task { + val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value + val configs = arts flatMap { art => + art.packaged.scopedKey.scope match { + case Scope(_, Select(c), _, _) => Some(c) + case _ => None + } } - } - val filter = ScopeFilter(configurations = inConfigurationsByKeys(configs: _*)) - Def.task { - val _ = pushRemoteCache.all(filter).value - () - } - }).value, - pullRemoteCache := (Def.taskDyn { - val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value - val configs = arts flatMap { art => - art.packaged.scopedKey.scope match { - case Scope(_, Select(c), _, _) => Some(c) - case _ => None + ScopeFilter(configurations = inConfigurationsByKeys(configs: _*)) + }) + .flatMapTask { case filter => + Def.task { + val _ = pushRemoteCache.all(filter).value + () } - } - val filter = ScopeFilter(configurations = inConfigurationsByKeys(configs: _*)) - Def.task { - val _ = pullRemoteCache.all(filter).value - () - } - }).value, + }) + .value, + pullRemoteCache := ((Def + .task { + val arts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value + val configs = arts flatMap { art => + art.packaged.scopedKey.scope match { + case Scope(_, Select(c), _, _) => Some(c) + case _ => None + } + } + ScopeFilter(configurations = inConfigurationsByKeys(configs: _*)) + }) + .flatMapTask { case filter => + Def.task { + val _ = pullRemoteCache.all(filter).value + () + } + }) + .value, pushRemoteCacheConfiguration / remoteCacheArtifacts := { enabledOnly(remoteCacheArtifact.toSettingKey, defaultArtifactTasks).apply(_.join).value }, @@ -239,13 +247,16 @@ object RemoteCache { isSnapshot.value ) }, - pushRemoteCacheConfiguration / packagedArtifacts := Def.taskDyn { - val artifacts = (pushRemoteCacheConfiguration / remoteCacheArtifacts).value - artifacts - .map(a => a.packaged.map(file => (a.artifact, file))) - .join - .apply(_.join.map(_.toMap)) - }.value, + pushRemoteCacheConfiguration / packagedArtifacts := + (Def + .task { (pushRemoteCacheConfiguration / remoteCacheArtifacts).value }) + .flatMapTask { case artifacts => + artifacts + .map(a => a.packaged.map(file => (a.artifact, file))) + .join + .apply(_.join.map(_.toMap)) + } + .value, pushRemoteCacheConfiguration / remoteCacheArtifacts := { List((packageCache / remoteCacheArtifact).value) }, diff --git a/main/src/main/scala-2/sbt/nio/Settings.scala b/main/src/main/scala-2/sbt/nio/Settings.scala index 00d327ca2..83cacb396 100644 --- a/main/src/main/scala-2/sbt/nio/Settings.scala +++ b/main/src/main/scala-2/sbt/nio/Settings.scala @@ -263,12 +263,19 @@ private[sbt] object Settings { @nowarn private[sbt] def cleanImpl[T: JsonFormat: ToSeqPath](taskKey: TaskKey[T]): Def.Setting[_] = { val taskScope = taskKey.scope in taskKey.key - addTaskDefinition(sbt.Keys.clean in taskScope := Def.taskDyn { - // the clean file task needs to run first because the previous cache gets blown away - // by the second task - Def.unit(Clean.cleanFileOutputTask(taskKey).value) - Clean.task(taskScope, full = false) - }.value) + addTaskDefinition( + sbt.Keys.clean in taskScope := + // the clean file task needs to run first because the previous cache gets blown away + // by the second task + Def + .task { + Def.unit(Clean.cleanFileOutputTask(taskKey).value) + } + .flatMapTask { case _ => + Clean.task(taskScope, full = false) + } + .value + ) } /** diff --git a/main/src/main/scala-2/sbt/pluigins/SemanticdbPlugin.scala b/main/src/main/scala-2/sbt/pluigins/SemanticdbPlugin.scala index 9c1f777b2..ea112750a 100644 --- a/main/src/main/scala-2/sbt/pluigins/SemanticdbPlugin.scala +++ b/main/src/main/scala-2/sbt/pluigins/SemanticdbPlugin.scala @@ -68,15 +68,19 @@ object SemanticdbPlugin extends AutoPlugin { }.value, semanticdbOptions ++= targetRootOptions(scalaVersion.value, semanticdbTargetRoot.value), - scalacOptions --= Def.settingDyn { - val config = configuration.value - val enabled = semanticdbEnabled.value - if (enabled) - Def.setting { - semanticdbOptions.?.all(ancestorConfigs(config)).value.flatten.flatten - } - else Def.setting { Nil } - }.value, + // todo: + // scalacOptions --= { + // Def + // .task { (configuration.value, semanticdbEnabled.value) } + // .flatMapTask { case (config, enabled) => + // if enabled then + // Def.task { + // (semanticdbOptions.?.all(ancestorConfigs(config)).value.flatten.flatten: Seq[String]) + // } + // else Def.task { (Nil: Seq[String]) } + // } + // .value + // }, scalacOptions ++= { if (semanticdbEnabled.value) semanticdbOptions.value diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 38bb0083a..9ad26656a 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1039,7 +1039,8 @@ object Defaults extends BuildCommon { cleanFiles := cleanFilesTask.value, cleanKeepFiles := Vector.empty, cleanKeepGlobs ++= historyPath.value.map(_.toGlob).toVector, - clean := Def.taskDyn(Clean.task(resolvedScoped.value.scope, full = true)).value, + // clean := Def.taskDyn(Clean.task(resolvedScoped.value.scope, full = true)).value, + clean := Clean.scopedTask.value, consoleProject := consoleProjectTask.value, transitiveDynamicInputs := WatchTransitiveDependencies.task.value, ) ++ sbt.internal.DeprecatedContinuous.taskDefinitions @@ -1097,17 +1098,13 @@ object Defaults extends BuildCommon { } } - def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Def.taskDyn { - // if this logic changes, ensure that `unmanagedScalaInstanceOnly` and `update` are changed - // appropriately to avoid cycles - scalaHome.value match { - case Some(h) => scalaInstanceFromHome(h) - case None => - val scalaProvider = appConfiguration.value.provider.scalaProvider - val version = scalaVersion.value - if ( - version == scalaProvider.version - ) // use the same class loader as the Scala classes used by sbt + def scalaInstanceTask: Initialize[Task[ScalaInstance]] = + (Def.task { (Keys.scalaHome.value, appConfiguration.value, scalaVersion.value) }).flatMapTask { + case (Some(h), _, _) => scalaInstanceFromHome(h) + case (_, app, version) => + val scalaProvider = app.provider.scalaProvider + if version == scalaProvider.version then + // use the same class loader as the Scala classes used by sbt Def.task { val allJars = scalaProvider.jars val libraryJars = allJars.filter(_.getName == "scala-library.jar") @@ -1124,16 +1121,15 @@ object Defaults extends BuildCommon { case _ => ScalaInstance(version, scalaProvider) } } - else - scalaInstanceFromUpdate + else scalaInstanceFromUpdate } - } // Returns the ScalaInstance only if it was not constructed via `update` // This is necessary to prevent cycles between `update` and `scalaInstance` private[sbt] def unmanagedScalaInstanceOnly: Initialize[Task[Option[ScalaInstance]]] = - Def.taskDyn { - if (scalaHome.value.isDefined) Def.task(Some(scalaInstance.value)) else Def.task(None) + (Def.task { scalaHome.value }).flatMapTask { case h => + if h.isDefined then Def.task(Some(scalaInstance.value)) + else Def.task(None) } private[this] def noToolConfiguration(autoInstance: Boolean): String = { @@ -2542,10 +2538,11 @@ object Defaults extends BuildCommon { PomExtraDependencyAttributes.ScalaVersionKey -> scalaV ).withCrossVersion(Disabled()) - def discoverSbtPluginNames: Initialize[Task[PluginDiscovery.DiscoveredNames]] = Def.taskDyn { - if (sbtPlugin.value) Def.task(PluginDiscovery.discoverSourceAll(compile.value)) - else Def.task(PluginDiscovery.emptyDiscoveredNames) - } + def discoverSbtPluginNames: Initialize[Task[PluginDiscovery.DiscoveredNames]] = + (Def.task { sbtPlugin.value }).flatMapTask { case p => + if p then Def.task(PluginDiscovery.discoverSourceAll(compile.value)) + else Def.task(PluginDiscovery.emptyDiscoveredNames) + } def copyResourcesTask = Def.task { @@ -3963,12 +3960,10 @@ object Classpaths { } private[sbt] def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] = - Def.taskDyn { - depMap( - buildDependencies.value classpathTransitiveRefs thisProjectRef.value, - settingsData.value, - streams.value.log - ) + import sbt.TupleSyntax.* + (buildDependencies.toTaskable, thisProjectRef.toTaskable, settingsData, streams).flatMapN { + case (bd, thisProj, data, s) => + depMap(bd.classpathTransitiveRefs(thisProj), data, s.log) } @nowarn @@ -3976,11 +3971,12 @@ object Classpaths { projects: Seq[ProjectRef], data: Settings[Scope], log: Logger - ): Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] = - Def.value { - projects.flatMap(ivyModule in _ get data).join.map { mod => - mod map { _.dependencyMapping(log) } toMap; - } + ): Task[Map[ModuleRevisionId, ModuleDescriptor]] = + val ivyModules = projects.flatMap { proj => + (proj / ivyModule).get(data) + }.join + ivyModules.mapN { mod => + mod map { _.dependencyMapping(log) } toMap; } def projectResolverTask: Initialize[Task[Resolver]] = @@ -4138,12 +4134,11 @@ object Classpaths { def addUnmanagedLibrary: Seq[Setting[_]] = Seq((Compile / unmanagedJars) ++= unmanagedScalaLibrary.value) - def unmanagedScalaLibrary: Initialize[Task[Seq[File]]] = Def.taskDyn { - if (autoScalaLibrary.value && scalaHome.value.isDefined) - Def.task { scalaInstance.value.libraryJars } - else - Def.task { Nil } - } + def unmanagedScalaLibrary: Initialize[Task[Seq[File]]] = + (Def.task { autoScalaLibrary.value && scalaHome.value.isDefined }).flatMapTask { case cond => + if cond then Def.task { (scalaInstance.value.libraryJars: Seq[File]) } + else Def.task { (Nil: Seq[File]) } + } import DependencyFilter._ def managedJars(config: Configuration, jarTypes: Set[String], up: UpdateReport): Classpath = @@ -4187,20 +4182,19 @@ object Classpaths { } private[this] lazy val internalCompilerPluginClasspath: Initialize[Task[Classpath]] = - Def.taskDyn { - val ref = thisProjectRef.value - val data = settingsData.value - val deps = buildDependencies.value - ClasspathImpl.internalDependenciesImplTask( - ref, - CompilerPlugin, - CompilerPlugin, - data, - deps, - TrackLevel.TrackAlways, - streams.value.log - ) - } + (Def + .task { (thisProjectRef.value, settingsData.value, buildDependencies.value, streams.value) }) + .flatMapTask { case (ref, data, deps, s) => + ClasspathImpl.internalDependenciesImplTask( + ref, + CompilerPlugin, + CompilerPlugin, + data, + deps, + TrackLevel.TrackAlways, + s.log + ) + } lazy val compilerPluginConfig = Seq( scalacOptions := { diff --git a/main/src/main/scala/sbt/coursierint/CoursierInputsTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierInputsTasks.scala index a9f20b566..97778c4c6 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierInputsTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierInputsTasks.scala @@ -147,14 +147,18 @@ object CoursierInputsTasks { } private[sbt] def coursierInterProjectDependenciesTask: Def.Initialize[sbt.Task[Seq[CProject]]] = - Def.taskDyn { - val state = sbt.Keys.state.value - val projectRef = sbt.Keys.thisProjectRef.value - val projectRefs = Project.transitiveInterDependencies(state, projectRef) - Def.task { - csrProject.all(ScopeFilter(inProjects(projectRefs :+ projectRef: _*))).value + (Def + .task { + val state = sbt.Keys.state.value + val projectRef = sbt.Keys.thisProjectRef.value + val projectRefs = Project.transitiveInterDependencies(state, projectRef) + ScopeFilter(inProjects(projectRefs :+ projectRef: _*)) + }) + .flatMapTask { case filter => + Def.task { + csrProject.all(filter).value + } } - } private[sbt] def coursierExtraProjectsTask: Def.Initialize[sbt.Task[Seq[CProject]]] = { Def.task { @@ -191,22 +195,25 @@ object CoursierInputsTasks { private[sbt] def coursierFallbackDependenciesTask : Def.Initialize[sbt.Task[Seq[FallbackDependency]]] = - Def.taskDyn { - val s = state.value - val projectRef = thisProjectRef.value - val projects = Project.transitiveInterDependencies(s, projectRef) + (Def + .task { + val s = state.value + val projectRef = thisProjectRef.value + val projects = Project.transitiveInterDependencies(s, projectRef) + ScopeFilter(inProjects(projectRef +: projects: _*)) + }) + .flatMapTask { case filter => + Def.task { + val allDeps = + allDependencies.all(filter).value.flatten - Def.task { - val allDeps = - allDependencies.all(ScopeFilter(inProjects(projectRef +: projects: _*))).value.flatten - - FromSbt.fallbackDependencies( - allDeps, - scalaVersion.value, - scalaBinaryVersion.value - ) + FromSbt.fallbackDependencies( + allDeps, + scalaVersion.value, + scalaBinaryVersion.value + ) + } } - } val credentialsTask = Def.task { val log = streams.value.log diff --git a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala index 0d263f270..73edce051 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala @@ -123,14 +123,17 @@ object CoursierRepositoriesTasks { } def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = - Def.taskDyn { - val s = state.value - val projectRef = thisProjectRef.value - val dependencyRefs = Project.transitiveInterDependencies(s, projectRef) - Def.task { - val resolvers = csrResolvers.all(ScopeFilter(inProjects(projectRef))).value ++ - csrResolvers.all(ScopeFilter(inProjects(dependencyRefs: _*))).value - resolvers.flatten + (Def + .task { + val s = state.value + val projectRef = thisProjectRef.value + val dependencyRefs = Project.transitiveInterDependencies(s, projectRef) + (ScopeFilter(inProjects(projectRef)), ScopeFilter(inProjects(dependencyRefs: _*))) + }) + .flatMapTask { case (filter1, filter2) => + Def.task { + val resolvers = csrResolvers.all(filter1).value ++ csrResolvers.all(filter2).value + resolvers.flatten + } } - } } diff --git a/main/src/main/scala/sbt/internal/ClassLoaders.scala b/main/src/main/scala/sbt/internal/ClassLoaders.scala index 1c5df8aa0..0dc63bbf7 100644 --- a/main/src/main/scala/sbt/internal/ClassLoaders.scala +++ b/main/src/main/scala/sbt/internal/ClassLoaders.scala @@ -62,18 +62,22 @@ private[sbt] object ClassLoaders { ) } - private[sbt] def runner: Def.Initialize[Task[ScalaRun]] = Def.taskDyn { - val resolvedScope = resolvedScoped.value.scope - val instance = scalaInstance.value - val s = streams.value - val opts = forkOptions.value - val options = javaOptions.value - if (fork.value) { - s.log.debug(s"javaOptions: $options") - Def.task(new ForkRun(opts)) - } else { - Def.task { - if (options.nonEmpty) { + private[sbt] def runner: Def.Initialize[Task[ScalaRun]] = + Def.taskIf { + if fork.value then + val s = streams.value + val options = javaOptions.value + s.log.debug(s"javaOptions: $options") + val opts = forkOptions.value + new ForkRun(opts) + else { + val resolvedScope = resolvedScoped.value.scope + val instance = scalaInstance.value + val s = streams.value + val opts = forkOptions.value + val options = javaOptions.value + + if options.nonEmpty then val mask = ScopeMask(project = false) val showJavaOptions = Scope.displayMasked( (resolvedScope / javaOptions).scopedKey.scope, @@ -86,7 +90,7 @@ private[sbt] object ClassLoaders { mask ) s.log.warn(s"$showJavaOptions will be ignored, $showFork is set to false") - } + val exclude = dependencyJars(exportedProducts).value.toSet ++ instance.libraryJars val allDeps = dependencyJars(dependencyClasspath).value.filterNot(exclude) val logger = state.value.globalLogging.full @@ -114,7 +118,6 @@ private[sbt] object ClassLoaders { new Run(newLoader, trapExit.value) } } - } private[this] def extendedClassLoaderCache: Def.Initialize[Task[ClassLoaderCache]] = Def.task { val errorMessage = "Tried to extract classloader cache for uninitialized state." diff --git a/main/src/main/scala/sbt/internal/ClasspathImpl.scala b/main/src/main/scala/sbt/internal/ClasspathImpl.scala index c28b623aa..3f226c71a 100644 --- a/main/src/main/scala/sbt/internal/ClasspathImpl.scala +++ b/main/src/main/scala/sbt/internal/ClasspathImpl.scala @@ -78,53 +78,58 @@ private[sbt] object ClasspathImpl { private[this] def trackedExportedProductsImplTask( track: TrackLevel ): Initialize[Task[Seq[(File, CompileAnalysis)]]] = - Def.taskDyn { - val _ = (packageBin / dynamicDependency).value - val useJars = exportJars.value - if (useJars) trackedJarProductsImplTask(track) - else trackedNonJarProductsImplTask(track) + Def.taskIf { + if { + val _ = (packageBin / dynamicDependency).value + exportJars.value + } then trackedJarProductsImplTask(track).value + else trackedNonJarProductsImplTask(track).value } private[this] def trackedNonJarProductsImplTask( track: TrackLevel ): Initialize[Task[Seq[(File, CompileAnalysis)]]] = - Def.taskDyn { - val dirs = productDirectories.value - val view = fileTreeView.value - def containsClassFile(): Boolean = - view.list(dirs.map(Glob(_, RecursiveGlob / "*.class"))).nonEmpty - TrackLevel.intersection(track, exportToInternal.value) match { - case TrackLevel.TrackAlways => + (Def + .task { + val dirs = productDirectories.value + val view = fileTreeView.value + (TrackLevel.intersection(track, exportToInternal.value), dirs, view) + }) + .flatMapTask { + case (TrackLevel.TrackAlways, _, _) => Def.task { products.value map { (_, compile.value) } } - case TrackLevel.TrackIfMissing if !containsClassFile() => + case (TrackLevel.TrackIfMissing, dirs, view) + if view.list(dirs.map(Glob(_, RecursiveGlob / "*.class"))).isEmpty => Def.task { products.value map { (_, compile.value) } } - case _ => + case (_, dirs, _) => Def.task { val analysis = previousCompile.value.analysis.toOption.getOrElse(Analysis.empty) dirs.map(_ -> analysis) } } - } private[this] def trackedJarProductsImplTask( track: TrackLevel ): Initialize[Task[Seq[(File, CompileAnalysis)]]] = - Def.taskDyn { - val jar = (packageBin / artifactPath).value - TrackLevel.intersection(track, exportToInternal.value) match { - case TrackLevel.TrackAlways => + (Def + .task { + val jar = (packageBin / artifactPath).value + (TrackLevel.intersection(track, exportToInternal.value), jar) + }) + .flatMapTask { + case (TrackLevel.TrackAlways, _) => Def.task { Seq((packageBin.value, compile.value)) } - case TrackLevel.TrackIfMissing if !jar.exists => + case (TrackLevel.TrackIfMissing, jar) if !jar.exists => Def.task { Seq((packageBin.value, compile.value)) } - case _ => + case (_, jar) => Def.task { val analysisOpt = previousCompile.value.analysis.toOption Seq(jar) map { x => @@ -136,29 +141,33 @@ private[sbt] object ClasspathImpl { } } } - } - def internalDependencyClasspathTask: Initialize[Task[Classpath]] = { - Def.taskDyn { - val _ = ( - (exportedProductsNoTracking / transitiveClasspathDependency).value, - (exportedProductsIfMissing / transitiveClasspathDependency).value, - (exportedProducts / transitiveClasspathDependency).value, - (exportedProductJarsNoTracking / transitiveClasspathDependency).value, - (exportedProductJarsIfMissing / transitiveClasspathDependency).value, - (exportedProductJars / transitiveClasspathDependency).value - ) - internalDependenciesImplTask( - thisProjectRef.value, - classpathConfiguration.value, - configuration.value, - settingsData.value, - buildDependencies.value, - trackInternalDependencies.value, - streams.value.log, - ) - } - } + def internalDependencyClasspathTask: Initialize[Task[Classpath]] = + (Def + .task { + val _ = ( + (exportedProductsNoTracking / transitiveClasspathDependency).value, + (exportedProductsIfMissing / transitiveClasspathDependency).value, + (exportedProducts / transitiveClasspathDependency).value, + (exportedProductJarsNoTracking / transitiveClasspathDependency).value, + (exportedProductJarsIfMissing / transitiveClasspathDependency).value, + (exportedProductJars / transitiveClasspathDependency).value + ) + }) + .flatMapTask { case u => + Def.task { + ( + thisProjectRef.value, + classpathConfiguration.value, + configuration.value, + settingsData.value, + buildDependencies.value, + trackInternalDependencies.value, + streams.value.log, + ) + } + } + .flatMapTask { internalDependenciesImplTask } def internalDependenciesImplTask( projectRef: ProjectRef, @@ -194,31 +203,35 @@ private[sbt] object ClasspathImpl { exportedPickles ) } - Def.taskDyn { - implTask( - thisProjectRef.value, - classpathConfiguration.value, - configuration.value, - settingsData.value, - buildDependencies.value, - TrackLevel.TrackAlways, - streams.value.log, - ) - } + (Def + .task { + ( + thisProjectRef.value, + classpathConfiguration.value, + configuration.value, + settingsData.value, + buildDependencies.value, + TrackLevel.TrackAlways, + streams.value.log, + ) + }) + .flatMapTask(implTask) } def internalDependencyJarsTask: Initialize[Task[Classpath]] = - Def.taskDyn { - internalDependencyJarsImplTask( - thisProjectRef.value, - classpathConfiguration.value, - configuration.value, - settingsData.value, - buildDependencies.value, - trackInternalDependencies.value, - streams.value.log, - ) - } + (Def + .task { + ( + thisProjectRef.value, + classpathConfiguration.value, + configuration.value, + settingsData.value, + buildDependencies.value, + trackInternalDependencies.value, + streams.value.log, + ) + }) + .flatMapTask(internalDependencyJarsImplTask) private def internalDependencyJarsImplTask( projectRef: ProjectRef, @@ -238,15 +251,17 @@ private[sbt] object ClasspathImpl { } def unmanagedDependenciesTask: Initialize[Task[Classpath]] = - Def.taskDyn { - unmanagedDependencies0( - thisProjectRef.value, - configuration.value, - settingsData.value, - buildDependencies.value, - streams.value.log - ) - } + (Def + .task { + ( + thisProjectRef.value, + configuration.value, + settingsData.value, + buildDependencies.value, + streams.value.log + ) + }) + .flatMapTask(unmanagedDependencies0) def unmanagedDependencies0( projectRef: ProjectRef, diff --git a/main/src/main/scala/sbt/internal/Clean.scala b/main/src/main/scala/sbt/internal/Clean.scala index 73e04c5a1..850563075 100644 --- a/main/src/main/scala/sbt/internal/Clean.scala +++ b/main/src/main/scala/sbt/internal/Clean.scala @@ -71,6 +71,11 @@ private[sbt] object Clean { tryDelete(debug) } + private[sbt] def scopedTask: Def.Initialize[Task[Unit]] = + Keys.resolvedScoped.toTaskable.toTask.flatMapTask { case (r: ScopedKey[_]) => + task(r.scope, full = true) + } + /** * Implements the clean task in a given scope. It uses the outputs task value in the provided * scope to determine which files to delete. @@ -82,53 +87,63 @@ private[sbt] object Clean { scope: Scope, full: Boolean ): Def.Initialize[Task[Unit]] = - Def.taskDyn { - val state = Keys.state.value - val extracted = Project.extract(state) - val view = (scope / fileTreeView).value - val manager = streamsManager.value - Def.task { - val excludeFilter = cleanFilter(scope).value - val delete = cleanDelete(scope).value - val targetDir = (scope / target).?.value.map(_.toPath) + (Def + .task { + val state = Keys.state.value + val extracted = Project.extract(state) + val view = (scope / fileTreeView).value + val manager = streamsManager.value + (state, extracted, view, manager) + }) + .flatMapTask { case (state, extracted, view, manager) => + Def.task { + val excludeFilter = cleanFilter(scope).value + val delete = cleanDelete(scope).value + val targetDir = (scope / target).?.value.map(_.toPath) - targetDir.filter(_ => full).foreach(deleteContents(_, excludeFilter, view, delete)) - (scope / cleanFiles).?.value.getOrElse(Nil).foreach { x => - if (x.isDirectory) deleteContents(x.toPath, excludeFilter, view, delete) - else delete(x.toPath) - } - - // This is the special portion of the task where we clear out the relevant streams - // and file outputs of a task. - val streamsKey = scope.task.toOption.map(k => ScopedKey(scope.copy(task = Zero), k)) - val stampsKey = - extracted.structure.data.getDirect(scope, inputFileStamps.key) match { - case Some(_) => ScopedKey(scope, inputFileStamps.key) :: Nil - case _ => Nil + targetDir.filter(_ => full).foreach(deleteContents(_, excludeFilter, view, delete)) + (scope / cleanFiles).?.value.getOrElse(Nil).foreach { x => + if (x.isDirectory) deleteContents(x.toPath, excludeFilter, view, delete) + else delete(x.toPath) } - val streamsGlobs = - (streamsKey.toSeq ++ stampsKey).map(k => manager(k).cacheDirectory.toGlob / **) - ((scope / fileOutputs).value.filter(g => - targetDir.fold(true)(g.base.startsWith) - ) ++ streamsGlobs) - .foreach { g => - val filter: Path => Boolean = { path => - !g.matches(path) || excludeFilter(path) + + // This is the special portion of the task where we clear out the relevant streams + // and file outputs of a task. + val streamsKey = scope.task.toOption.map(k => ScopedKey(scope.copy(task = Zero), k)) + val stampsKey = + extracted.structure.data.getDirect(scope, inputFileStamps.key) match { + case Some(_) => ScopedKey(scope, inputFileStamps.key) :: Nil + case _ => Nil } - deleteContents(g.base, filter, FileTreeView.default, delete) - delete(g.base) - } + val streamsGlobs = + (streamsKey.toSeq ++ stampsKey) + .map(k => manager(k).cacheDirectory.toPath.toGlob / **) + ((scope / fileOutputs).value.filter { g => + targetDir.fold(true)(g.base.startsWith) + } ++ streamsGlobs) + .foreach { g => + val filter: Path => Boolean = { path => + !g.matches(path) || excludeFilter(path) + } + deleteContents(g.base, filter, FileTreeView.default, delete) + delete(g.base) + } + } } - } tag Tags.Clean - private[sbt] trait ToSeqPath[T] { - def apply(t: T): Seq[Path] - } - private[sbt] object ToSeqPath { - implicit val identitySeqPath: ToSeqPath[Seq[Path]] = identity _ - implicit val seqFile: ToSeqPath[Seq[File]] = _.map(_.toPath) - implicit val path: ToSeqPath[Path] = _ :: Nil - implicit val file: ToSeqPath[File] = _.toPath :: Nil - } + .tag(Tags.Clean) + + // SAM + private[sbt] trait ToSeqPath[A]: + def apply(a: A): Seq[Path] + end ToSeqPath + + private[sbt] object ToSeqPath: + given identitySeqPath: ToSeqPath[Seq[Path]] = identity[Seq[Path]](_) + given seqFile: ToSeqPath[Seq[File]] = _.map(_.toPath) + given path: ToSeqPath[Path] = _ :: Nil + given file: ToSeqPath[File] = _.toPath :: Nil + end ToSeqPath + private[this] implicit class ToSeqPathOps[T](val t: T) extends AnyVal { def toSeqPath(implicit toSeqPath: ToSeqPath[T]): Seq[Path] = toSeqPath(t) } @@ -137,19 +152,24 @@ private[sbt] object Clean { private[sbt] def cleanFileOutputTask[T: JsonFormat: ToSeqPath]( taskKey: TaskKey[T] ): Def.Initialize[Task[Unit]] = - Def.taskDyn { - val scope = taskKey.scope in taskKey.key - Def.task { - val targetDir = (scope / target).value.toPath - val filter = cleanFilter(scope).value - // We do not want to inadvertently delete files that are not in the target directory. - val excludeFilter: Path => Boolean = path => !path.startsWith(targetDir) || filter(path) - val delete = cleanDelete(scope).value - val st = (scope / streams).value - taskKey.previous.foreach(_.toSeqPath.foreach(p => if (!excludeFilter(p)) delete(p))) - delete(st.cacheDirectory.toPath / Previous.DependencyDirectory) + (Def + .task { + taskKey.scope in taskKey.key + }) + .flatMapTask { case scope => + Def.task { + val targetDir = (scope / target).value.toPath + val filter = cleanFilter(scope).value + // We do not want to inadvertently delete files that are not in the target directory. + val excludeFilter: Path => Boolean = path => !path.startsWith(targetDir) || filter(path) + val delete = cleanDelete(scope).value + val st = (scope / streams).value + taskKey.previous.foreach(_.toSeqPath.foreach(p => if (!excludeFilter(p)) delete(p))) + delete(st.cacheDirectory.toPath / Previous.DependencyDirectory) + } } - } tag Tags.Clean + .tag(Tags.Clean) + private[this] def tryDelete(debug: String => Unit): Path => Unit = path => { try { debug(s"clean -- deleting file $path") diff --git a/main/src/main/scala/sbt/internal/GlobalPlugin.scala b/main/src/main/scala/sbt/internal/GlobalPlugin.scala index 443141183..35c6beec6 100644 --- a/main/src/main/scala/sbt/internal/GlobalPlugin.scala +++ b/main/src/main/scala/sbt/internal/GlobalPlugin.scala @@ -74,6 +74,8 @@ object GlobalPlugin { import structure.{ data, root, rootProject } val p: Scope = Scope.GlobalScope in ProjectRef(root, rootProject(root)) + // If we reference it directly (if it's an executionRoot) then it forces an update, which is not what we want. + val updateReport = (Def.task { () }).flatMapTask { case _ => Def.task { update.value } } val taskInit = Def.task { val intcp = (Runtime / internalDependencyClasspath).value val prods = (Runtime / exportedProducts).value diff --git a/main/src/main/scala/sbt/internal/TaskSequential.scala b/main/src/main/scala/sbt/internal/TaskSequential.scala index 628652dda..eeb5831b2 100644 --- a/main/src/main/scala/sbt/internal/TaskSequential.scala +++ b/main/src/main/scala/sbt/internal/TaskSequential.scala @@ -770,8 +770,7 @@ trait TaskSequential { tasks.toList match { case Nil => Def.task { last.value } case x :: xs => - Def.taskDyn { - Def.unit(x.value) + Def.task { Def.unit(x.value) }.flatMapTask { case _ => sequential(xs, last) } } diff --git a/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala b/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala index 17d9868f0..812fdf5cb 100644 --- a/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala +++ b/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala @@ -36,10 +36,10 @@ private[sbt] object WatchTransitiveDependencies { withParams((e, cm) => Def.task(transitiveDynamicInputs(argumentsImpl(key, e, cm).value))) private def withParams[R]( f: (Extracted, CompiledMap) => Def.Initialize[Task[R]] - ): Def.Initialize[Task[R]] = Def.taskDyn { - val extracted = Project.extract(state.value) - f(extracted, compile(extracted.structure)) - } + ): Def.Initialize[Task[R]] = + Def.task { Project.extract(state.value) }.flatMapTask { extracted => + f(extracted, compile(extracted.structure)) + } private[sbt] def compile(structure: BuildStructure): CompiledMap = structure.compiledMap private[sbt] final class Arguments( @@ -76,20 +76,24 @@ private[sbt] object WatchTransitiveDependencies { ) } private val ShowTransitive = "(?:show)?(?:[ ]*)(.*)/(?:[ ]*)transitive(?:Inputs|Globs|Triggers)".r - private def arguments: Def.Initialize[Task[Arguments]] = Def.taskDyn { - Def.task { - val extracted = Project.extract(state.value) - val compiledMap = compile(extracted.structure) - state.value.currentCommand.map(_.commandLine) match { - case Some(ShowTransitive(key)) => - Parser.parse(key.trim, Act.scopedKeyParser(state.value)) match { - case Right(scopedKey) => argumentsImpl(scopedKey, extracted, compiledMap) - case _ => argumentsImpl(Keys.resolvedScoped.value, extracted, compiledMap) - } - case Some(_) => argumentsImpl(Keys.resolvedScoped.value, extracted, compiledMap) + private def arguments: Def.Initialize[Task[Arguments]] = + Def + .task { + val extracted = Project.extract(state.value) + val compiledMap = compile(extracted.structure) + val st = state.value + val rs = Keys.resolvedScoped.value + (extracted, compiledMap, st, rs) } - }.value - } + .flatMapTask { case (extracted, compiledMap, st, rs) => + st.currentCommand.map(_.commandLine) match + case Some(ShowTransitive(key)) => + Parser.parse(key.trim, Act.scopedKeyParser(st)) match + case Right(scopedKey) => argumentsImpl(scopedKey, extracted, compiledMap) + case _ => argumentsImpl(rs, extracted, compiledMap) + case Some(_) => argumentsImpl(rs, extracted, compiledMap) + } + private[sbt] def transitiveDynamicInputs(args: Arguments): Seq[DynamicInput] = { import args._ val taskScope = Project.fillTaskAxis(scopedKey).scope diff --git a/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala b/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala index ae36a2825..756f1e95e 100644 --- a/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala +++ b/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala @@ -198,24 +198,20 @@ object IvyXml { shadedConfigOpt: Option[Configuration] ): Setting[Task[T]] = task := task.dependsOn { - Def.taskDyn { - val doGen = useCoursier.value - if (doGen) - Def.task { - val currentProject = { - val proj = csrProject.value - val publications = csrPublications.value - proj.withPublications(publications) - } - IvyXml.writeFiles( - currentProject, - shadedConfigOpt, - sbt.Keys.ivySbt.value, - sbt.Keys.streams.value.log - ) + Def.taskIf { + if useCoursier.value then + val currentProject = { + val proj = csrProject.value + val publications = csrPublications.value + proj.withPublications(publications) } - else - Def.task(()) + IvyXml.writeFiles( + currentProject, + shadedConfigOpt, + sbt.Keys.ivySbt.value, + sbt.Keys.streams.value.log + ) + else () } }.value diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 16a2a76cd..fb20584d5 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -93,21 +93,26 @@ object BuildServerProtocol { bspSbtEnabled := true, bspFullWorkspace := bspFullWorkspaceSetting.value, bspWorkspace := bspFullWorkspace.value.scopes, - bspWorkspaceBuildTargets := Def.taskDyn { - val workspace = Keys.bspFullWorkspace.value - val state = Keys.state.value - val allTargets = ScopeFilter.in(workspace.scopes.values.toSeq) - val sbtTargets = workspace.builds.map { case (buildTargetIdentifier, loadedBuildUnit) => - val buildFor = workspace.buildToScope.getOrElse(buildTargetIdentifier, Nil) - sbtBuildTarget(loadedBuildUnit, buildTargetIdentifier, buildFor).result - }.toList - Def.task { - val buildTargets = Keys.bspBuildTarget.result.all(allTargets).value - val successfulBuildTargets = anyOrThrow(buildTargets ++ sbtTargets.join.value) - state.respondEvent(WorkspaceBuildTargetsResult(successfulBuildTargets.toVector)) - successfulBuildTargets + bspWorkspaceBuildTargets := (Def + .task { + val workspace = Keys.bspFullWorkspace.value + val state = Keys.state.value + val allTargets = ScopeFilter.in(workspace.scopes.values.toSeq) + val sbtTargets = workspace.builds.map { case (buildTargetIdentifier, loadedBuildUnit) => + val buildFor = workspace.buildToScope.getOrElse(buildTargetIdentifier, Nil) + sbtBuildTarget(loadedBuildUnit, buildTargetIdentifier, buildFor).result + }.toList + (workspace, state, allTargets, sbtTargets) } - }.value, + .flatMapTask { case (workspace, state, allTargets, sbtTargets) => + Def.task { + val buildTargets = Keys.bspBuildTarget.result.all(allTargets).value + val successfulBuildTargets = anyOrThrow(buildTargets ++ sbtTargets.join.value) + state.respondEvent(WorkspaceBuildTargetsResult(successfulBuildTargets.toVector)) + successfulBuildTargets + } + }) + .value, // https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request bspBuildTargetSources := bspInputTask { (state, _, workspace, filter) => // run the worker task concurrently @@ -588,44 +593,66 @@ object BuildServerProtocol { } } - private def buildTargetTask: Def.Initialize[Task[BuildTarget]] = Def.taskDyn { - val buildTargetIdentifier = Keys.bspTargetIdentifier.value - val thisProject = Keys.thisProject.value - val thisProjectRef = Keys.thisProjectRef.value - val thisConfig = Keys.configuration.value - val scalaJars = Keys.scalaInstance.value.allJars.map(_.toURI.toString) - val compileData = ScalaBuildTarget( - scalaOrganization = scalaOrganization.value, - scalaVersion = scalaVersion.value, - scalaBinaryVersion = scalaBinaryVersion.value, - platform = ScalaPlatform.JVM, - jars = scalaJars.toVector - ) - val configuration = Keys.configuration.value - val displayName = BuildTargetName.fromScope(thisProject.id, configuration.name) - val baseDirectory = Keys.baseDirectory.value.toURI - val projectDependencies = for { - (dep, configs) <- Keys.bspInternalDependencyConfigurations.value - config <- configs - if dep != thisProjectRef || config.name != thisConfig.name - } yield (dep / config / Keys.bspTargetIdentifier) - val capabilities = - BuildTargetCapabilities(canCompile = true, canTest = true, canRun = true, canDebug = false) - val tags = BuildTargetTag.fromConfig(configuration.name) - Def.task { - BuildTarget( - buildTargetIdentifier, - Some(displayName), - Some(baseDirectory), - tags, - capabilities, - BuildServerConnection.languages, - projectDependencies.join.value.distinct.toVector, - dataKind = Some("scala"), - data = Some(Converter.toJsonUnsafe(compileData)), - ) - } - } + private def buildTargetTask: Def.Initialize[Task[BuildTarget]] = + Def + .task { + val buildTargetIdentifier = Keys.bspTargetIdentifier.value + val thisProject = Keys.thisProject.value + val thisProjectRef = Keys.thisProjectRef.value + val thisConfig = Keys.configuration.value + val scalaJars = Keys.scalaInstance.value.allJars.map(_.toURI.toString) + val compileData = ScalaBuildTarget( + scalaOrganization = scalaOrganization.value, + scalaVersion = scalaVersion.value, + scalaBinaryVersion = scalaBinaryVersion.value, + platform = ScalaPlatform.JVM, + jars = scalaJars.toVector + ) + val configuration = Keys.configuration.value + val displayName = BuildTargetName.fromScope(thisProject.id, configuration.name) + val baseDirectory = Keys.baseDirectory.value.toURI + val projectDependencies = for { + (dep, configs) <- Keys.bspInternalDependencyConfigurations.value + config <- configs + if dep != thisProjectRef || config.name != thisConfig.name + } yield (dep / config / Keys.bspTargetIdentifier) + val capabilities = + BuildTargetCapabilities(canCompile = true, canTest = true, canRun = true, canDebug = false) + val tags = BuildTargetTag.fromConfig(configuration.name) + ( + buildTargetIdentifier, + displayName, + baseDirectory, + tags, + capabilities, + projectDependencies, + compileData + ) + } + .flatMapTask { + case ( + buildTargetIdentifier, + displayName, + baseDirectory, + tags, + capabilities, + projectDependencies, + compileData + ) => + Def.task { + BuildTarget( + buildTargetIdentifier, + Some(displayName), + Some(baseDirectory), + tags, + capabilities, + BuildServerConnection.languages, + projectDependencies.join.value.distinct.toVector, + dataKind = Some("scala"), + data = Some(Converter.toJsonUnsafe(compileData)), + ) + } + } private def sbtBuildTarget( loadedUnit: LoadedBuildUnit, @@ -701,28 +728,44 @@ object BuildServerProtocol { ) } - private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn { - val target = Keys.bspTargetIdentifier.value - val scalacOptions = Keys.scalacOptions.value - val classDirectory = Keys.classDirectory.value - val externalDependencyClasspath = Keys.externalDependencyClasspath.value - - val internalDependencyClasspath = for { - (ref, configs) <- bspInternalDependencyConfigurations.value - config <- configs - } yield ref / config / Keys.classDirectory - - Def.task { - val classpath = internalDependencyClasspath.join.value.distinct ++ - externalDependencyClasspath.map(_.data) - ScalacOptionsItem( - target, - scalacOptions.toVector, - classpath.map(_.toURI).toVector, - classDirectory.toURI - ) - } - } + private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = + Def + .task { + val target = Keys.bspTargetIdentifier.value + val scalacOptions = Keys.scalacOptions.value + val classDirectory = Keys.classDirectory.value + val externalDependencyClasspath = Keys.externalDependencyClasspath.value + val internalDependencyClasspath = for { + (ref, configs) <- bspInternalDependencyConfigurations.value + config <- configs + } yield ref / config / Keys.classDirectory + ( + target, + scalacOptions, + classDirectory, + externalDependencyClasspath, + internalDependencyClasspath + ) + } + .flatMapTask { + case ( + target, + scalacOptions, + classDirectory, + externalDependencyClasspath, + internalDependencyClasspath + ) => + Def.task { + val classpath = internalDependencyClasspath.join.value.distinct ++ + externalDependencyClasspath.map(_.data) + ScalacOptionsItem( + target, + scalacOptions.toVector, + classpath.map(_.toURI).toVector, + classDirectory.toURI + ) + } + } private def dependencySourcesItemTask: Def.Initialize[Task[DependencySourcesItem]] = Def.task { val targetId = Keys.bspTargetIdentifier.value