Merge branch 'develop' into wip/query

This commit is contained in:
eugene yokota 2024-10-01 16:47:49 -04:00 committed by Eugene Yokota
commit 59099cb3af
67 changed files with 319 additions and 290 deletions

View File

@ -186,7 +186,7 @@ You'd need alternative DSL import since you can't rely on sbt package object.
```scala
// for slash syntax
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
// for IO
import sbt.io.syntax._

View File

@ -23,7 +23,7 @@ import java.nio.file.Path
import sbt.internal.util.complete.DefaultParsers.validID
import Def.{ ScopedKey, Setting }
import Scope.GlobalScope
import sbt.SlashSyntax0.*
import sbt.SlashSyntax0.given
import sbt.internal.parser.SbtParser
import sbt.io.IO
import scala.jdk.CollectionConverters.*

View File

@ -101,6 +101,10 @@ abstract class CommandChannel {
}
private[sbt] def terminal: Terminal
private[sbt] var _active: Boolean = true
private[sbt] def pause(): Unit = _active = false
private[sbt] def isPaused: Boolean = !_active
private[sbt] def resume(): Unit = _active = true
}
// case class Exec(commandLine: String, source: Option[CommandSource])

View File

@ -11,7 +11,7 @@ package sbt
import sbt.Def.{ Initialize, ScopedKey }
import sbt.Previous._
import sbt.Scope.Global
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.util._
import sbt.std.TaskExtra._
import sbt.util.StampedFormat

View File

@ -14,8 +14,7 @@ import java.net.URI
import sbt.internal.util.AttributeKey
import sbt.io.IO
import sbt.librarymanagement.Configuration
import sbt.SlashSyntax.{ RichConfiguration, RichScope }
import scala.annotation.nowarn
import sbt.SlashSyntax.RichConfiguration
// in all of these, the URI must be resolved and normalized before it is definitive
@ -26,20 +25,17 @@ sealed trait Reference:
private[sbt] def asScope: Scope =
Scope(asScopeAxis, This, This, This)
@nowarn
def /(c: ConfigKey): RichConfiguration = RichConfiguration(asScope in c)
def /(c: ConfigKey): RichConfiguration = RichConfiguration(asScope.rescope(c))
@nowarn
def /(c: Configuration): RichConfiguration = RichConfiguration(asScope in c)
def /(c: Configuration): RichConfiguration = RichConfiguration(asScope.rescope(c))
// This is for handling `Zero / Zero / name`.
def /(configAxis: ScopeAxis[ConfigKey]): RichConfiguration =
new RichConfiguration(asScope.copy(config = configAxis))
final def /[K](key: Scoped.ScopingSetting[K]): K = key.in(asScope)
final def /[K](key: Scoped.ScopingSetting[K]): K = key.rescope(asScope)
@nowarn
final def /(key: AttributeKey[_]): RichScope = new RichScope(asScope in key)
final def /(key: AttributeKey[_]): Scope = asScope.rescope(key)
end Reference
/** A fully resolved, unique identifier for a project or build. */

View File

@ -20,39 +20,18 @@ final case class Scope(
config: ScopeAxis[ConfigKey],
task: ScopeAxis[AttributeKey[_]],
extra: ScopeAxis[AttributeMap]
) {
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(project: Reference, config: ConfigKey): Scope =
copy(project = Select(project), config = Select(config))
):
def rescope(project: Reference): Scope = copy(project = Select(project))
def rescope(config: ConfigKey): Scope = copy(config = Select(config))
def rescope(task: AttributeKey[?]): Scope = copy(task = Select(task))
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(config: ConfigKey, task: AttributeKey[_]): Scope =
copy(config = Select(config), task = Select(task))
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(project: Reference, task: AttributeKey[_]): Scope =
copy(project = Select(project), task = Select(task))
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(project: Reference, config: ConfigKey, task: AttributeKey[_]): Scope =
copy(project = Select(project), config = Select(config), task = Select(task))
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(project: Reference): Scope = copy(project = Select(project))
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(config: ConfigKey): Scope = copy(config = Select(config))
@deprecated(Scope.inIsDeprecated, "1.5.0")
def in(task: AttributeKey[_]): Scope = copy(task = Select(task))
override def toString: String = this match {
override def toString: String = this match
case Scope(Zero, Zero, Zero, Zero) => "Global"
case Scope(_, _, _, This) => s"$project / $config / $task"
case _ => s"Scope($project, $config, $task, $extra)"
}
}
object Scope {
end Scope
object Scope:
val ThisScope: Scope = Scope(This, This, This, This)
val Global: Scope = Scope(Zero, Zero, Zero, Zero)
val GlobalScope: Scope = Global
@ -457,4 +436,4 @@ object Scope {
t <- withZeroAxis(scope.task)
e <- withZeroAxis(scope.extra)
} yield Scope(Zero, c, t, e)
}
end Scope

View File

@ -10,7 +10,6 @@ package sbt
import sbt.librarymanagement.Configuration
import sbt.internal.util.AttributeKey
import scala.annotation.nowarn
/**
* SlashSyntax implements the slash syntax to scope keys for build.sbt DSL.
@ -29,59 +28,60 @@ import scala.annotation.nowarn
* Zero / Zero / name := "foo"
* }}}
*/
trait SlashSyntax {
import SlashSyntax._
trait SlashSyntax:
import SlashSyntax.*
implicit def sbtSlashSyntaxRichReferenceAxis(a: ScopeAxis[Reference]): RichReference =
new RichReference(Scope(a, This, This, This))
given Conversion[ScopeAxis[Reference], RichReference] =
(a: ScopeAxis[Reference]) => RichReference(Scope(a, This, This, This))
// implicit def sbtSlashSyntaxRichReference(r: Reference): RichReference = Select(r)
// Implement in Reference directly
// given sbtSlashSyntaxRichReference: Conversion[Reference, RichReference] =
// (r: Reference) => Select(r)
given sbtSlashSyntaxRichProject[A](using Conversion[A, Reference]): Conversion[A, RichReference] =
given [A](using Conversion[A, Reference]): Conversion[A, RichReference] =
(a: A) => Select(a: Reference)
implicit def sbtSlashSyntaxRichConfigKey(c: ConfigKey): RichConfiguration =
new RichConfiguration(Scope(This, Select(c), This, This))
given Conversion[Reference, RichReference] =
(r: Reference) => Select(r)
implicit def sbtSlashSyntaxRichConfiguration(c: Configuration): RichConfiguration = (c: ConfigKey)
given Conversion[ConfigKey, RichConfiguration] =
(c: ConfigKey) => RichConfiguration(Scope(This, Select(c), This, This))
implicit def sbtSlashSyntaxRichScope(s: Scope): RichScope = new RichScope(s)
given Conversion[Configuration, RichConfiguration] =
(c: Configuration) => (c: ConfigKey)
/**
* This handles task scoping an existing scoped key (such as `Compile / test`)
* into a task scoping in `(Compile / test) / name`.
*/
implicit def sbtSlashSyntaxRichScopeFromScoped(t: Scoped): RichScope =
new RichScope(t.scope.copy(task = Select(t.key)))
given Conversion[Scoped, Scope] =
(t: Scoped) => t.scope.copy(task = Select(t.key))
implicit def sbtSlashSyntaxRichScopeFromAttributeKey(a: AttributeKey[_]): RichScope =
Scope(This, This, Select(a), This)
given Conversion[Scoped, RichScope] =
(t: Scoped) => RichScope(t: Scope)
}
given [A1]: Conversion[AttributeKey[A1], Scope] =
(a: AttributeKey[A1]) => Scope(This, This, Select(a), This)
object SlashSyntax {
given [A1]: Conversion[AttributeKey[A1], RichScope] =
(a: AttributeKey[A1]) => RichScope(a: Scope)
given Conversion[Scope, RichScope] =
(scope: Scope) => RichScope(scope)
end SlashSyntax
object SlashSyntax:
sealed trait HasSlashKey {
protected def scope: Scope
final def /[K](key: Scoped.ScopingSetting[K]): K = key.in(scope)
def /[K](key: Scoped.ScopingSetting[K]): K = key.rescope(scope)
}
sealed trait HasSlashKeyOrAttrKey extends HasSlashKey {
@nowarn
final def /(key: AttributeKey[_]): RichScope = new RichScope(scope in key)
def /(key: AttributeKey[_]): Scope = scope.rescope(key)
}
/** RichReference wraps a reference to provide the `/` operator for scoping. */
final class RichReference(protected val scope: Scope) extends HasSlashKeyOrAttrKey {
@nowarn
def /(c: ConfigKey): RichConfiguration = new RichConfiguration(scope in c)
def /(c: ConfigKey): RichConfiguration = new RichConfiguration(scope.rescope(c))
@nowarn
def /(c: Configuration): RichConfiguration = new RichConfiguration(scope in c)
def /(c: Configuration): RichConfiguration = new RichConfiguration(scope.rescope(c))
// This is for handling `Zero / Zero / name`.
def /(configAxis: ScopeAxis[ConfigKey]): RichConfiguration =
@ -91,13 +91,15 @@ object SlashSyntax {
/** RichConfiguration wraps a configuration to provide the `/` operator for scoping. */
final class RichConfiguration(protected val scope: Scope) extends HasSlashKeyOrAttrKey {
// This is for handling `Zero / Zero / Zero / name`.
def /(taskAxis: ScopeAxis[AttributeKey[_]]): RichScope =
new RichScope(scope.copy(task = taskAxis))
def /(taskAxis: ScopeAxis[AttributeKey[_]]): Scope =
scope.copy(task = taskAxis)
}
/** RichScope wraps a general scope to provide the `/` operator for scoping. */
/**
* RichScope wraps a general scope to provide the `/` operator for scoping.
*/
final class RichScope(protected val scope: Scope) extends HasSlashKeyOrAttrKey
}
end SlashSyntax
private[sbt] object SlashSyntax0 extends SlashSyntax

View File

@ -72,10 +72,12 @@ sealed abstract class SettingKey[A1]
final def scopedKey: ScopedKey[A1] = ScopedKey(scope, key)
// @deprecated(Scope.inIsDeprecated, "1.5.0")
final def in(scope: Scope): SettingKey[A1] =
private[sbt] final inline def rescope(scope: Scope): SettingKey[A1] =
Scoped.scopedSetting(Scope.replaceThis(this.scope)(scope), this.key)
final def /[A1](subkey: Scoped.ScopingSetting[A1]): A1 =
subkey.rescope(scope.copy(task = Select(key)))
/** Internal function for the setting macro. */
inline def settingMacro[A](inline a: A): Initialize[A] =
${ std.SettingMacro.settingMacroImpl[A]('a) }
@ -151,10 +153,12 @@ sealed abstract class TaskKey[A1]
def scopedKey: ScopedKey[Task[A1]] = ScopedKey(scope, key)
// @deprecated(Scope.inIsDeprecated, "1.5.0")
def in(scope: Scope): TaskKey[A1] =
private[sbt] final inline def rescope(scope: Scope): TaskKey[A1] =
Scoped.scopedTask(Scope.replaceThis(this.scope)(scope), this.key)
final def /[A1](subkey: Scoped.ScopingSetting[A1]): A1 =
subkey.rescope(scope.copy(task = Select(key)))
inline def +=[A2](inline v: A2)(using Append.Value[A1, A2]): Setting[Task[A1]] =
append1[A2](taskMacro(v))
@ -232,10 +236,12 @@ sealed trait InputKey[A1]
def scopedKey: ScopedKey[InputTask[A1]] = ScopedKey(scope, key)
// @deprecated(Scope.inIsDeprecated, "1.5.0")
def in(scope: Scope): InputKey[A1] =
private[sbt] final inline def rescope(scope: Scope): InputKey[A1] =
Scoped.scopedInput(Scope.replaceThis(this.scope)(scope), this.key)
final def /[A1](subkey: Scoped.ScopingSetting[A1]): A1 =
subkey.rescope(scope.copy(task = Select(key)))
private inline def inputTaskMacro[A2](inline a: A2): Def.Initialize[InputTask[A2]] =
${ std.InputTaskMacro.inputTaskMacroImpl('a) }
@ -261,52 +267,11 @@ object Scoped:
ScopedKey(s.scope, s.key)
/**
* Mixin trait for adding convenience vocabulary associated with specifying the [[Scope]] of a setting.
* Allows specification of the Scope or part of the [[Scope]] of a setting being referenced.
* @example
* {{{
* name in Global := "hello Global scope"
*
* name in (Compile, packageBin) := "hello Compile scope packageBin"
*
* name in Compile := "hello Compile scope"
*
* name.in(Compile).:=("hello ugly syntax")
* }}}
* A trait that provides rescope method.
*/
sealed trait ScopingSetting[ResultType]:
private[sbt] def in(s: Scope): ResultType
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(s: Scope): ResultType
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(p: Reference): ResultType = in(Select(p), This, This)
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(t: Scoped): ResultType = in(This, This, Select(t.key))
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(c: ConfigKey): ResultType = in(This, Select(c), This)
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(c: ConfigKey, t: Scoped): ResultType = in(This, Select(c), Select(t.key))
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(p: Reference, c: ConfigKey): ResultType = in(Select(p), Select(c), This)
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(p: Reference, t: Scoped): ResultType = in(Select(p), This, Select(t.key))
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(p: Reference, c: ConfigKey, t: Scoped): ResultType =
// in(Select(p), Select(c), Select(t.key))
// @deprecated(Scope.inIsDeprecated, "1.5.0")
// def in(
// p: ScopeAxis[Reference],
// c: ScopeAxis[ConfigKey],
// t: ScopeAxis[AttributeKey[_]]
// ): ResultType = in(Scope(p, c, t, This))
// formerly known as "in"
private[sbt] def rescope(s: Scope): ResultType
end ScopingSetting
def scopedSetting[T](s: Scope, k: AttributeKey[T]): SettingKey[T] =
@ -382,8 +347,6 @@ object Scoped:
protected def onTask[A2](f: Task[A1] => Task[A2]): Initialize[Task[A2]] =
init.apply(f)
def dependsOn(tasks: Initialize[? <: Task[?]]*): Initialize[Task[A1]] =
init.zipWith(tasks.asInstanceOf[Seq[Initialize[Task[?]]]].join)(_.dependsOn(_*))
def flatMapTaskValue[T](f: A1 => Task[T]): Initialize[Task[T]] =
onTask(_.result flatMap (f compose successM))
def map[A2](f: A1 => A2): Initialize[Task[A2]] =
@ -398,6 +361,8 @@ object Scoped:
def tagw(tags: (Tag, Int)*): Initialize[Task[A1]] = onTask(_.tagw(tags: _*))
// Task-specific extensions
def dependsOn(tasks: Initialize[? <: Task[?]]*): Initialize[Task[A1]] =
init.zipWith(tasks.asInstanceOf[Seq[Initialize[Task[?]]]].join)(_.dependsOn(_*))
def dependsOnTask[A2](task1: Initialize[Task[A2]]): Initialize[Task[A1]] =
dependsOnSeq(Seq[AnyInitTask](task1.asInstanceOf[AnyInitTask]))
def dependsOnSeq(tasks: Seq[AnyInitTask]): Initialize[Task[A1]] =
@ -443,6 +408,11 @@ object Scoped:
def tagw(tags: (Tag, Int)*): Initialize[InputTask[A1]] = onTask(_.tagw(tags: _*))
// InputTask specific extensions
@targetName("dependsOnInitializeInputTask")
def dependsOn(tasks: Initialize[? <: Task[?]]*): Initialize[InputTask[A1]] =
init.zipWith(tasks.asInstanceOf[Seq[Initialize[Task[?]]]].join)((thisTask, deps) =>
thisTask.mapTask(_.dependsOn(deps*))
)
@targetName("dependsOnTaskInitializeInputTask")
def dependsOnTask[B1](task1: Initialize[Task[B1]]): Initialize[InputTask[A1]] =
dependsOnSeq(Seq[AnyInitTask](task1.asInstanceOf[AnyInitTask]))

View File

@ -62,7 +62,11 @@ private[sbt] object KeyMacro:
if term.isValDef then Expr(term.name)
else errorAndAbort(errorMsg)
def enclosingTerm(using qctx: Quotes) =
private[sbt] def callerThis(using Quotes): Expr[Any] =
import quotes.reflect.*
This(enclosingClass).asExpr
private def enclosingTerm(using qctx: Quotes) =
import qctx.reflect._
def enclosingTerm0(sym: Symbol): Symbol =
sym match
@ -70,4 +74,11 @@ private[sbt] object KeyMacro:
case sym if !sym.isTerm => enclosingTerm0(sym.owner)
case _ => sym
enclosingTerm0(Symbol.spliceOwner)
private def enclosingClass(using Quotes) =
import quotes.reflect.*
def rec(sym: Symbol): Symbol =
if sym.isClassDef then sym
else rec(sym.owner)
rec(Symbol.spliceOwner)
end KeyMacro

View File

@ -12,7 +12,7 @@ object AppendSpec {
val onLoad = SettingKey[State => State]("onLoad")
import Scope.Global
import SlashSyntax0._
import SlashSyntax0.given
def doSideEffect(): Unit = ()

View File

@ -86,6 +86,8 @@ abstract class BackgroundJobService extends Closeable {
hashContents: Boolean,
converter: FileConverter,
): Classpath = copyClasspath(products, full, workingDirectory, converter)
private[sbt] def pauseChannelDuringJob(state: State, handle: JobHandle): Unit
}
object BackgroundJobService {
@ -108,3 +110,10 @@ abstract class JobHandle {
def humanReadableName: String
def spawningTask: ScopedKey[_]
}
/**
* This datatype is used signal the task engine or the commands
* that the background job is emulated to be a foreground job on
* the originating channel.
*/
case class EmulateForeground(handle: JobHandle)

View File

@ -12,7 +12,7 @@ import java.io.File
import sbt.Def.{ ScopedKey, Setting }
import sbt.Keys._
import sbt.ProjectExtra.extract
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.Act
import sbt.internal.CommandStrings._
import sbt.internal.inc.ScalaInstance

View File

@ -97,7 +97,7 @@ import scala.util.control.NonFatal
import scala.xml.NodeSeq
// incremental compiler
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.inc.{
Analysis,
AnalyzingCompiler,
@ -1051,6 +1051,12 @@ object Defaults extends BuildCommon {
},
runMain := foregroundRunMainTask.evaluated,
run := foregroundRunTask.evaluated,
runBlock := {
val r = run.evaluated
val service = bgJobService.value
service.waitForTry(r.handle).get
r
},
fgRun := runTask(fullClasspath, (run / mainClass), (run / runner)).evaluated,
fgRunMain := runMainTask(fullClasspath, (run / runner)).evaluated,
copyResources := copyResourcesTask.value,
@ -1508,7 +1514,7 @@ object Defaults extends BuildCommon {
@nowarn
def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] =
inputTests0.mapReferenced(Def.mapScope(_ in key.key))
inputTests0.mapReferenced(Def.mapScope((s) => s.rescope(key.key)))
private[this] lazy val inputTests0: Initialize[InputTask[Unit]] = {
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
@ -2143,21 +2149,18 @@ object Defaults extends BuildCommon {
}
}
// runMain calls bgRunMain in the background and waits for the result.
def foregroundRunMainTask: Initialize[InputTask[Unit]] =
Def.inputTask[Unit] {
// `runMain` calls bgRunMain in the background and pauses the current channel
def foregroundRunMainTask: Initialize[InputTask[EmulateForeground]] =
Def.inputTask {
val handle = bgRunMain.evaluated
val service = bgJobService.value
service.waitForTry(handle).get
()
EmulateForeground(handle)
}
// run calls bgRun in the background and waits for the result.
def foregroundRunTask: Initialize[InputTask[Unit]] =
// `run` task calls bgRun in the background and pauses the current channel
def foregroundRunTask: Initialize[InputTask[EmulateForeground]] =
Def.inputTask {
val handle = bgRun.evaluated
val service = bgJobService.value
service.waitForTry(handle).get
EmulateForeground(handle)
}
def runMainTask(
@ -5006,7 +5009,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
.flatMapTask { result =>
initScoped(
scoped.scopedKey,
ClassLoaders.runner mapReferenced Project.mapScope(s => s.in(config)),
ClassLoaders.runner mapReferenced Project.mapScope(_.rescope(config)),
).zipWith(Def.task {
((config / fullClasspath).value, streams.value, fileConverter.value, result)
}) { (rTask, t) =>
@ -5022,7 +5025,6 @@ trait BuildExtra extends BuildCommon with DefExtra {
// public API
/** Returns a vector of settings that create custom run task. */
@nowarn
def fullRunTask(
scoped: TaskKey[Unit],
config: Configuration,
@ -5032,7 +5034,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
Vector(
scoped := initScoped(
scoped.scopedKey,
ClassLoaders.runner mapReferenced Project.mapScope(s => s.in(config)),
ClassLoaders.runner mapReferenced Project.mapScope(_.rescope(config)),
).zipWith(Def.task { ((config / fullClasspath).value, streams.value, fileConverter.value) }) {
case (rTask, t) =>
(t, rTask).mapN { case ((cp, s, converter), r) =>

View File

@ -16,7 +16,7 @@ import sbt.Keys.{ TaskProgress => _, name => _, _ }
import sbt.BuildExtra.*
import sbt.ProjectExtra.*
import sbt.Scope.Global
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.Aggregation.KeyValue
import sbt.internal.TaskName._
import sbt.internal._
@ -512,6 +512,16 @@ object EvaluateTask {
case Some(t: Task[?]) => transformNode(t).isEmpty
case _ => true
}
def suspendChannel[A1](
state: State,
result: Result[A1]
): Unit =
(state.getSetting(Global / Keys.bgJobService), result) match
case (Some(service), Result.Value(List(KeyValue(_, EmulateForeground(handle))))) =>
state.remainingCommands match
case Nil => service.waitForTry(handle).get
case _ => service.pauseChannelDuringJob(state, handle)
case _ => ()
def run() = {
val x = new Execute(
Execute.config(config.checkCycles, overwriteNode),
@ -529,6 +539,7 @@ object EvaluateTask {
} finally shutdown()
val replaced = transformInc(result)
logIncResult(replaced, state, streams)
suspendChannel(newState, replaced)
(newState, replaced)
}
object runningEngine extends RunningTaskEngine {

View File

@ -17,7 +17,7 @@ import sbt.util.Show
import std.Transform.DummyTaskMap
import sbt.EvaluateTask.extractedTaskConfig
import sbt.ProjectExtra.setProject
import scala.annotation.nowarn
import sbt.SlashSyntax0.given
final case class Extracted(
structure: BuildStructure,
@ -46,9 +46,9 @@ final case class Extracted(
def getOpt[T](key: TaskKey[T]): Option[Task[T]] =
structure.data.get(inCurrent(key.scope), key.key)
@nowarn
private[this] def inCurrent(scope: Scope): Scope =
if (scope.project == This) scope in currentRef else scope
if scope.project == This then scope.rescope(currentRef)
else scope
/**
* Runs the task specified by `key` and returns the transformed State and the resulting value of the task.
@ -114,7 +114,7 @@ final case class Extracted(
)
private[this] def resolve[K <: Scoped.ScopingSetting[K] with Scoped](key: K): K =
key in Scope.resolveScope(GlobalScope, currentRef.build, rootProject)(key.scope)
Scope.resolveScope(GlobalScope, currentRef.build, rootProject)(key.scope) / key
private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T])(implicit
display: Show[ScopedKey[_]]

View File

@ -318,8 +318,9 @@ object Keys {
// Run Keys
val selectMainClass = taskKey[Option[String]]("Selects the main class to run.").withRank(BMinusTask)
val mainClass = taskKey[Option[String]]("Defines the main class for packaging or running.").withRank(BPlusTask)
val run = inputKey[Unit]("Runs a main class, passing along arguments provided on the command line.").withRank(APlusTask)
val runMain = inputKey[Unit]("Runs the main class selected by the first argument, passing the remaining arguments to the main method.").withRank(ATask)
val run = inputKey[EmulateForeground]("Runs a main class, passing along arguments provided on the command line.").withRank(APlusTask)
val runBlock = inputKey[EmulateForeground]("Runs a main class, and blocks until it's done.").withRank(DTask)
val runMain = inputKey[EmulateForeground]("Runs the main class selected by the first argument, passing the remaining arguments to the main method.").withRank(ATask)
val discoveredMainClasses = taskKey[Seq[String]]("Auto-detects main classes.").withRank(BMinusTask)
val runner = taskKey[ScalaRun]("Implementation used to run a main class.").withRank(DTask)
val trapExit = settingKey[Boolean]("If true, enables exit trapping and thread management for 'run'-like tasks. This was removed in sbt 1.6.0 due to JDK 17 deprecating Security Manager.").withRank(CSetting)

View File

@ -13,7 +13,7 @@ import DefaultParsers._
import sbt.Keys._
import Scope.GlobalScope
import Def.ScopedKey
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.Load
import sbt.internal.CommandStrings._
import Cross.{ spacedFirst, requireSession }

View File

@ -37,7 +37,7 @@ import Keys.{
}
import Project.LoadAction
import Scope.{ Global, ThisScope }
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import Def.{ Flattened, Initialize, ScopedKey, Setting }
import sbt.internal.{
Load,

View File

@ -253,6 +253,7 @@ object ProjectMatrix {
val plugins: Plugins,
val transforms: Seq[Project => Project],
val defAxes: Seq[VirtualAxis],
val pluginClassLoader: ClassLoader
) extends ProjectMatrix { self =>
lazy val resolvedMappings: ListMap[ProjectRow, Project] = resolveMappings
private def resolveProjectIds: Map[ProjectRow, String] = {
@ -470,7 +471,7 @@ object ProjectMatrix {
private def enableScalaJSPlugin(project: Project): Project =
project.enablePlugins(
scalajsPlugin(this.getClass.getClassLoader).getOrElse(
scalajsPlugin.getOrElse(
sys.error(
"""Scala.js plugin was not found. Add the sbt-scalajs plugin into project/plugins.sbt:
| addSbtPlugin("org.scala-js" % "sbt-scalajs" % "x.y.z")
@ -517,9 +518,9 @@ object ProjectMatrix {
override def defaultAxes(axes: VirtualAxis*): ProjectMatrix =
copy(defAxes = axes.toSeq)
def scalajsPlugin(classLoader: ClassLoader): Try[AutoPlugin] = {
def scalajsPlugin: Try[AutoPlugin] = {
import ReflectionUtil.*
withContextClassloader(classLoader) { loader =>
withContextClassloader(pluginClassLoader) { loader =>
getSingletonObject[AutoPlugin](loader, "org.scalajs.sbtplugin.ScalaJSPlugin$")
}
}
@ -533,7 +534,7 @@ object ProjectMatrix {
private def enableScalaNativePlugin(project: Project): Project =
project.enablePlugins(
nativePlugin(this.getClass.getClassLoader).getOrElse(
nativePlugin.getOrElse(
sys.error(
"""Scala Native plugin was not found. Add the sbt-scala-native plugin into project/plugins.sbt:
| addSbtPlugin("org.scala-native" % "sbt-scala-native" % "x.y.z")
@ -577,9 +578,9 @@ object ProjectMatrix {
project => configure(enableScalaNativePlugin(project))
)
def nativePlugin(classLoader: ClassLoader): Try[AutoPlugin] = {
def nativePlugin: Try[AutoPlugin] = {
import ReflectionUtil.*
withContextClassloader(classLoader) { loader =>
withContextClassloader(pluginClassLoader) { loader =>
getSingletonObject[AutoPlugin](loader, "scala.scalanative.sbtplugin.ScalaNativePlugin$")
}
}
@ -678,6 +679,7 @@ object ProjectMatrix {
plugins: Plugins = plugins,
transforms: Seq[Project => Project] = transforms,
defAxes: Seq[VirtualAxis] = defAxes,
pluginClassLoader: ClassLoader = pluginClassLoader,
): ProjectMatrix = {
val matrix = unresolved(
id,
@ -693,6 +695,7 @@ object ProjectMatrix {
plugins,
transforms,
defAxes,
pluginClassLoader
)
allMatrices(id) = matrix
matrix
@ -700,7 +703,7 @@ object ProjectMatrix {
}
// called by macro
def apply(id: String, base: File): ProjectMatrix = {
def apply(id: String, base: File, pluginClassLoader: ClassLoader): ProjectMatrix = {
val defaultDefAxes = Seq(VirtualAxis.jvm, VirtualAxis.scalaABIVersion("3.3.3"))
val matrix = unresolved(
id,
@ -715,7 +718,8 @@ object ProjectMatrix {
Nil,
Plugins.Empty,
Nil,
defaultDefAxes
defaultDefAxes,
pluginClassLoader
)
allMatrices(id) = matrix
matrix
@ -735,6 +739,7 @@ object ProjectMatrix {
plugins: Plugins,
transforms: Seq[Project => Project],
defAxes: Seq[VirtualAxis],
pluginClassLoader: ClassLoader
): ProjectMatrix =
new ProjectMatrixDef(
id,
@ -750,6 +755,7 @@ object ProjectMatrix {
plugins,
transforms,
defAxes,
pluginClassLoader
)
def lookupMatrix(local: LocalProjectMatrix): ProjectMatrix = {
@ -799,7 +805,8 @@ object ProjectMatrix {
val name = std.KeyMacro.definingValName(
"projectMatrix must be directly assigned to a val, such as `val x = projectMatrix`. Alternatively, you can use `sbt.ProjectMatrix.apply`"
)
'{ ProjectMatrix($name, new File($name)) }
val callerThis = std.KeyMacro.callerThis
'{ ProjectMatrix($name, new File($name), $callerThis.getClass.getClassLoader) }
}
}

View File

@ -21,7 +21,7 @@ import sbt.Keys._
import sbt.Project.{ inConfig => _, * }
import sbt.ProjectExtra.*
import sbt.ScopeFilter.Make._
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.coursierint.LMCoursier
import sbt.internal.inc.{ HashUtil, JarUtils }
import sbt.internal.librarymanagement._
@ -206,9 +206,9 @@ object RemoteCache {
): Seq[Def.Setting[_]] =
inTask(packageCache)(
Seq(
packageCache.in(Defaults.TaskZero) := {
(Defaults.TaskZero / packageCache) := {
val converter = fileConverter.value
val original = packageBin.in(Defaults.TaskZero).value
val original = (Defaults.TaskZero / packageBin).value
val originalFile = converter.toPath(original)
val artp = artifactPath.value
val artpFile = converter.toPath(artp)
@ -243,7 +243,7 @@ object RemoteCache {
ModuleDescriptorConfiguration(remoteCacheProjectId.value, projectInfo.value)
.withScalaModuleInfo(smi)
},
pushRemoteCache.in(Defaults.TaskZero) := (Def.task {
(Defaults.TaskZero / pushRemoteCache) := (Def.task {
val s = streams.value
val config = pushRemoteCacheConfiguration.value
val is = (pushRemoteCache / ivySbt).value

View File

@ -15,7 +15,7 @@ import sbt.Keys._
import sbt.nio.Keys._
import sbt.ProjectExtra.*
import sbt.ScopeFilter.Make._
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.inc.ModuleUtilities
import sbt.internal.inc.classpath.ClasspathUtil
import sbt.internal.librarymanagement.cross.CrossVersionUtil

View File

@ -12,7 +12,6 @@ import java.lang.reflect.InvocationTargetException
import java.nio.file.Path
import java.io.File
import sbt.SlashSyntax0._
import sbt.io._, syntax._
import sbt.util._
import sbt.internal.util.{ ConsoleAppender, Terminal => ITerminal }

View File

@ -19,7 +19,6 @@ import lmcoursier.definitions.{
import sbt.librarymanagement._
import sbt.Keys._
import sbt.ProjectExtra.extract
import sbt.SlashSyntax0._
object CoursierArtifactsTasks {
def coursierPublicationsTask(

View File

@ -13,7 +13,6 @@ import sbt.librarymanagement._
import sbt.Keys._
import sbt.ProjectExtra.transitiveInterDependencies
import sbt.ScopeFilter.Make._
import sbt.SlashSyntax0._
object CoursierRepositoriesTasks {
private object CResolvers {

View File

@ -14,6 +14,7 @@ import java.text.DateFormat
import sbt.Def.ScopedKey
import sbt.Keys.{ showSuccess, showTiming, timingFormat }
import sbt.ProjectExtra.*
import sbt.SlashSyntax0.given
import sbt.internal.util.complete.Parser
import sbt.internal.util.complete.Parser.{ failure, seq, success }
import sbt.internal.util._
@ -79,13 +80,25 @@ object Aggregation {
val success = results match
case Result.Value(_) => true
case Result.Inc(_) => false
val isPaused = currentChannel(state) match
case Some(channel) => channel.isPaused
case None => false
results.toEither.foreach { r =>
if show.taskValues then printSettings(r, show.print) else ()
}
if show.success && !state.get(suppressShow).getOrElse(false) then
if !isPaused && show.success && !state.get(suppressShow).getOrElse(false) then
printSuccess(start, stop, extracted, success, cacheSummary, log)
else ()
private def currentChannel(state: State): Option[CommandChannel] =
state.currentCommand match
case Some(exec) =>
exec.source match
case Some(source) =>
StandardMain.exchange.channels.find(_.name == source.channelName)
case _ => None
case _ => None
def timedRun[A](
s: State,
ts: Values[Task[A]],
@ -290,7 +303,7 @@ object Aggregation {
}
def aggregationEnabled(key: ScopedKey[_], data: Settings[Scope]): Boolean =
Keys.aggregate in Scope.fillTaskAxis(key.scope, key.key) get data getOrElse true
(Scope.fillTaskAxis(key.scope, key.key) / Keys.aggregate).get(data).getOrElse(true)
private[sbt] val suppressShow =
AttributeKey[Boolean]("suppress-aggregation-show", Int.MaxValue)
}

View File

@ -16,6 +16,7 @@ import java.net.URI
import Def.{ ScopeLocal, ScopedKey, Setting, displayFull }
import BuildPaths.outputDirectory
import Scope.GlobalScope
import sbt.SlashSyntax0.given
import BuildStreams.Streams
import sbt.io.syntax._
import sbt.internal.inc.MappedFileConverter
@ -400,5 +401,5 @@ object BuildStreams {
refTarget(GlobalScope.copy(project = Select(ref)), fallbackBase, data)
def refTarget(scope: Scope, fallbackBase: File, data: Settings[Scope]): File =
(Keys.target in scope get data getOrElse outputDirectory(fallbackBase)) / StreamsDirectory
((scope / Keys.target).get(data) getOrElse outputDirectory(fallbackBase)) / StreamsDirectory
}

View File

@ -14,7 +14,7 @@ import java.net.URL
import java.nio.file.Path
import sbt.ClassLoaderLayeringStrategy._
import sbt.Keys._
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.classpath.ClassLoaderCache
import sbt.internal.inc.ScalaInstance
import sbt.internal.inc.classpath.ClasspathUtil

View File

@ -11,7 +11,6 @@ package internal
import java.io.File
import java.util.LinkedHashSet
import sbt.SlashSyntax0._
import sbt.Keys._
import sbt.nio.Keys._
import sbt.nio.file.{ Glob, RecursiveGlob }

View File

@ -16,7 +16,7 @@ import sbt.Def._
import sbt.Keys._
// import sbt.Project.richInitializeTask
import sbt.ProjectExtra.*
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.io.syntax._
import sbt.nio.Keys._
import sbt.nio.file._
@ -163,7 +163,7 @@ private[sbt] object Clean {
): Def.Initialize[Task[Unit]] =
(Def
.task {
taskKey.scope in taskKey.key
taskKey.scope / taskKey.key
})
.flatMapTask { case scope =>
Def.task {

View File

@ -146,10 +146,11 @@ private[sbt] final class CommandExchange {
}
private def addConsoleChannel(): Unit =
if (!Terminal.startedByRemoteClient) {
if Terminal.startedByRemoteClient then ()
else
val name = ConsoleChannel.defaultName
subscribe(new ConsoleChannel(name, mkAskUser(name)))
}
def run(s: State): State = run(s, s.get(autoStartServer).getOrElse(true))
def run(s: State, autoStart: Boolean): State = {
if (autoStartServerSysProp && autoStart) runServer(s)
@ -376,13 +377,14 @@ private[sbt] final class CommandExchange {
private[sbt] def setExec(exec: Option[Exec]): Unit = currentExecRef.set(exec.orNull)
def prompt(event: ConsolePromptEvent): Unit = {
def prompt(event: ConsolePromptEvent): Unit =
currentExecRef.set(null)
channels.foreach {
case c if ContinuousCommands.isInWatch(lastState.get, c) =>
case c => c.prompt(event)
case c =>
if c.isPaused then ()
else c.prompt(event)
}
}
def unprompt(event: ConsoleUnpromptEvent): Unit = channels.foreach(_.unprompt(event))
def logMessage(event: LogEvent): Unit = {

View File

@ -10,7 +10,6 @@ package sbt
package internal
import sbt.ProjectExtra.extract
import sbt.SlashSyntax0._
import sbt.internal.classpath.AlternativeZincUtil
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil }
import sbt.internal.util.Terminal

View File

@ -24,7 +24,7 @@ import sbt.BasicCommandStrings._
import sbt.Def._
import sbt.Keys._
import sbt.ProjectExtra.extract
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.Continuous.{ ContinuousState, FileStampRepository }
import sbt.internal.LabeledFunctions._
import sbt.internal.io.WatchState

View File

@ -18,7 +18,7 @@ import sbt.io.syntax._
import sbt.Cross._
import sbt.Def.{ ScopedKey, Setting }
import sbt.ProjectExtra.extract
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.util.complete.DefaultParsers._
import sbt.internal.util.AttributeKey
import sbt.internal.util.complete.{ DefaultParsers, Parser }

View File

@ -19,12 +19,12 @@ import java.util.concurrent.atomic.{ AtomicLong, AtomicReference }
import sbt.Def.{ Classpath, ScopedKey, Setting }
import sbt.ProjectExtra.extract
import sbt.Scope.GlobalScope
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.inc.classpath.ClasspathFilter
import sbt.internal.util.{ Attributed, ManagedLogger }
import sbt.io.syntax._
import sbt.io.{ Hash, IO }
import sbt.util.Logger
import sbt.util.{ Level, Logger }
import scala.concurrent.ExecutionContext
import scala.concurrent.duration._
@ -79,6 +79,9 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
private val nextId = new AtomicLong(1)
private val pool = new BackgroundThreadPool()
private val context = LoggerContext()
// EC for onStop handler below
given ExecutionContext =
ExecutionContext.fromExecutor(pool.executor)
private[sbt] def serviceTempDirBase: File
private[sbt] def useLog4J: Boolean
@ -119,10 +122,6 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
val workingDirectory: File,
val job: BackgroundJob
) extends AbstractJobHandle {
// EC for onStop handler below
implicit val executionContext: ExecutionContext =
ExecutionContext.fromExecutor(pool.executor)
def humanReadableName: String = job.humanReadableName
job.onStop { () =>
@ -306,6 +305,28 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
converter: FileConverter,
): Classpath =
copyClasspath(products, full, workingDirectory, hashFileContents = true, converter)
private[sbt] def pauseChannelDuringJob(state: State, handle: JobHandle): Unit =
currentChannel(state) match
case Some(channel) =>
handle match
case t: ThreadJobHandle =>
val level = channel.logLevel
channel.setLevel(Level.Error)
channel.pause()
t.job.onStop: () =>
channel.setLevel(level)
channel.resume()
channel.prompt(ConsolePromptEvent(state))
case _ => ()
case _ => ()
private[sbt] def currentChannel(state: State): Option[CommandChannel] =
state.currentCommand match
case Some(e: Exec) if e.source.isDefined =>
val source = e.source.get
StandardMain.exchange.channelForName(source.channelName)
case _ => None
}
private[sbt] object BackgroundThreadPool {

View File

@ -22,7 +22,7 @@ import Def.{ ScopedKey, Setting }
import Keys._
import Configurations.{ Compile, Runtime }
import sbt.ProjectExtra.{ extract, runUnloadHooks, setProject }
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import java.io.File
import org.apache.ivy.core.module.{ descriptor, id }
import descriptor.ModuleDescriptor, id.ModuleRevisionId
@ -74,7 +74,7 @@ object GlobalPlugin {
@nowarn
def extract(state: State, structure: BuildStructure): (State, GlobalPluginData) = {
import structure.{ data, root, rootProject }
val p: Scope = Scope.GlobalScope in ProjectRef(root, rootProject(root))
val p: Scope = Scope.GlobalScope.rescope(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 } }
@ -113,7 +113,7 @@ object GlobalPlugin {
}
@nowarn
val globalPluginSettings = Project.inScope(Scope.GlobalScope in LocalRootProject)(
val globalPluginSettings = Project.inScope(Scope.GlobalScope.rescope(LocalRootProject))(
Seq(
organization := SbtArtifacts.Organization,
onLoadMessage := Keys.baseDirectory("loading global plugins from " + _).value,

View File

@ -27,7 +27,7 @@ import Def.Setting
import Keys._
import Scope.Global
import sbt.ProjectExtra.{ extract, setProject }
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.io.IO

View File

@ -13,7 +13,6 @@ import java.io.File
import java.util.concurrent.Callable
import sbt.Def.ScopedKey
import sbt.SlashSyntax0._
import sbt.internal.librarymanagement._
import sbt.librarymanagement._
import sbt.librarymanagement.syntax._

View File

@ -15,7 +15,7 @@ import sbt.internal.util.{ FilePosition, NoPosition, SourcePosition }
import java.io.File
import ProjectExtra.{ extract, scopedKeyData }
import Scope.Global
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.Def._
object LintUnused {

View File

@ -15,7 +15,7 @@ import sbt.Keys._
import sbt.Project.inScope
import sbt.ProjectExtra.{ prefixConfigs, setProject, showLoadingKey, structure }
import sbt.Scope.GlobalScope
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.BuildStreams._
import sbt.internal.inc.classpath.ClasspathUtil
import sbt.internal.inc.{ MappedFileConverter, ScalaInstance, ZincLmUtil, ZincUtil }
@ -33,7 +33,7 @@ import xsbti.compile.{ ClasspathOptionsUtil, Compilers }
import java.io.File
import java.net.URI
import java.nio.file.{ Path, Paths }
import scala.annotation.{ nowarn, tailrec }
import scala.annotation.tailrec
import scala.collection.mutable
private[sbt] object Load {
@ -1318,8 +1318,7 @@ private[sbt] object Load {
case None => Nil
/** These are the settings defined when loading a project "meta" build. */
@nowarn
val autoPluginSettings: Seq[Setting[_]] = inScope(GlobalScope in LocalRootProject)(
val autoPluginSettings: Seq[Setting[_]] = inScope(GlobalScope.rescope(LocalRootProject))(
Seq(
sbtPlugin :== true,
isMetaBuild :== true,

View File

@ -13,7 +13,7 @@ import sbt.Def.ScopedKey
import sbt.Keys._
import sbt.ProjectExtra.showContextKey
import sbt.Scope.Global
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.util.MainAppender._
import sbt.internal.util.{ Terminal => ITerminal, _ }
import sbt.util.{ Level, Logger, LoggerContext }
@ -68,7 +68,7 @@ object LogManager {
(task: ScopedKey[_], to: PrintWriter) => {
val context = state.get(Keys.loggerContext).getOrElse(LoggerContext.globalContext)
val manager: LogManager =
(logManager in task.scope).get(data) getOrElse defaultManager(state.globalLogging.console)
(task.scope / logManager).get(data) getOrElse defaultManager(state.globalLogging.console)
manager(data, state, task, to, context)
}
@ -88,7 +88,7 @@ object LogManager {
): (ScopedKey[_]) => ManagedLogger =
(task: ScopedKey[_]) => {
val manager: LogManager =
(logManager in task.scope).get(data) getOrElse defaultManager(state.globalLogging.console)
(task.scope / logManager).get(data) getOrElse defaultManager(state.globalLogging.console)
manager.backgroundLog(data, state, task, context)
}

View File

@ -24,7 +24,7 @@ private[sbt] case class ProjectQuery(
val scalaMatches =
params.get(Keys.scalaBinaryVersion.key) match
case Some(expected) =>
val actualSbv = structure.data.get(Scope.ThisScope.in(p), scalaBinaryVersion.key)
val actualSbv = structure.data.get(Scope.ThisScope.rescope(p), scalaBinaryVersion.key)
actualSbv match
case Some(sbv) => sbv == expected
case None => true

View File

@ -19,7 +19,7 @@ import EvaluateConfigurations.{ evaluateConfiguration => evaluate }
import Configurations.Compile
import Scope.Global
import sbt.ProjectExtra.{ extract, setProject }
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.io.{ Hash, IO }

View File

@ -16,6 +16,7 @@ import sbt.librarymanagement.Configuration
import ProjectExtra.{ relation }
import Def.{ ScopedKey, Setting }
import Scope.Global
import sbt.SlashSyntax0.given
import complete._
import DefaultParsers._
@ -59,10 +60,8 @@ private[sbt] object SettingCompletions {
val global = ScopedKey(Global, akey)
val globalSetting = resolve(Def.setting(global, setting.init, setting.pos))
globalSetting ++ allDefs.flatMap { d =>
if (d.key == akey)
Seq(SettingKey(akey) in d.scope := { global.value })
else
Nil
if d.key == akey then Seq((d.scope / SettingKey(akey)) := global.value)
else Nil
}
}
val redefined = settings.flatMap(x => rescope(x))

View File

@ -13,6 +13,7 @@ import sbt.Def._
import sbt.Keys._
// import sbt.Project.richInitializeTask
import sbt.ProjectExtra.*
import sbt.SlashSyntax0.given
import sbt.internal.io.Source
import sbt.internal.nio.Globs
import sbt.internal.util.AttributeMap
@ -68,7 +69,7 @@ private[sbt] object WatchTransitiveDependencies {
stream.open()
stream
}).toTaskable,
(internalDependencyConfigurations in scopedKey.scope).toTaskable,
(scopedKey.scope / internalDependencyConfigurations).toTaskable,
state,
).mapN { case (log, configs, st) =>
new Arguments(
@ -166,7 +167,7 @@ private[sbt] object WatchTransitiveDependencies {
DynamicInput(glob, FileStamper.LastModified, forceTrigger = true)
scopes.flatMap {
case Left(scope) =>
extracted.runTask(Keys.watchSources in scope, state)._2.map(s => toDynamicInput(s.toGlob))
extracted.runTask(scope / Keys.watchSources, state)._2.map(s => toDynamicInput(s.toGlob))
case Right(globs) => globs.map(toDynamicInput)
}
}
@ -209,7 +210,9 @@ private[sbt] object WatchTransitiveDependencies {
val zeroedTaskScope = key.scope.copy(task = Zero)
val transitiveKeys = arguments.dependencyConfigurations.flatMap {
case (p, configs) =>
configs.map(c => ScopedKey(zeroedTaskScope in (p, ConfigKey(c)), task))
configs.map(c =>
ScopedKey(zeroedTaskScope.rescope(p).rescope(ConfigKey(c)), task)
)
}
(d ++ transitiveKeys.filterNot(newVisited), s)

View File

@ -19,7 +19,7 @@ import sbt.Project._
import sbt.ProjectExtra.*
import sbt.ScopeFilter.Make._
import sbt.Scoped.richTaskSeq
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.StandardMain.exchange
import sbt.internal.bsp._
import sbt.internal.langserver.ErrorCodes
@ -583,7 +583,7 @@ object BuildServerProtocol {
(ref, project) <- loadedBuild.allProjectRefs
setting <- project.settings
if setting.key.key.label == Keys.bspTargetIdentifier.key.label
} yield Scope.replaceThis(Scope.Global.in(ref))(setting.key.scope)
} yield Scope.replaceThis(Scope.Global.rescope(ref))(setting.key.scope)
import sbt.TupleSyntax.*
t2ToApp2(
@ -1010,7 +1010,7 @@ object BuildServerProtocol {
.flatMap(_.split(","))
.map(name => ConfigKey(name.trim))
.filter { config =>
val scope = Scope.Global.in(project, config)
val scope = Scope.Global.rescope(project).rescope(config)
allScopes.contains(scope)
}
(project, configs)

View File

@ -23,6 +23,7 @@ import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
import sbt.BasicCommandStrings.{ Shutdown, TerminateAction }
import sbt.ProjectExtra.extract
import sbt.SlashSyntax0.given
import sbt.internal.langserver.{ CancelRequestParams, ErrorCodes, LogMessageParams, MessageType }
import sbt.internal.protocol.{
JsonRpcNotificationMessage,
@ -446,7 +447,11 @@ final class NetworkChannel(
keys.filter(k => k.key.label == "testOnly" || k.key.label == "testQuick")
val (testState, cachedTestNames) = testKeys.foldLeft((sstate, true)) {
case ((st, allCached), k) =>
SessionVar.loadAndSet(sbt.Keys.definedTestNames in k.scope, st, true) match {
SessionVar.loadAndSet(
(k.scope / Keys.definedTestNames).scopedKey,
st,
true
) match {
case (nst, d) => (nst, allCached && d.isDefined)
}
}
@ -454,7 +459,7 @@ final class NetworkChannel(
val (runState, cachedMainClassNames) = runKeys.foldLeft((testState, true)) {
case ((st, allCached), k) =>
SessionVar.loadAndSet(
sbt.Keys.discoveredMainClasses in k.scope,
(k.scope / Keys.discoveredMainClasses).scopedKey,
st,
true
) match {

View File

@ -15,7 +15,7 @@ import sbt.BasicCommandStrings.{ RebootCommand, Shutdown, TerminateAction }
import sbt.Keys.{ baseDirectory, pollInterval, state }
import sbt.ProjectExtra.extract
import sbt.Scope.Global
import sbt.SlashSyntax0._
import sbt.SlashSyntax0.given
import sbt.internal.CommandStrings.LoadProject
import sbt.internal.SysProp
import sbt.internal.util.{ AttributeKey, Terminal }

View File

@ -13,6 +13,7 @@ import java.nio.file.{ Files, Path }
import java.util.concurrent.ConcurrentHashMap
import sbt.Keys._
import sbt.SlashSyntax0.given
import sbt.internal.Clean.ToSeqPath
import sbt.internal.Continuous.FileStampRepository
import sbt.internal.util.KeyTag
@ -97,7 +98,7 @@ private[sbt] object Settings {
val scope = setting.key.scope.copy(task = Select(setting.key.key))
if (fileOutputScopes.contains(scope)) {
val sk = setting.asInstanceOf[Def.Setting[Task[Any]]].key
val scopedKey = Keys.dynamicFileOutputs in (sk.scope in sk.key)
val scopedKey = Keys.dynamicFileOutputs.rescope(sk.scope.rescope(sk.key))
val init: Def.Initialize[Task[Seq[Path]]] = sk(_.map(_ => Nil))
addTaskDefinition(Def.setting[Task[Seq[Path]]](scopedKey, init, setting.pos)) ::
allOutputPathsImpl(scope) :: outputFileStampsImpl(scope) :: cleanImpl(scope) :: Nil
@ -109,13 +110,13 @@ private[sbt] object Settings {
setting: Def.Setting[_]
): List[Def.Setting[_]] = {
val sk = setting.asInstanceOf[Def.Setting[Task[T]]].key
val taskKey = TaskKey(sk.key) in sk.scope
val taskKey = sk.scope / TaskKey(sk.key)
// We create a previous reference so that clean automatically works without the
// user having to explicitly call previous anywhere.
val init = Previous.runtime(taskKey).zip(taskKey) { case (_, t) =>
t.map(implicitly[ToSeqPath[T]].apply)
}
val key = Def.ScopedKey(taskKey.scope in taskKey.key, Keys.dynamicFileOutputs.key)
val key = Def.ScopedKey(taskKey.scope.rescope(taskKey.key), Keys.dynamicFileOutputs.key)
addTaskDefinition(Def.setting[Task[Seq[Path]]](key, init, setting.pos)) ::
outputsAndStamps(taskKey)
}
@ -125,12 +126,12 @@ private[sbt] object Settings {
case transitiveDynamicInputs.key =>
scopedKey.scope.task.toOption.toSeq.map { key =>
val updatedKey = Def.ScopedKey(scopedKey.scope.copy(task = Zero), key)
transitiveDynamicInputs in scopedKey.scope :=
scopedKey.scope / transitiveDynamicInputs :=
WatchTransitiveDependencies.task(updatedKey).value
}
case dynamicDependency.key => (dynamicDependency in scopedKey.scope := { () }) :: Nil
case dynamicDependency.key => (scopedKey.scope / dynamicDependency := { () }) :: Nil
case transitiveClasspathDependency.key =>
(transitiveClasspathDependency in scopedKey.scope := { () }) :: Nil
(scopedKey.scope / transitiveClasspathDependency := { () }) :: Nil
case _ => Nil
}
@ -157,12 +158,12 @@ private[sbt] object Settings {
private[sbt] def inputPathSettings(setting: Def.Setting[_]): Seq[Def.Setting[_]] = {
val scopedKey = setting.key
val scope = scopedKey.scope
(Keys.allInputPathsAndAttributes in scope := {
val view = (fileTreeView in scope).value
val inputs = (fileInputs in scope).value
val stamper = (inputFileStamper in scope).value
val forceTrigger = (watchForceTriggerOnAnyChange in scope).value
val dynamicInputs = (Continuous.dynamicInputs in scope).value
(scope / Keys.allInputPathsAndAttributes := {
val view = (scope / fileTreeView).value
val inputs = (scope / fileInputs).value
val stamper = (scope / inputFileStamper).value
val forceTrigger = (scope / watchForceTriggerOnAnyChange).value
val dynamicInputs = (scope / Continuous.dynamicInputs).value
// This makes watch work by ensuring that the input glob is registered with the
// repository used by the watch process.
state.value.get(globalFileTreeRepository).foreach { repo =>
@ -186,10 +187,10 @@ private[sbt] object Settings {
* @return a task definition that retrieves all of the input paths scoped to the input key.
*/
private[this] def allFilesImpl(scope: Scope): Def.Setting[_] = {
addTaskDefinition(Keys.allInputFiles in scope := {
addTaskDefinition(scope / Keys.allInputFiles := {
val filter =
(fileInputIncludeFilter in scope).value && !(fileInputExcludeFilter in scope).value
(Keys.allInputPathsAndAttributes in scope).value.collect {
(scope / fileInputIncludeFilter).value && !(scope / fileInputExcludeFilter).value
(scope / Keys.allInputPathsAndAttributes).value.collect {
case (p, a) if filter.accept(p, a) => p
}
})
@ -206,8 +207,8 @@ private[sbt] object Settings {
*/
private[this] def changedInputFilesImpl(scope: Scope): List[Def.Setting[_]] =
changedFilesImpl(scope, changedInputFiles, inputFileStamps) ::
(watchForceTriggerOnAnyChange in scope := {
(watchForceTriggerOnAnyChange in scope).?.value match {
(scope / watchForceTriggerOnAnyChange := {
(scope / watchForceTriggerOnAnyChange).?.value match {
case Some(t) => t
case None => false
}
@ -218,8 +219,8 @@ private[sbt] object Settings {
changeKey: TaskKey[Seq[(Path, FileStamp)] => FileChanges],
stampKey: TaskKey[Seq[(Path, FileStamp)]]
): Def.Setting[_] =
addTaskDefinition(changeKey in scope := {
val current = (stampKey in scope).value
addTaskDefinition(scope / changeKey := {
val current = (scope / stampKey).value
changedFiles(_, current)
})
private[sbt] def changedFiles(
@ -260,7 +261,7 @@ private[sbt] object Settings {
* @return a task specific clean implementation
*/
private[sbt] def cleanImpl(scope: Scope): Def.Setting[_] = addTaskDefinition {
sbt.Keys.clean in scope := Clean.task(scope, full = false).value
scope / sbt.Keys.clean := Clean.task(scope, full = false).value
}
/**
@ -271,9 +272,9 @@ private[sbt] object Settings {
*/
@nowarn
private[sbt] def cleanImpl[T: JsonFormat: ToSeqPath](taskKey: TaskKey[T]): Def.Setting[_] = {
val taskScope = taskKey.scope in taskKey.key
val taskScope = taskKey.scope.rescope(taskKey.key)
addTaskDefinition(
sbt.Keys.clean in taskScope :=
taskScope / sbt.Keys.clean :=
// the clean file task needs to run first because the previous cache gets blown away
// by the second task
Def
@ -298,9 +299,9 @@ private[sbt] object Settings {
private[sbt] def fileStamps(scopedKey: Def.ScopedKey[_]): Def.Setting[_] = {
import sbt.internal.CompatParColls.Converters._
val scope = scopedKey.scope
addTaskDefinition(Keys.inputFileStamps in scope := {
val cache = (unmanagedFileStampCache in scope).value
val stamper = (Keys.inputFileStamper in scope).value
addTaskDefinition(scope / Keys.inputFileStamps := {
val cache = (scope / unmanagedFileStampCache).value
val stamper = (scope / Keys.inputFileStamper).value
val stampFile: Path => Option[(Path, FileStamp)] =
state.value.get(globalFileTreeRepository) match {
case Some(repo: FileStampRepository) =>
@ -315,8 +316,8 @@ private[sbt] object Settings {
(path: Path) => cache.getOrElseUpdate(path, stamper).map(path -> _)
}
val filter =
(fileInputIncludeFilter in scope).value && !(fileInputExcludeFilter in scope).value
(Keys.allInputPathsAndAttributes in scope).value.par.flatMap {
(scope / fileInputIncludeFilter).value && !(scope / fileInputExcludeFilter).value
(scope / Keys.allInputPathsAndAttributes).value.par.flatMap {
case (path, a) if filter.accept(path, a) => stampFile(path)
case _ => None
}.toVector
@ -327,19 +328,19 @@ private[sbt] object Settings {
private[this] def outputsAndStamps[T: JsonFormat: ToSeqPath](
taskKey: TaskKey[T]
): List[Def.Setting[_]] = {
val scope = taskKey.scope in taskKey.key
val scope = taskKey.scope.rescope(taskKey.key)
val changes = changedFilesImpl(scope, changedOutputFiles, outputFileStamps) :: Nil
allOutputPathsImpl(scope) :: outputFileStampsImpl(scope) :: cleanImpl(taskKey) :: changes
}
private[this] def allOutputPathsImpl(scope: Scope): Def.Setting[_] =
addTaskDefinition(allOutputFiles in scope := {
addTaskDefinition(scope / allOutputFiles := {
val filter =
(fileOutputIncludeFilter in scope).value && !(fileOutputExcludeFilter in scope).value
val view = (fileTreeView in scope).value
val fileOutputGlobs = (fileOutputs in scope).value
(scope / fileOutputIncludeFilter).value && !(scope / fileOutputExcludeFilter).value
val view = (scope / fileTreeView).value
val fileOutputGlobs = (scope / fileOutputs).value
val allFileOutputs = view.list(fileOutputGlobs).map(_._1)
val dynamicOutputs = (dynamicFileOutputs in scope).value
val dynamicOutputs = (scope / dynamicFileOutputs).value
val allDynamicOutputs = dynamicOutputs.flatMap {
case p if Files.isDirectory(p) => p +: view.list(Glob(p, RecursiveGlob)).map(_._1)
case p => p :: Nil
@ -359,15 +360,15 @@ private[sbt] object Settings {
})
private[this] def outputFileStampsImpl(scope: Scope): Def.Setting[_] =
addTaskDefinition(outputFileStamps in scope := {
val stamper: Path => Option[FileStamp] = (outputFileStamper in scope).value match {
addTaskDefinition(scope / outputFileStamps := {
val stamper: Path => Option[FileStamp] = (scope / outputFileStamper).value match {
case LastModified => FileStamp.lastModified
case Hash => FileStamp.hash
}
val allFiles = (allOutputFiles in scope).value
val allFiles = (scope / allOutputFiles).value
// The cache invalidation is specifically so that source formatters can run before
// the compile task and the file stamps seen by compile match the post-format stamps.
allFiles.foreach((unmanagedFileStampCache in scope).value.invalidate)
allFiles.foreach((scope / unmanagedFileStampCache).value.invalidate)
allFiles.flatMap(p => stamper(p).map(p -> _))
})

View File

@ -13,7 +13,6 @@ import java.io.File
import sbt.Def._
import sbt.Keys._
import sbt.SlashSyntax0._
import sbt.Project._
import sbt.ProjectExtra.*
import sbt.internal.graph._
@ -173,7 +172,7 @@ object DependencyTreeSettings {
val str = (key / asString).value
s.log.info(str)
},
key / toFile := {
(key / toFile) := {
val (targetFile, force) = targetFileAndForceParser.parsed
writeToFile(key.key.label, (key / asString).value, targetFile, force, streams.value)
},

View File

@ -11,7 +11,6 @@ package plugins
import sbt.Def.Setting
import sbt.Keys.*
import sbt.SlashSyntax0.*
object SbtPlugin extends AutoPlugin:
override def requires = ScriptedPlugin

View File

@ -5,6 +5,7 @@ import java.lang.reflect.InvocationTargetException
import sbt._
import sbt.internal.inc.ScalaInstance
import sbt.internal.inc.classpath.{ ClasspathUtilities, FilteredLoader }
import scala.annotation.nowarn
object LocalScriptedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
@ -89,6 +90,7 @@ object Scripted {
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
}
@nowarn
def doScripted(
scriptedSbtInstance: ScalaInstance,
sourcePath: File,

View File

@ -1,3 +1,3 @@
addCommandAlias("demo-success", "run true")
addCommandAlias("demo-failure", "run false")
addCommandAlias("demo-success", "runBlock true")
addCommandAlias("demo-failure", "runBlock false")
addCommandAlias("z", "scalaVersion")

View File

@ -7,7 +7,7 @@ val dropLibraryPath = taskKey[Unit]("Drop the last path from the java.library.pa
val wrappedRun = taskKey[Unit]("Run with modified java.library.path")
val wrappedTest = taskKey[Unit]("Test with modified java.library.path")
def wrap(task: InputKey[Unit]): Def.Initialize[Task[Unit]] =
def wrap[A1](task: InputKey[A1]): Def.Initialize[Task[Unit]] =
Def.sequential(appendToLibraryPath, task.toTask(""), dropLibraryPath)
// ThisBuild / turbo := true
@ -35,6 +35,6 @@ val root = (project in file(".")).settings(
val cp = System.getProperty("java.library.path", "").split(":").dropRight(1)
System.setProperty("java.library.path", cp.mkString(":"))
},
wrappedRun := wrap(Runtime / run).value,
wrappedRun := wrap(Runtime / runBlock).value,
wrappedTest := wrap(Test / testOnly).value
)

View File

@ -1,3 +1,3 @@
$ delete output
> run
> runBlock
$ exists output

View File

@ -1,3 +1,3 @@
$ delete output
> run
> runBlock
$ exists output

View File

@ -1,3 +1,3 @@
$ delete output
> run
> runBlock
$ exists output

View File

@ -1,12 +1,12 @@
> a/checkLibs
> b/checkLibs
> b/run
> b/runBlock
$ exists s2.13.8.txt
$ delete s2.13.8.txt
# don't crash when expanding the macro
> b3/run
> b3/runBlock
$ exists s2.13.10.txt
$ delete s2.13.10.txt

View File

@ -1,3 +1,3 @@
$ delete output
> run
> runBlock
$ exists output

View File

@ -4,7 +4,7 @@
# This should fail because the Main object is in package jartest and the resource is directly
# in src/main/resources
-> run
-> runBlock
> package
@ -18,7 +18,7 @@ $ copy-file src/main/resources/main_resource_test src/main/resources/jartest/mai
$ delete src/main/resources/main_resource_test
# This should succeed because sbt should put the resource on the runClasspath
> run
> runBlock
# This is necessary because package bases whether or not to run on last modified times, which don't have
# high enough resolution to notice the above move of main_resource_test

View File

@ -3,14 +3,14 @@
$ copy-file changes/B.scala B.scala
$ copy-file changes/A1.scala A.scala
> run 1
> runBlock 1
$ copy-file changes/A2.scala A.scala
> run 2
> runBlock 2
> clean
> ++2.13.12!
$ copy-file changes/A1.scala A.scala
> run 1
> runBlock 1
$ copy-file changes/A2.scala A.scala
> run 2
> runBlock 2

View File

@ -1,2 +1 @@
ThisBuild / scalaVersion := "2.12.17"
scalaVersion := "2.12.19"

View File

@ -2,10 +2,10 @@ $ copy-file changes/A1.scala A.scala
$ copy-file changes/B.scala B.scala
$ copy-file changes/C.scala C.scala
> compile
-> run
-> runBlock
$ copy-file changes/A2.scala A.scala
$ sleep 1000
> compile
> run
> runBlock

View File

@ -36,10 +36,10 @@ $ delete src/main/java/a/A.java
# It shouldn't run though, because it doesn't have a main method
$ copy-file changes/B1.java src/main/java/a/b/B.java
> compile
-> run
-> runBlock
# Replace B with a new B that has a main method and should therefore run
# if the main method was properly detected
$ copy-file changes/B3.java src/main/java/a/b/B.java
> run
> runBlock

View File

@ -1,7 +1,7 @@
> compile
# the value of F.x should be 16
> run 16
> runBlock 16
# modify D.scala so that the linearization changes
$ copy-file changes/D.scala D.scala
@ -12,4 +12,4 @@ $ sleep 1000
# if F is recompiled, the value of x should be 11, otherwise it will still be 16
# and this will fail
> run 11
> runBlock 11

View File

@ -4,7 +4,7 @@
> compile
# result should be 1
> run 1
> runBlock 1
# change order of arguments in A.x
$ copy-file changes/A.scala A.scala
@ -13,4 +13,4 @@ $ copy-file changes/A.scala A.scala
> compile
# Should still get 1 and not -1
> run 1
> runBlock 1

View File

@ -2,7 +2,7 @@
> compile
# verify that erased A.x can be called normally and reflectively
> run false
> runBlock false
# make A.x specialized
$ copy-file changes/A.scala A.scala
@ -12,4 +12,4 @@ $ copy-file changes/A.scala A.scala
# verify that specialized A.x can be called normally and reflectively
# NOTE: this test doesn't actually work correctly: have to check the output to see that B.scala was recompiled
> run true
> runBlock true

View File

@ -3,9 +3,9 @@
# if the tests are actually executed concurrently. The default concurrent
# restrictions limit the number of concurrent tasks to the number of processors,
# so we set it to 2.
> set concurrentRestrictions in Global := Seq(Tags.limitAll(2))
> set Global / concurrentRestrictions := Seq(Tags.limitAll(2))
-> test
# this should prevent concurrent execution of tests
> set concurrentRestrictions in Global += Tags.limit(Tags.Test, 1)
> set Global / concurrentRestrictions += Tags.limit(Tags.Test, 1)
> test