Use flatMapTask instead of taskDyn

This commit is contained in:
Eugene Yokota 2022-09-21 05:07:49 -04:00
parent e9490e203b
commit 100f1ac09c
17 changed files with 504 additions and 390 deletions

View File

@ -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

View File

@ -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 _.==)

View File

@ -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))
}

View File

@ -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)
},

View File

@ -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
)
}
/**

View File

@ -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

View File

@ -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 := {

View File

@ -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

View File

@ -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
}
}
}
}

View File

@ -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."

View File

@ -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,

View File

@ -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")

View File

@ -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

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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