diff --git a/DEVELOPING.md b/DEVELOPING.md index beff0e099..a0d41f26a 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -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._ diff --git a/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala b/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala index 78f60b560..ec935626d 100644 --- a/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala +++ b/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala @@ -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.* diff --git a/main-command/src/main/scala/sbt/internal/CommandChannel.scala b/main-command/src/main/scala/sbt/internal/CommandChannel.scala index 49f139a93..7d9eb94d1 100644 --- a/main-command/src/main/scala/sbt/internal/CommandChannel.scala +++ b/main-command/src/main/scala/sbt/internal/CommandChannel.scala @@ -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]) diff --git a/main-settings/src/main/scala/sbt/Previous.scala b/main-settings/src/main/scala/sbt/Previous.scala index 22dbba3b9..b0c41dca5 100644 --- a/main-settings/src/main/scala/sbt/Previous.scala +++ b/main-settings/src/main/scala/sbt/Previous.scala @@ -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 diff --git a/main-settings/src/main/scala/sbt/Reference.scala b/main-settings/src/main/scala/sbt/Reference.scala index 4b9d2608a..a9426a7b5 100644 --- a/main-settings/src/main/scala/sbt/Reference.scala +++ b/main-settings/src/main/scala/sbt/Reference.scala @@ -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. */ diff --git a/main-settings/src/main/scala/sbt/Scope.scala b/main-settings/src/main/scala/sbt/Scope.scala index 6016983bc..0f29f16f5 100644 --- a/main-settings/src/main/scala/sbt/Scope.scala +++ b/main-settings/src/main/scala/sbt/Scope.scala @@ -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 diff --git a/main-settings/src/main/scala/sbt/SlashSyntax.scala b/main-settings/src/main/scala/sbt/SlashSyntax.scala index 5a534ccb7..4991ce1a9 100644 --- a/main-settings/src/main/scala/sbt/SlashSyntax.scala +++ b/main-settings/src/main/scala/sbt/SlashSyntax.scala @@ -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 diff --git a/main-settings/src/main/scala/sbt/Structure.scala b/main-settings/src/main/scala/sbt/Structure.scala index bce97a035..ff361d604 100644 --- a/main-settings/src/main/scala/sbt/Structure.scala +++ b/main-settings/src/main/scala/sbt/Structure.scala @@ -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])) diff --git a/main-settings/src/main/scala/sbt/std/KeyMacro.scala b/main-settings/src/main/scala/sbt/std/KeyMacro.scala index b59a4c534..653388433 100644 --- a/main-settings/src/main/scala/sbt/std/KeyMacro.scala +++ b/main-settings/src/main/scala/sbt/std/KeyMacro.scala @@ -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 diff --git a/main-settings/src/test/scala/sbt/AppendSpec.scala b/main-settings/src/test/scala/sbt/AppendSpec.scala index ab4d660d6..3bfe1aa9b 100644 --- a/main-settings/src/test/scala/sbt/AppendSpec.scala +++ b/main-settings/src/test/scala/sbt/AppendSpec.scala @@ -12,7 +12,7 @@ object AppendSpec { val onLoad = SettingKey[State => State]("onLoad") import Scope.Global - import SlashSyntax0._ + import SlashSyntax0.given def doSideEffect(): Unit = () diff --git a/main/src/main/scala/sbt/BackgroundJobService.scala b/main/src/main/scala/sbt/BackgroundJobService.scala index a9189d334..e268b96ce 100644 --- a/main/src/main/scala/sbt/BackgroundJobService.scala +++ b/main/src/main/scala/sbt/BackgroundJobService.scala @@ -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) diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 63e6ef590..d3daa2b6b 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -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 diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 27b6da56b..5564409b7 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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) => diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index 3eb37c2b7..fed53f3e6 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -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 { diff --git a/main/src/main/scala/sbt/Extracted.scala b/main/src/main/scala/sbt/Extracted.scala index 8a8512f73..798b106dd 100644 --- a/main/src/main/scala/sbt/Extracted.scala +++ b/main/src/main/scala/sbt/Extracted.scala @@ -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[_]] diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 610faebb1..9ac7b24aa 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -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) diff --git a/main/src/main/scala/sbt/PluginCross.scala b/main/src/main/scala/sbt/PluginCross.scala index cf23826c9..7532eaffd 100644 --- a/main/src/main/scala/sbt/PluginCross.scala +++ b/main/src/main/scala/sbt/PluginCross.scala @@ -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 } diff --git a/main/src/main/scala/sbt/ProjectExtra.scala b/main/src/main/scala/sbt/ProjectExtra.scala index 9669ea6e7..296eb5dc9 100755 --- a/main/src/main/scala/sbt/ProjectExtra.scala +++ b/main/src/main/scala/sbt/ProjectExtra.scala @@ -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, diff --git a/main/src/main/scala/sbt/ProjectMatrix.scala b/main/src/main/scala/sbt/ProjectMatrix.scala index 1b834ded7..dd7bb7d12 100644 --- a/main/src/main/scala/sbt/ProjectMatrix.scala +++ b/main/src/main/scala/sbt/ProjectMatrix.scala @@ -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) } } } diff --git a/main/src/main/scala/sbt/RemoteCache.scala b/main/src/main/scala/sbt/RemoteCache.scala index be4864eec..1c57f38c8 100644 --- a/main/src/main/scala/sbt/RemoteCache.scala +++ b/main/src/main/scala/sbt/RemoteCache.scala @@ -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 diff --git a/main/src/main/scala/sbt/ScriptedPlugin.scala b/main/src/main/scala/sbt/ScriptedPlugin.scala index a98b498d6..5113798c5 100644 --- a/main/src/main/scala/sbt/ScriptedPlugin.scala +++ b/main/src/main/scala/sbt/ScriptedPlugin.scala @@ -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 diff --git a/main/src/main/scala/sbt/TemplateCommandUtil.scala b/main/src/main/scala/sbt/TemplateCommandUtil.scala index 7fbb69ef1..a63af42b9 100644 --- a/main/src/main/scala/sbt/TemplateCommandUtil.scala +++ b/main/src/main/scala/sbt/TemplateCommandUtil.scala @@ -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 } diff --git a/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala index 144462d0b..8eb10df9b 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala @@ -19,7 +19,6 @@ import lmcoursier.definitions.{ import sbt.librarymanagement._ import sbt.Keys._ import sbt.ProjectExtra.extract -import sbt.SlashSyntax0._ object CoursierArtifactsTasks { def coursierPublicationsTask( diff --git a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala index 2d05d53c9..3134425d1 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala @@ -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 { diff --git a/main/src/main/scala/sbt/internal/Aggregation.scala b/main/src/main/scala/sbt/internal/Aggregation.scala index 68700681e..4a2a8e727 100644 --- a/main/src/main/scala/sbt/internal/Aggregation.scala +++ b/main/src/main/scala/sbt/internal/Aggregation.scala @@ -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) } diff --git a/main/src/main/scala/sbt/internal/BuildStructure.scala b/main/src/main/scala/sbt/internal/BuildStructure.scala index 9e4610674..e9e998dd1 100644 --- a/main/src/main/scala/sbt/internal/BuildStructure.scala +++ b/main/src/main/scala/sbt/internal/BuildStructure.scala @@ -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 } diff --git a/main/src/main/scala/sbt/internal/ClassLoaders.scala b/main/src/main/scala/sbt/internal/ClassLoaders.scala index 708193f43..cf47bc325 100644 --- a/main/src/main/scala/sbt/internal/ClassLoaders.scala +++ b/main/src/main/scala/sbt/internal/ClassLoaders.scala @@ -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 diff --git a/main/src/main/scala/sbt/internal/ClasspathImpl.scala b/main/src/main/scala/sbt/internal/ClasspathImpl.scala index 74b5f066d..6861873ad 100644 --- a/main/src/main/scala/sbt/internal/ClasspathImpl.scala +++ b/main/src/main/scala/sbt/internal/ClasspathImpl.scala @@ -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 } diff --git a/main/src/main/scala/sbt/internal/Clean.scala b/main/src/main/scala/sbt/internal/Clean.scala index 34f0092e0..de8524e9c 100644 --- a/main/src/main/scala/sbt/internal/Clean.scala +++ b/main/src/main/scala/sbt/internal/Clean.scala @@ -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 { diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 637270ef3..8569bb474 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -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 = { diff --git a/main/src/main/scala/sbt/internal/ConsoleProject.scala b/main/src/main/scala/sbt/internal/ConsoleProject.scala index 6790d8c6c..7d3708c87 100644 --- a/main/src/main/scala/sbt/internal/ConsoleProject.scala +++ b/main/src/main/scala/sbt/internal/ConsoleProject.scala @@ -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 diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index edab39f5a..ab2b47464 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -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 diff --git a/main/src/main/scala/sbt/internal/CrossJava.scala b/main/src/main/scala/sbt/internal/CrossJava.scala index aca3593da..68e2fbb8e 100644 --- a/main/src/main/scala/sbt/internal/CrossJava.scala +++ b/main/src/main/scala/sbt/internal/CrossJava.scala @@ -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 } diff --git a/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala b/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala index e1b6179a9..0380f86b0 100644 --- a/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala +++ b/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala @@ -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 { diff --git a/main/src/main/scala/sbt/internal/GlobalPlugin.scala b/main/src/main/scala/sbt/internal/GlobalPlugin.scala index dcc9d816d..9cac57c26 100644 --- a/main/src/main/scala/sbt/internal/GlobalPlugin.scala +++ b/main/src/main/scala/sbt/internal/GlobalPlugin.scala @@ -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, diff --git a/main/src/main/scala/sbt/internal/IvyConsole.scala b/main/src/main/scala/sbt/internal/IvyConsole.scala index e2a1e0651..5ab6aed19 100644 --- a/main/src/main/scala/sbt/internal/IvyConsole.scala +++ b/main/src/main/scala/sbt/internal/IvyConsole.scala @@ -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 diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index 21d454f56..1ceb82fa5 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -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._ diff --git a/main/src/main/scala/sbt/internal/LintUnused.scala b/main/src/main/scala/sbt/internal/LintUnused.scala index 283e345c9..91ccd3b2a 100644 --- a/main/src/main/scala/sbt/internal/LintUnused.scala +++ b/main/src/main/scala/sbt/internal/LintUnused.scala @@ -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 { diff --git a/main/src/main/scala/sbt/internal/Load.scala b/main/src/main/scala/sbt/internal/Load.scala index 01b164ef9..bbe238308 100755 --- a/main/src/main/scala/sbt/internal/Load.scala +++ b/main/src/main/scala/sbt/internal/Load.scala @@ -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, diff --git a/main/src/main/scala/sbt/internal/LogManager.scala b/main/src/main/scala/sbt/internal/LogManager.scala index 86631b387..2768b92f2 100644 --- a/main/src/main/scala/sbt/internal/LogManager.scala +++ b/main/src/main/scala/sbt/internal/LogManager.scala @@ -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) } diff --git a/main/src/main/scala/sbt/internal/ProjectQuery.scala b/main/src/main/scala/sbt/internal/ProjectQuery.scala index 2d0903d4a..00cd29485 100644 --- a/main/src/main/scala/sbt/internal/ProjectQuery.scala +++ b/main/src/main/scala/sbt/internal/ProjectQuery.scala @@ -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 diff --git a/main/src/main/scala/sbt/internal/Script.scala b/main/src/main/scala/sbt/internal/Script.scala index 7df34cadf..2ce83e96b 100644 --- a/main/src/main/scala/sbt/internal/Script.scala +++ b/main/src/main/scala/sbt/internal/Script.scala @@ -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 } diff --git a/main/src/main/scala/sbt/internal/SettingCompletions.scala b/main/src/main/scala/sbt/internal/SettingCompletions.scala index e7891351d..4688cf03f 100644 --- a/main/src/main/scala/sbt/internal/SettingCompletions.scala +++ b/main/src/main/scala/sbt/internal/SettingCompletions.scala @@ -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)) diff --git a/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala b/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala index f991822d5..cfc0e832e 100644 --- a/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala +++ b/main/src/main/scala/sbt/internal/WatchTransitiveDependencies.scala @@ -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) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index df65d95a2..c43d6bc0b 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -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) diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 0b30f1a2e..303501344 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -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 { diff --git a/main/src/main/scala/sbt/nio/CheckBuildSources.scala b/main/src/main/scala/sbt/nio/CheckBuildSources.scala index a04cd8ac1..83522f849 100644 --- a/main/src/main/scala/sbt/nio/CheckBuildSources.scala +++ b/main/src/main/scala/sbt/nio/CheckBuildSources.scala @@ -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 } diff --git a/main/src/main/scala/sbt/nio/Settings.scala b/main/src/main/scala/sbt/nio/Settings.scala index 98d7b6551..b4cc96a72 100644 --- a/main/src/main/scala/sbt/nio/Settings.scala +++ b/main/src/main/scala/sbt/nio/Settings.scala @@ -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 -> _)) }) diff --git a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala index 65b75f59a..d367cc57c 100644 --- a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala +++ b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala @@ -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) }, diff --git a/main/src/main/scala/sbt/plugins/SbtPlugin.scala b/main/src/main/scala/sbt/plugins/SbtPlugin.scala index a37cd8b6f..b1ebb9046 100644 --- a/main/src/main/scala/sbt/plugins/SbtPlugin.scala +++ b/main/src/main/scala/sbt/plugins/SbtPlugin.scala @@ -11,7 +11,6 @@ package plugins import sbt.Def.Setting import sbt.Keys.* -import sbt.SlashSyntax0.* object SbtPlugin extends AutoPlugin: override def requires = ScriptedPlugin diff --git a/project/Scripted.scala b/project/Scripted.scala index 098807419..f0839f0d9 100644 --- a/project/Scripted.scala +++ b/project/Scripted.scala @@ -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, diff --git a/sbt-app/src/sbt-test/actions/add-alias/build.sbt b/sbt-app/src/sbt-test/actions/add-alias/build.sbt index 089e388c1..c8673eaea 100644 --- a/sbt-app/src/sbt-test/actions/add-alias/build.sbt +++ b/sbt-app/src/sbt-test/actions/add-alias/build.sbt @@ -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") diff --git a/sbt-app/src/sbt-test/classloader-cache/jni/build.sbt b/sbt-app/src/sbt-test/classloader-cache/jni/build.sbt index e9449cc48..e92d9b23d 100644 --- a/sbt-app/src/sbt-test/classloader-cache/jni/build.sbt +++ b/sbt-app/src/sbt-test/classloader-cache/jni/build.sbt @@ -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 ) diff --git a/sbt-app/src/sbt-test/dependency-management/aar-packaging/test b/sbt-app/src/sbt-test/dependency-management/aar-packaging/test index 2182f57b0..5efe58689 100644 --- a/sbt-app/src/sbt-test/dependency-management/aar-packaging/test +++ b/sbt-app/src/sbt-test/dependency-management/aar-packaging/test @@ -1,3 +1,3 @@ $ delete output -> run +> runBlock $ exists output diff --git a/sbt-app/src/sbt-test/dependency-management/exclude-dependencies2/test b/sbt-app/src/sbt-test/dependency-management/exclude-dependencies2/test index 2182f57b0..5efe58689 100644 --- a/sbt-app/src/sbt-test/dependency-management/exclude-dependencies2/test +++ b/sbt-app/src/sbt-test/dependency-management/exclude-dependencies2/test @@ -1,3 +1,3 @@ $ delete output -> run +> runBlock $ exists output diff --git a/sbt-app/src/sbt-test/dependency-management/profiles/test b/sbt-app/src/sbt-test/dependency-management/profiles/test index 2182f57b0..5efe58689 100644 --- a/sbt-app/src/sbt-test/dependency-management/profiles/test +++ b/sbt-app/src/sbt-test/dependency-management/profiles/test @@ -1,3 +1,3 @@ $ delete output -> run +> runBlock $ exists output diff --git a/sbt-app/src/sbt-test/dependency-management/stdlib-unfreeze/test b/sbt-app/src/sbt-test/dependency-management/stdlib-unfreeze/test index 7df93ab6c..8984f6503 100644 --- a/sbt-app/src/sbt-test/dependency-management/stdlib-unfreeze/test +++ b/sbt-app/src/sbt-test/dependency-management/stdlib-unfreeze/test @@ -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 diff --git a/sbt-app/src/sbt-test/dependency-management/url-no-head/test b/sbt-app/src/sbt-test/dependency-management/url-no-head/test index 2182f57b0..5efe58689 100644 --- a/sbt-app/src/sbt-test/dependency-management/url-no-head/test +++ b/sbt-app/src/sbt-test/dependency-management/url-no-head/test @@ -1,3 +1,3 @@ $ delete output -> run +> runBlock $ exists output diff --git a/sbt-app/src/sbt-test/package/resources/test b/sbt-app/src/sbt-test/package/resources/test index 27ee7a65d..83139bf77 100644 --- a/sbt-app/src/sbt-test/package/resources/test +++ b/sbt-app/src/sbt-test/package/resources/test @@ -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 diff --git a/sbt-app/src/sbt-test/source-dependencies/constants/test b/sbt-app/src/sbt-test/source-dependencies/constants/test index ff8815d85..9d448cea2 100644 --- a/sbt-app/src/sbt-test/source-dependencies/constants/test +++ b/sbt-app/src/sbt-test/source-dependencies/constants/test @@ -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 diff --git a/sbt-app/src/sbt-test/source-dependencies/implicit-search/build.sbt b/sbt-app/src/sbt-test/source-dependencies/implicit-search/build.sbt index 07fe33830..8f5047976 100644 --- a/sbt-app/src/sbt-test/source-dependencies/implicit-search/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/implicit-search/build.sbt @@ -1,2 +1 @@ -ThisBuild / scalaVersion := "2.12.17" - +scalaVersion := "2.12.19" diff --git a/sbt-app/src/sbt-test/source-dependencies/implicit-search/test b/sbt-app/src/sbt-test/source-dependencies/implicit-search/test index 18d69f6b8..d7d7190b5 100644 --- a/sbt-app/src/sbt-test/source-dependencies/implicit-search/test +++ b/sbt-app/src/sbt-test/source-dependencies/implicit-search/test @@ -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 diff --git a/sbt-app/src/sbt-test/source-dependencies/java-basic/test b/sbt-app/src/sbt-test/source-dependencies/java-basic/test index 9dac40735..04a3d604d 100644 --- a/sbt-app/src/sbt-test/source-dependencies/java-basic/test +++ b/sbt-app/src/sbt-test/source-dependencies/java-basic/test @@ -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 \ No newline at end of file +> runBlock diff --git a/sbt-app/src/sbt-test/source-dependencies/linearization/test b/sbt-app/src/sbt-test/source-dependencies/linearization/test index 22f17664a..f6c002d7c 100644 --- a/sbt-app/src/sbt-test/source-dependencies/linearization/test +++ b/sbt-app/src/sbt-test/source-dependencies/linearization/test @@ -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 \ No newline at end of file +> runBlock 11 \ No newline at end of file diff --git a/sbt-app/src/sbt-test/source-dependencies/named/test b/sbt-app/src/sbt-test/source-dependencies/named/test index 28f1c58d3..626ddc2f4 100644 --- a/sbt-app/src/sbt-test/source-dependencies/named/test +++ b/sbt-app/src/sbt-test/source-dependencies/named/test @@ -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 diff --git a/sbt-app/src/sbt-test/source-dependencies/specialized/test b/sbt-app/src/sbt-test/source-dependencies/specialized/test index b9e1ad09c..76c2120a8 100644 --- a/sbt-app/src/sbt-test/source-dependencies/specialized/test +++ b/sbt-app/src/sbt-test/source-dependencies/specialized/test @@ -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 \ No newline at end of file +> runBlock true \ No newline at end of file diff --git a/sbt-app/src/sbt-test/tests/serial/test b/sbt-app/src/sbt-test/tests/serial/test index a657fd48f..86ebb70d2 100644 --- a/sbt-app/src/sbt-test/tests/serial/test +++ b/sbt-app/src/sbt-test/tests/serial/test @@ -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