diff --git a/core-macros/src/main/scala/sbt/internal/util/appmacro/Cont.scala b/core-macros/src/main/scala/sbt/internal/util/appmacro/Cont.scala index 6db4069f6..e8d78068d 100644 --- a/core-macros/src/main/scala/sbt/internal/util/appmacro/Cont.scala +++ b/core-macros/src/main/scala/sbt/internal/util/appmacro/Cont.scala @@ -94,17 +94,25 @@ trait Cont: import conv.qctx import qctx.reflect.* given qctx.type = qctx + def msg: String = + s"given evidence sjsonnew.HashWriter[${TypeRepr.of[A].show}] is not found; " + + "opt out of caching by annotating the key with @cacheLevel(include = Array.empty), or as" + + "foo := Def.uncached(...), or provide a given value" Expr .summon[HashWriter[A]] - .getOrElse(sys.error(s"HashWriter[A] not found for ${TypeRepr.of[A].show}")) + .getOrElse(report.errorAndAbort(msg)) def summonJsonFormat[A: Type]: Expr[JsonFormat[A]] = import conv.qctx import qctx.reflect.* given qctx.type = qctx + def msg: String = + s"given evidence sjsonnew.JsonFormat[${TypeRepr.of[A].show}] is not found; " + + "opt out of caching by annotating the key with @cacheLevel(include = Array.empty), or as" + + "foo := Def.uncached(...), or provide a given value" Expr .summon[JsonFormat[A]] - .getOrElse(sys.error(s"JsonFormat[A] not found for ${TypeRepr.of[A].show}")) + .getOrElse(report.errorAndAbort(msg)) def summonClassTag[A: Type]: Expr[ClassTag[A]] = import conv.qctx @@ -112,7 +120,7 @@ trait Cont: given qctx.type = qctx Expr .summon[ClassTag[A]] - .getOrElse(sys.error(s"ClassTag[A] not found for ${TypeRepr.of[A].show}")) + .getOrElse(report.errorAndAbort(s"ClassTag[A] not found for ${TypeRepr.of[A].show}")) /** * Implementation of a macro that provides a direct syntax for applicative functors and monads. @@ -334,7 +342,11 @@ trait Cont: cacheConfigExpr: Expr[BuildWideCacheConfiguration], tags: List[CacheLevelTag], )(body: Expr[A1], input: Expr[A2]): Expr[A1] = - val codeContentHash = Expr[Long](body.show.##) + val codeContentHash = + try Expr[Long](body.show.##) + catch + case e: Throwable => + Expr[Long](Printer.TreeStructure.show(body.asTerm).##) val extraHash = Expr[Long](0L) val aJsonFormat = summonJsonFormat[A1] val aClassTag = summonClassTag[A1] diff --git a/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala b/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala index ec608ef72..0b11187e7 100644 --- a/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala +++ b/core-macros/src/main/scala/sbt/internal/util/appmacro/ContextUtil.scala @@ -102,6 +102,28 @@ trait ContextUtil[C <: Quotes & scala.Singleton](val valStart: Int): case Apply(_, List(arg)) => extractTags(arg) case _ => extractTags0(tree) + def cacheLevels(tree: Term): Seq[CacheLevelTag] = + tree.underlying match + // handles foo / bar cases + case Apply(TypeApply(_, _), List(t @ Ident(_))) => + t.symbol.getAnnotation(cacheLevelSym) match + case Some(_) => cacheLevelsForSym(t.symbol) + case None => CacheLevelTag.all.toList + case u => + u.symbol.getAnnotation(cacheLevelSym) match + case Some(_) => cacheLevelsForSym(u.symbol) + case None => CacheLevelTag.all.toList + + def cacheLevelsForSym(sym: Symbol): Seq[CacheLevelTag] = + sym.getAnnotation(cacheLevelSym) match + case Some(annot) => + annot.asExprOf[cacheLevel] match + case '{ cacheLevel(include = Array.empty[CacheLevelTag](using $_)) } => Nil + case '{ cacheLevel(include = Array[CacheLevelTag]($include*)) } => + include.value.get + case _ => report.errorAndAbort(Printer.TreeStructure.show(annot) + " does not match") + case None => CacheLevelTag.all.toList + enum OutputType: case File case Directory @@ -178,5 +200,15 @@ end ContextUtil object ContextUtil: def appendScalacOptions(options: Seq[String]): Unit = - Attic.appendItems(options.asJava); + Attic.appendItems(options.asJava) + + def isTaskCacheByDefault: Boolean = + val atticValues = Attic.getItems().asScala.toSet + val noDefaultMacroSetting = atticValues.contains("-Xmacro-settings:sbt:no-default-task-cache") + !noDefaultMacroSetting end ContextUtil + +class ContextUtil0[C <: Quotes & scala.Singleton](override val qctx: C, valStart: Int) + extends ContextUtil[C](valStart): +// import qctx.reflect.* +end ContextUtil0 diff --git a/main-settings/src/main/scala/sbt/Def.scala b/main-settings/src/main/scala/sbt/Def.scala index 2f12d4e7f..f49d41837 100644 --- a/main-settings/src/main/scala/sbt/Def.scala +++ b/main-settings/src/main/scala/sbt/Def.scala @@ -20,7 +20,8 @@ import sbt.util.{ AggregateActionCacheStore, BuildWideCacheConfiguration, cacheLevel, - DiskActionCacheStore + DiskActionCacheStore, + Uncached, } import Util.* import sbt.util.Show @@ -301,6 +302,9 @@ object Def extends BuildSyntax with Init with InitializeImplicits: inline def cachedTask[A1](inline a1: A1): Def.Initialize[Task[A1]] = ${ TaskMacro.taskMacroImpl[A1]('a1, cached = true) } + inline def uncachedTask[A1](inline a1: A1): Def.Initialize[Task[A1]] = + ${ TaskMacro.taskMacroImpl[A1]('a1, cached = false) } + inline def task[A1](inline a1: A1): Def.Initialize[Task[A1]] = ${ TaskMacro.taskMacroImpl[A1]('a1, cached = false) } @@ -465,6 +469,11 @@ object Def extends BuildSyntax with Init with InitializeImplicits: private[sbt] def isDummy(t: Task[?]): Boolean = t.get(isDummyTask).getOrElse(false) + + /** + * Marker function to make the task uncached. + */ + inline def uncached[A1](inline a: A1): A1 = Uncached(a) end Def sealed trait InitializeImplicits { self: Def.type => diff --git a/main-settings/src/main/scala/sbt/Structure.scala b/main-settings/src/main/scala/sbt/Structure.scala index 74471c5d6..c3b68e2e9 100644 --- a/main-settings/src/main/scala/sbt/Structure.scala +++ b/main-settings/src/main/scala/sbt/Structure.scala @@ -157,6 +157,9 @@ sealed abstract class TaskKey[A1] private[sbt] final inline def rescope(scope: Scope): TaskKey[A1] = Scoped.scopedTask(Scope.replaceThis(this.scope)(scope), this.key) + /** + * Appends a single value to the task key. + */ inline def +=[A2](inline v: A2)(using Append.Value[A1, A2]): Setting[Task[A1]] = append1[A2](taskMacro(v)) @@ -165,6 +168,9 @@ sealed abstract class TaskKey[A1] ): Setting[Task[A1]] = make(v)(ev.appendValue) + /** + * Appends a sequence of values to the task key. + */ inline def ++=[A2](inline vs: A2)(using Append.Values[A1, A2]): Setting[Task[A1]] = appendN(taskMacro[A2](vs)) @@ -427,8 +433,8 @@ object Scoped: sealed trait DefinableTask[A1] { self: TaskKey[A1] => /** Internal function for the task macro. */ - inline def taskMacro[A](inline a: A): Initialize[Task[A]] = - ${ TaskMacro.taskMacroImpl[A]('a, cached = false) } + inline def taskMacro[A2](inline a: A2): Initialize[Task[A2]] = + ${ TaskMacro.taskMacroImpl[A2]('a, 'this) } private[sbt] inline def :==(app: A1): Setting[Task[A1]] = set(Def.valueStrict(std.TaskExtra.constant(app))) diff --git a/main-settings/src/main/scala/sbt/std/TaskMacro.scala b/main-settings/src/main/scala/sbt/std/TaskMacro.scala index c2070948a..01ce61888 100644 --- a/main-settings/src/main/scala/sbt/std/TaskMacro.scala +++ b/main-settings/src/main/scala/sbt/std/TaskMacro.scala @@ -15,10 +15,9 @@ import sbt.internal.util.appmacro.{ Cont, // Instance, // LinterDSL, - // MixedBuilder, - // MonadInstance + ContextUtil, + ContextUtil0, } -// import Instance.Transform import sbt.internal.util.{ LinePosition, NoPosition, SourcePosition } import language.experimental.macros @@ -49,6 +48,42 @@ object TaskMacro: // import LinterDSL.{ Empty => EmptyLinter } + def taskMacroImpl[A1: Type](t: Expr[A1], key: Expr[TaskKey[?]])(using + qctx: Quotes + ): Expr[Initialize[Task[A1]]] = + import qctx.reflect.* + var isUncacheApplied = false + object appTransformer extends TreeMap: + override def transformTerm(tree: Term)(owner: Symbol): Term = + tree match + case Apply(TypeApply(s @ Select(Ident("Uncached"), "apply"), targ :: Nil), qual :: Nil) + if "sbt.util.Uncached$.apply" == s.symbol.fullName => + isUncacheApplied = true + super.transformTerm(tree)(owner) + case _ => + super.transformTerm(tree)(owner) + end appTransformer + val _ = appTransformer.transformTerm(t.asTerm)(Symbol.spliceOwner) + + val cu0 = ContextUtil0(qctx, 0) + val cl = cu0.cacheLevels(key.asTerm) + val cached = ContextUtil.isTaskCacheByDefault && !isUncacheApplied && cl.nonEmpty + t match + case '{ if ($cond) then $thenp else $elsep } => taskIfImpl[A1](t, cached) + case _ => + val convert1 = new FullConvert(qctx, 0) + if cached then + convert1.contMapN[A1, F, Id]( + t, + convert1.appExpr, + Some('{ + InputWrapper.`wrapInitTask_\u2603\u2603`[BuildWideCacheConfiguration]( + Def.cacheConfiguration + ) + }) + ) + else convert1.contMapN[A1, F, Id](t, convert1.appExpr, None) + def taskMacroImpl[A1: Type](t: Expr[A1], cached: Boolean)(using qctx: Quotes ): Expr[Initialize[Task[A1]]] = diff --git a/main-settings/src/test/scala/sbt/SlashSyntaxTest.scala b/main-settings/src/test/scala/sbt/SlashSyntaxTest.scala index f232d70cb..cb17887d6 100644 --- a/main-settings/src/test/scala/sbt/SlashSyntaxTest.scala +++ b/main-settings/src/test/scala/sbt/SlashSyntaxTest.scala @@ -10,6 +10,7 @@ package sbt.test import java.io.File import sjsonnew.* +import sbt.Def import sbt.Def.{ Setting, inputKey, settingKey, taskKey } import sbt.Scope.Global import sbt.ScopeAxis.Zero @@ -56,7 +57,7 @@ object SlashSyntaxTest extends sbt.SlashSyntax { Compile / bar := { (Compile / foo).previous.getOrElse(2) }, - Test / buildInfo := Nil, + Test / buildInfo := Def.uncached(Nil), baz := { val _ = (Test / buildInfo).taskValue (Compile / run).evaluated diff --git a/main-settings/src/test/scala/sbt/std/UsageTest.scala b/main-settings/src/test/scala/sbt/std/UsageTest.scala index e4d03f321..bdaf40a87 100644 --- a/main-settings/src/test/scala/sbt/std/UsageTest.scala +++ b/main-settings/src/test/scala/sbt/std/UsageTest.scala @@ -73,7 +73,7 @@ object Assign { // ak += z.value + (if (y.value) set.value else plain.value), ck := new File(ck.value, "asdf"), - ak := sk.value.size, + ak := Def.uncached(sk.value.size), // bk ++= Seq(z.value) intTask := ak.previous.get, bgList := { mk.value.toString.toList.map(_.toInt) }, diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 1f9bb700f..398566abf 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -399,12 +399,12 @@ object Cross { val scope = Scope(Select(project), Zero, Zero, Zero) instance match { - case Some((home, inst)) => + case Some((home, inst1)) => Seq( scope / scalaVersion := version, scope / crossScalaVersions := scalaVersions, scope / scalaHome := Some(home), - scope / scalaInstance := inst, + scope / scalaInstance := Def.uncached(inst1), ) case None => Seq( diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index c18086997..5545af24e 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -70,6 +70,7 @@ import sbt.librarymanagement.CrossVersion.{ binarySbtVersion, binaryScalaVersion import sbt.librarymanagement.* import sbt.librarymanagement.ivy.* import sbt.librarymanagement.syntax.* +import sbt.librarymanagement.LibraryManagementCodec.given import sbt.nio.FileStamp import sbt.nio.Keys.* import sbt.nio.file.syntax.* @@ -166,24 +167,27 @@ object Defaults extends BuildCommon { outputFileStamper :== sbt.nio.FileStamper.LastModified, onChangedBuildSource :== SysProp.onChangedBuildSource, clean := { () }, - unmanagedFileStampCache := - state.value.get(persistentFileStampCache).getOrElse(new sbt.nio.FileStamp.Cache), - managedFileStampCache := new sbt.nio.FileStamp.Cache, + unmanagedFileStampCache := Def.uncached( + state.value.get(persistentFileStampCache).getOrElse(new sbt.nio.FileStamp.Cache) + ), + managedFileStampCache := Def.uncached(new sbt.nio.FileStamp.Cache), ) ++ globalIvyCore ++ globalJvmCore ++ Watch.defaults ) ++ globalSbtCore private[sbt] lazy val globalJvmCore: Seq[Setting[?]] = Seq( - compilerCache := state.value - .get(Keys.stateCompilerCache) - .getOrElse(CompilerCache.fresh), + compilerCache := Def.uncached( + state.value + .get(Keys.stateCompilerCache) + .getOrElse(CompilerCache.fresh) + ), sourcesInBase :== true, autoAPIMappings := false, apiMappings := Map.empty, autoScalaLibrary :== true, managedScalaInstance :== true, allowUnsafeScalaLibUpgrade :== false, - classpathEntryDefinesClass := { (file: File) => + classpathEntryDefinesClass := Def.uncached { (file: File) => sys.error("use classpathEntryDefinesClassVF instead") }, extraIncOptions :== Seq("JAVA_CLASS_VERSION" -> sys.props("java.class.version")), @@ -216,8 +220,8 @@ object Defaults extends BuildCommon { unmanagedSources / includeFilter :== ("*.java" | "*.scala"), unmanagedJars / includeFilter :== "*.jar" | "*.so" | "*.dll" | "*.jnilib" | "*.zip", unmanagedResources / includeFilter :== AllPassFilter, - bgList := { bgJobService.value.jobs }, - ps := psTask.value, + bgList := Def.uncached { bgJobService.value.jobs }, + ps := Def.uncached(psTask.value), bgStop := bgStopTask.evaluated, bgWaitFor := bgWaitForTask.evaluated, bgCopyClasspath :== true, @@ -285,7 +289,7 @@ object Defaults extends BuildCommon { platform :== Platform.jvm, // coursier settings csrExtraCredentials :== Nil, - csrLogger := LMCoursier.coursierLoggerTask.value, + csrLogger := Def.uncached(LMCoursier.coursierLoggerTask.value), csrMavenProfiles :== Set.empty, csrReconciliations :== LMCoursier.relaxedForAllModules, csrMavenDependencyOverride :== false, @@ -309,14 +313,14 @@ object Defaults extends BuildCommon { private[sbt] lazy val globalSbtCore: Seq[Setting[?]] = globalDefaults( Seq( outputStrategy :== None, // TODO - This might belong elsewhere. - buildStructure := Project.structure(state.value), - settingsData := buildStructure.value.data, + buildStructure := Def.uncached(Project.structure(state.value)), + settingsData := Def.uncached(buildStructure.value.data), allScopes := ScopeFilter.allScopes.value, checkBuildSources / aggregate :== false, checkBuildSources / changedInputFiles / aggregate := false, - checkBuildSources / Continuous.dynamicInputs := None, + checkBuildSources / Continuous.dynamicInputs := Def.uncached(None), checkBuildSources / fileInputs := CheckBuildSources.buildSourceFileInputs.value, - checkBuildSources := CheckBuildSources.needReloadImpl.value, + checkBuildSources := Def.uncached(CheckBuildSources.needReloadImpl.value), fileCacheSize := "128M", trapExit :== true, connectInput :== false, @@ -374,15 +378,17 @@ object Defaults extends BuildCommon { commandProgress := Seq(), // progressState is deprecated SettingKey[Option[ProgressState]]("progressState") := None, - Previous.cache := new Previous( - Def.streamsManagerKey.value, - Previous.references.value.getReferences + Previous.cache := Def.uncached( + new Previous( + Def.streamsManagerKey.value, + Previous.references.value.getReferences + ) ), Previous.references :== new Previous.References, concurrentRestrictions := defaultRestrictions.value, parallelExecution :== true, fileTreeView :== FileTreeView.default, - Continuous.dynamicInputs := Continuous.dynamicInputsImpl.value, + Continuous.dynamicInputs := Def.uncached(Continuous.dynamicInputsImpl.value), logBuffered :== false, commands :== Nil, showSuccess :== true, @@ -423,7 +429,7 @@ object Defaults extends BuildCommon { pollInterval :== Watch.defaultPollInterval, canonicalInput :== true, echoInput :== true, - terminal := state.value.get(terminalKey).getOrElse(Terminal(ITerminal.get)), + terminal := Def.uncached(state.value.get(terminalKey).getOrElse(Terminal(ITerminal.get))), InstallSbtn.installSbtn := InstallSbtn.installSbtnImpl.evaluated, InstallSbtn.installSbtn / aggregate := false, ) ++ LintUnused.lintSettings @@ -433,7 +439,9 @@ object Defaults extends BuildCommon { private[sbt] lazy val buildLevelJvmSettings: Seq[Setting[?]] = Seq( exportPipelining := usePipelining.value, - sourcePositionMappers := Nil, // Never set a default sourcePositionMapper, see #6352! Whatever you are trying to solve, do it in the foldMappers method. + sourcePositionMappers := Def.uncached( + Nil + ), // Never set a default sourcePositionMapper, see #6352! Whatever you are trying to solve, do it in the foldMappers method. // The virtual file value cache needs to be global or sbt will run out of direct byte buffer memory. classpathDefinesClassCache := VirtualFileValueCache.definesClassCache(fileConverter.value), fullServerHandlers := { @@ -451,7 +459,7 @@ object Defaults extends BuildCommon { }, timeWrappedStamper := Stamps .timeWrapBinaryStamps(Stamps.uncachedStamps(fileConverter.value), fileConverter.value), - reusableStamper := { + reusableStamper := Def.uncached { val converter = fileConverter.value val unmanagedCache = unmanagedFileStampCache.value val managedCache = managedFileStampCache.value @@ -604,7 +612,7 @@ object Defaults extends BuildCommon { unmanagedSourceDirectories.value .map(d => Globs(d.toPath, recursive = true, filter)) ++ baseSources }, - unmanagedSources := (unmanagedSources / inputFileStamps).value.map(_._1.toFile), + unmanagedSources := Def.uncached((unmanagedSources / inputFileStamps).value.map(_._1.toFile)), managedSourceDirectories := Seq(sourceManaged.value), managedSources := { val stamper = inputFileStamper.value @@ -613,7 +621,7 @@ object Defaults extends BuildCommon { res.foreach { f => cache.putIfAbsent(f.toPath, stamper) } - res + Def.uncached(res) }, managedSourcePaths / outputFileStamper := sbt.nio.FileStamper.Hash, managedSourcePaths := managedSources.value.map(_.toPath), @@ -640,14 +648,16 @@ object Defaults extends BuildCommon { } unmanagedResourceDirectories.value.map(d => Globs(d.toPath, recursive = true, filter)) }, - unmanagedResources := (unmanagedResources / inputFileStamps).value.map(_._1.toFile), + unmanagedResources := Def.uncached( + (unmanagedResources / inputFileStamps).value.map(_._1.toFile) + ), resourceGenerators :== Nil, resourceGenerators += (Def.task { PluginDiscovery.writeDescriptors(discoveredSbtPlugins.value, resourceManaged.value) }).taskValue, managedResources := generate(resourceGenerators).value, resources := Classpaths.concat(managedResources, unmanagedResources).value, - resourceDigests := { + resourceDigests := Def.uncached { val uifs = (unmanagedResources / inputFileStamps).value val mifs = (managedResources / inputFileStamps).value (uifs ++ mifs).sortBy(_._1.toString()).map { (p, fileStamp) => @@ -694,7 +704,7 @@ object Defaults extends BuildCommon { } else topLoader }, - scalaInstance := Compiler.scalaInstanceTask.value, + scalaInstance := Def.uncached(Compiler.scalaInstanceTask.value), crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled), pluginCrossBuild / sbtBinaryVersion := binarySbtVersion( (pluginCrossBuild / sbtVersion).value @@ -732,7 +742,7 @@ object Defaults extends BuildCommon { } clean.value }, - scalaCompilerBridgeBinaryJar := { + scalaCompilerBridgeBinaryJar := Def.uncached { val sv = scalaVersion.value val managed = managedScalaInstance.value val hasSbtBridge = ScalaArtifacts.isScala3(sv) || ZincLmUtil.hasScala2SbtBridge(sv) @@ -752,7 +762,7 @@ object Defaults extends BuildCommon { if (ScalaArtifacts.isScala3(scalaVersion.value)) List(TastyFiles.instance) else Nil }, - consoleProject / scalaCompilerBridgeBinaryJar := None, + consoleProject / scalaCompilerBridgeBinaryJar := Def.uncached(None), consoleProject / scalaCompilerBridgeSource := ZincLmUtil.getDefaultBridgeSourceModule( appConfiguration.value.provider.scalaProvider.version ), @@ -762,7 +772,7 @@ object Defaults extends BuildCommon { private lazy val compileBaseGlobal: Seq[Setting[?]] = globalDefaults( Seq( auxiliaryClassFiles :== Nil, - incOptions := IncOptions.of(), + incOptions := Def.uncached(IncOptions.of()), compileOrder :== CompileOrder.Mixed, javacOptions :== Nil, scalacOptions :== Nil, @@ -829,7 +839,7 @@ object Defaults extends BuildCommon { } def compilersSetting = { - compilers := { + compilers := Def.uncached { val st = state.value val g = BuildPaths.getGlobalBase(st) val zincDir = BuildPaths.getZincDirectory(st, g) @@ -882,11 +892,11 @@ object Defaults extends BuildCommon { inTask(compile)(compileInputsSettings) ++ inTask(compileJava)( Seq( - compileInputs := { + compileInputs := Def.uncached { val opts = (compileJava / compileOptions).value (compile / compileInputs).value.withOptions(opts) }, - compileOptions := { + compileOptions := Def.uncached { val opts = (compile / compileOptions).value val cp0 = dependencyClasspath.value val cp1 = backendOutput.value +: data(cp0) @@ -897,7 +907,7 @@ object Defaults extends BuildCommon { ) ) ++ configGlobal ++ compileAnalysisSettings ++ Seq( - compileOutputs := { + compileOutputs := Def.uncached { import scala.jdk.CollectionConverters.* val c = fileConverter.value val (_, vfDir, packedDir) = compileIncremental.value @@ -907,7 +917,7 @@ object Defaults extends BuildCommon { c.toPath(vfDir) :+ c.toPath(packedDir) }, - compileOutputs := compileOutputs.triggeredBy(compile).value, + compileOutputs := Def.uncached(compileOutputs.triggeredBy(compile).value), tastyFiles := Def.taskIf { if (ScalaArtifacts.isScala3(scalaVersion.value)) { val _ = compile.value @@ -921,8 +931,8 @@ object Defaults extends BuildCommon { (compileOutputs / clean).value (products / clean).value }, - earlyOutputPing := Def.promise[Boolean], - compileProgress := { + earlyOutputPing := Def.uncached(Def.promise[Boolean]), + compileProgress := Def.uncached { val s = streams.value val promise = earlyOutputPing.value val mn = moduleName.value @@ -935,19 +945,19 @@ object Defaults extends BuildCommon { } } }, - compileEarly := compileEarlyTask.value, - compile := compileTask.value, - compileScalaBackend := compileScalaBackendTask.value, - compileJava := compileJavaTask.value, + compileEarly := Def.uncached(compileEarlyTask.value), + compile := Def.uncached(compileTask.value), + compileScalaBackend := Def.uncached(compileScalaBackendTask.value), + compileJava := Def.uncached(compileJavaTask.value), compileSplit := { // conditional task - if (incOptions.value.pipelining) compileJava.value - else compileScalaBackend.value + if (incOptions.value.pipelining) Def.uncached(compileJava.value) + else Def.uncached(compileScalaBackend.value) }, internalDependencyConfigurations := InternalDependencies.configurations.value, - manipulateBytecode := compileSplit.value, + manipulateBytecode := Def.uncached(compileSplit.value), printWarnings := printWarningsTask.value, - compileAnalysisFilename := { + compileAnalysisFilename := Def.uncached { // Here, if the user wants cross-scala-versioning, we also append it // to the analysis cache, so we keep the scala versions separated. val binVersion = scalaBinaryVersion.value @@ -962,9 +972,9 @@ object Defaults extends BuildCommon { compileAnalysisFile := { compileAnalysisTargetRoot.value / compileAnalysisFilename.value }, - externalHooks := IncOptions.defaultExternal, + externalHooks := Def.uncached(IncOptions.defaultExternal), zincCompilationListeners := Seq.empty, - incOptions := { + incOptions := Def.uncached { val old = incOptions.value val extHooks = externalHooks.value val newExtHooks = extHooks.withInvalidationProfiler(() => @@ -988,21 +998,23 @@ object Defaults extends BuildCommon { val old = scalacOptions.value val converter = fileConverter.value if (exportPipelining.value) - Vector( - "-Ypickle-java", - "-Ypickle-write", - earlyOutput.value.toString - ) ++ old - else old + Def.uncached( + Vector( + "-Ypickle-java", + "-Ypickle-write", + earlyOutput.value.toString + ) ++ old + ) + else Def.uncached(old) }, persistJarClasspath :== true, - classpathEntryDefinesClassVF := { + classpathEntryDefinesClassVF := Def.uncached { val cache = if persistJarClasspath.value then classpathDefinesClassCache.value else VirtualFileValueCache.definesClassCache(fileConverter.value) cache.get }, - compileIncSetup := compileIncSetupTask.value, + compileIncSetup := Def.uncached(compileIncSetupTask.value), console := consoleTask.value, collectAnalyses := Definition.collectAnalysesTask.map(_ => ()).value, consoleQuick := consoleQuickTask.value, @@ -1011,12 +1023,12 @@ object Defaults extends BuildCommon { .storeAs(discoveredMainClasses) .triggeredBy(compile) .value, - discoveredSbtPlugins := discoverSbtPluginNames.value, + discoveredSbtPlugins := Def.uncached(discoverSbtPluginNames.value), // This fork options, scoped to the configuration is used for tests - forkOptions := forkOptionsTask.value, + forkOptions := Def.uncached(forkOptionsTask.value), selectMainClass := mainClass.value orElse askForMainClass(discoveredMainClasses.value), run / mainClass := (run / selectMainClass).value, - mainClass := { + mainClass := Def.uncached { val logWarning = state.value.currentCommand.forall(!_.commandLine.split(" ").exists { case "run" | "runMain" => true case r => @@ -1052,7 +1064,7 @@ object Defaults extends BuildCommon { // clean := Def.taskDyn(Clean.task(resolvedScoped.value.scope, full = true)).value, clean := Clean.scopedTask.value, consoleProject := consoleProjectTask.value, - transitiveDynamicInputs := WatchTransitiveDependencies.task.value, + transitiveDynamicInputs := Def.uncached(WatchTransitiveDependencies.task.value), ) def generate(generators: SettingKey[Seq[Task[Seq[File]]]]): Initialize[Task[Seq[File]]] = @@ -1080,7 +1092,7 @@ object Defaults extends BuildCommon { testFrameworks :== sbt.TestFrameworks.All, testListeners :== Nil, testOptions :== Nil, - testOptionDigests := Nil, + testOptionDigests :== Nil, testResultLogger :== TestResultLogger.Default, testOnly / testFilter :== (IncrementalTest.selectedFilter), extraTestDigests :== Nil, @@ -1091,13 +1103,13 @@ object Defaults extends BuildCommon { testTaskOptions(testOnly), testTaskOptions(testQuick), testDefaults, - testLoader := ClassLoaders.testTask.value, - loadedTestFrameworks := { + testLoader := Def.uncached(ClassLoaders.testTask.value), + loadedTestFrameworks := Def.uncached { val loader = testLoader.value val log = streams.value.log testFrameworks.value.flatMap(f => f.create(loader, log).map(x => (f, x))).toMap }, - definedTests := detectTests.value, + definedTests := Def.uncached(detectTests.value), definedTestNames := definedTests .map(_.map(_.name).distinct) .storeAs(definedTestNames) @@ -1106,9 +1118,9 @@ object Defaults extends BuildCommon { definedTestDigests := IncrementalTest.definedTestDigestTask .triggeredBy(compile) .value, - testQuick / testFilter := IncrementalTest.filterTask.value, + testQuick / testFilter := Def.uncached(IncrementalTest.filterTask.value), extraTestDigests ++= IncrementalTest.extraTestDigestsTask.value, - executeTests := { + executeTests := Def.uncached({ import sbt.TupleSyntax.* ( test / streams, @@ -1137,10 +1149,10 @@ object Defaults extends BuildCommon { c, ) } - }.value, + }.value), // ((streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test, testForkedParallel, javaOptions in test) flatMap allTestGroupsTask).value, Test / testFull / testResultLogger :== TestResultLogger.SilentWhenNoTests, // https://github.com/sbt/sbt/issues/1185 - testFull := { + testFull := Def.uncached { val trl = (Test / testFull / testResultLogger).value val taskName = Project.showContextKey(state.value).show(resolvedScoped.value) try trl.run(streams.value.log, executeTests.value, taskName) @@ -1175,7 +1187,7 @@ object Defaults extends BuildCommon { def testTaskOptions(key: Scoped): Seq[Setting[?]] = inTask(key)( Seq( - testListeners := { + testListeners := Def.uncached { val stateLogLevel = state.value.get(Keys.logLevel.key).getOrElse(Level.Info) TestLogger.make( streams.value.log, @@ -1192,8 +1204,11 @@ object Defaults extends BuildCommon { ) +: (TaskZero / testListeners).value }, - testOptions := Tests.Listeners(testListeners.value) +: (TaskZero / testOptions).value, - testOptionDigests := { + testOptions := Def.uncached( + Tests.Listeners(testListeners.value) +: (TaskZero / testOptions).value + ), + // This needs to be uncached since testOptions is uncahed. + testOptionDigests := Def.uncached { (TaskZero / testOptions).value.flatMap { case Tests.Setup(_, digest) => Seq(digest) case Tests.Cleanup(_, digest) => Seq(digest) @@ -1206,11 +1221,11 @@ object Defaults extends BuildCommon { case _ => Nil } }, - testExecution := testExecutionTask(key).value + testExecution := Def.uncached(testExecutionTask(key).value), ) ) ++ inScope(GlobalScope)( Seq( - derive(testGrouping := singleTestGroupDefault.value) + derive(testGrouping := Def.uncached(singleTestGroupDefault.value)) ) ) @@ -1741,7 +1756,7 @@ object Defaults extends BuildCommon { (TaskZero / key) := packageTask.value, packageConfiguration := packageConfigurationTask.value, mappings := mappingsTask.value, - packagedArtifact := artifact.value -> key.value, + packagedArtifact := Def.uncached(artifact.value -> key.value), artifact := artifactSetting.value, artifactPath := artifactPathSetting(artifact).value ) @@ -1837,7 +1852,8 @@ object Defaults extends BuildCommon { scalaRun: Initialize[Task[ScalaRun]] ): Initialize[InputTask[Unit]] = RunUtil.serverSideRunTask(classpath, mainClassTask, scalaRun) - def runnerTask: Setting[Task[ScalaRun]] = runner := runnerInit.value + def runnerTask: Setting[Task[ScalaRun]] = + runner := Def.uncached(runnerInit.value) def runnerInit: Initialize[Task[ScalaRun]] = Def.task { val tmp = taskTemporaryDirectory.value @@ -1930,7 +1946,7 @@ object Defaults extends BuildCommon { } } else compileOptions }, - (TaskZero / key) := { + (TaskZero / key) := Def.uncached { val s = streams.value val cs: Compilers = compilers.value val srcs = sources.value @@ -2103,16 +2119,16 @@ object Defaults extends BuildCommon { def compileIncrementalTaskSettings = inTask(compileIncremental)( Seq( - (TaskZero / compileIncremental) := { + TaskZero / compileIncremental := Def.uncached { val bspTask = (compile / bspCompileTask).value val result = cachedCompileIncrementalTask.result.value val reporter = (compile / bspReporter).value - val store = analysisStore(compileAnalysisFile) val ci = (compile / compileInputs).value val c = fileConverter.value val dir = c.toPath(backendOutput.value).toFile result match case Result.Value(res) => + val store = analysisStore(compileAnalysisFile) val analysis = store.unsafeGet().getAnalysis() reporter.sendSuccessReport(analysis) bspTask.notifySuccess(analysis) @@ -2238,7 +2254,7 @@ object Defaults extends BuildCommon { compileInputsSettings(dependencyPicklePath) def compileInputsSettings(classpathTask: TaskKey[Classpath]): Seq[Setting[?]] = { Seq( - compileOptions := { + compileOptions := Def.uncached { val c = fileConverter.value val cp0 = classpathTask.value val cp1 = backendOutput.value +: data(cp0) @@ -2267,14 +2283,14 @@ object Defaults extends BuildCommon { eoOpt.toOptional, ) }, - compilerReporter := { + compilerReporter := Def.uncached { new ManagedLoggedReporter( maxErrors.value, streams.value.log, foldMappers(sourcePositionMappers.value, reportAbsolutePath.value, fileConverter.value) ) }, - compileInputs := { + compileInputs := Def.uncached { val options = compileOptions.value val setup = compileIncSetup.value val prev = previousCompile.value @@ -2286,7 +2302,7 @@ object Defaults extends BuildCommon { ) }, // todo: Zinc's hashing should automatically handle directories - compileInputs2 := { + compileInputs2 := Def.uncached { val cp0 = classpathTask.value val inputs = compileInputs.value val c = fileConverter.value @@ -2300,11 +2316,13 @@ object Defaults extends BuildCommon { ) }, bspCompileTask := - BspCompileTask.start( - bspTargetIdentifier.value, - thisProjectRef.value, - configuration.value, - compileInputs.value + Def.uncached( + BspCompileTask.start( + bspTargetIdentifier.value, + thisProjectRef.value, + configuration.value, + compileInputs.value + ) ) ) } @@ -2330,7 +2348,7 @@ object Defaults extends BuildCommon { private[sbt] def none[A]: Option[A] = (None: Option[A]) private[sbt] def jnone[A]: Optional[A] = none[A].toOptional def compileAnalysisSettings: Seq[Setting[?]] = Seq( - previousCompile := { + previousCompile := Def.uncached { val setup = compileIncSetup.value val store = analysisStore(compileAnalysisFile) val prev = store.get().toOption match { @@ -2442,9 +2460,13 @@ object Defaults extends BuildCommon { // 1. runnerSettings is added unscoped via JvmPlugin. // 2. In addition it's added scoped to run task. - lazy val runnerSettings: Seq[Setting[?]] = Seq(runnerTask, forkOptions := forkOptionsTask.value) + lazy val runnerSettings: Seq[Setting[?]] = + Seq(runnerTask, forkOptions := Def.uncached(forkOptionsTask.value)) private lazy val newRunnerSettings: Seq[Setting[?]] = - Seq(runner := ClassLoaders.runner.value, forkOptions := forkOptionsTask.value) + Seq( + runner := Def.uncached(ClassLoaders.runner.value), + forkOptions := Def.uncached(forkOptionsTask.value) + ) lazy val baseTasks: Seq[Setting[?]] = projectTasks ++ packageBase @@ -2551,13 +2573,15 @@ object Classpaths { // Included as part of JvmPlugin#projectSettings. lazy val configSettings: Seq[Setting[?]] = classpaths ++ Seq( products := makeProducts.value, - pickleProducts := makePickleProducts.value, + pickleProducts := Def.uncached(makePickleProducts.value), productDirectories := classDirectory.value :: Nil, - classpathConfiguration := findClasspathConfig( - internalConfigurationMap.value, - configuration.value, - classpathConfiguration.?.value, - update.value + classpathConfiguration := Def.uncached( + findClasspathConfig( + internalConfigurationMap.value, + configuration.value, + classpathConfiguration.?.value, + update.value + ) ) ) private def classpaths: Seq[Setting[?]] = @@ -2566,8 +2590,8 @@ object Classpaths { dependencyClasspath := concat(internalDependencyClasspath, externalDependencyClasspath).value, fullClasspath := concatDistinct(exportedProducts, dependencyClasspath).value, internalDependencyClasspath := ClasspathImpl.internalDependencyClasspathTask.value, - unmanagedClasspath := ClasspathImpl.unmanagedDependenciesTask.value, - managedClasspath := { + unmanagedClasspath := Def.uncached(ClasspathImpl.unmanagedDependenciesTask.value), + managedClasspath := Def.uncached { val converter = fileConverter.value val isMeta = isMetaBuild.value val force = reresolveSbtArtifacts.value @@ -2601,21 +2625,27 @@ object Classpaths { exportedProductJarsNoTracking := ClasspathImpl .trackedExportedJarProducts(TrackLevel.NoTracking) .value, - internalDependencyAsJars := internalDependencyJarsTask.value, - dependencyClasspathAsJars := concat( - internalDependencyAsJars, - externalDependencyClasspath - ).value, - fullClasspathAsJars := concatDistinct(exportedProductJars, dependencyClasspathAsJars).value, - unmanagedJars := findUnmanagedJars( - configuration.value, - unmanagedBase.value, - (unmanagedJars / includeFilter).value, - (unmanagedJars / excludeFilter).value, - fileConverter.value, + internalDependencyAsJars := Def.uncached(internalDependencyJarsTask.value), + dependencyClasspathAsJars := Def.uncached( + concat( + internalDependencyAsJars, + externalDependencyClasspath + ).value + ), + fullClasspathAsJars := Def.uncached( + concatDistinct(exportedProductJars, dependencyClasspathAsJars).value + ), + unmanagedJars := Def.uncached( + findUnmanagedJars( + configuration.value, + unmanagedBase.value, + (unmanagedJars / includeFilter).value, + (unmanagedJars / excludeFilter).value, + fileConverter.value, + ) ) ).map(exportVirtualClasspath) ++ Seq( - externalDependencyClasspath / outputFileStamps := { + externalDependencyClasspath / outputFileStamps := Def.uncached { val stamper = timeWrappedStamper.value val converter = fileConverter.value externalDependencyClasspath.value.flatMap: vf => @@ -2626,7 +2656,7 @@ object Classpaths { val converter = fileConverter.value data(dependencyClasspath.value).map(converter.toPath) }, - dependencyClasspathFiles / outputFileStamps := { + dependencyClasspathFiles / outputFileStamps := Def.uncached { val stamper = timeWrappedStamper.value val converter = fileConverter.value dependencyClasspathFiles.value.flatMap: p => @@ -2724,9 +2754,10 @@ object Classpaths { } val jvmPublishSettings: Seq[Setting[?]] = Seq( artifacts := artifactDefs(defaultArtifactTasks).value, - packagedArtifacts := Def - .ifS(publishSbtPluginMavenStyle)(mavenArtifactsOfSbtPlugin)(packagedDefaultArtifacts) - .value, + packagedArtifacts := { + if publishSbtPluginMavenStyle.value then Def.uncached(mavenArtifactsOfSbtPlugin.value) + else Def.uncached(packagedDefaultArtifacts.value) + }, // publishLocal needs legacy artifacts (see https://github.com/sbt/sbt/issues/7285) publishLocal / packagedArtifacts ++= { if (sbtPlugin.value && !sbtPluginPublishLegacyMavenStyle.value) { @@ -2808,21 +2839,21 @@ object Classpaths { def ivyPublishSettings: Seq[Setting[?]] = publishGlobalDefaults ++ Seq( artifacts :== Nil, packagedArtifacts :== Map.empty, - makePom := { + makePom := Def.uncached { val converter = fileConverter.value val config = makePomConfiguration.value val publisher = Keys.publisher.value publisher.makePomFile(ivyModule.value, config, streams.value.log) converter.toVirtualFile(config.file.get.toPath()) }, - (makePom / packagedArtifact) := ((makePom / artifact).value -> makePom.value), + (makePom / packagedArtifact) := Def.uncached((makePom / artifact).value -> makePom.value), deliver := deliverTask(makeIvyXmlConfiguration).value, deliverLocal := deliverTask(makeIvyXmlLocalConfiguration).value, makeIvyXml := deliverTask(makeIvyXmlConfiguration).value, publish := publishOrSkip(publishConfiguration, publish / skip).value, publishLocal := publishOrSkip(publishLocalConfiguration, publishLocal / skip).value, publishM2 := publishOrSkip(publishM2Configuration, publishM2 / skip).value, - credentials ++= { + credentials ++= Def.uncached { val alreadyContainsCentralCredentials: Boolean = credentials.value.exists { case d: DirectCredentials => d.host == Sona.host case _ => false @@ -2931,16 +2962,18 @@ object Classpaths { developers.value.toVector ), overrideBuildResolvers := appConfiguration(isOverrideRepositories).value, - externalResolvers := (( - externalResolvers.?.value, - resolvers.value, - appResolvers.value, - ) match { - case (Some(delegated), Seq(), _) => delegated - case (_, rs, Some(ars)) => ars ++ rs - case (_, rs, _) => - Resolver.combineDefaultResolvers(rs.toVector, mavenCentral = true) - }), + externalResolvers := Def.uncached( + ( + externalResolvers.?.value, + resolvers.value, + appResolvers.value, + ) match { + case (Some(delegated), Seq(), _) => delegated + case (_, rs, Some(ars)) => ars ++ rs + case (_, rs, _) => + Resolver.combineDefaultResolvers(rs.toVector, mavenCentral = true) + } + ), appResolvers := { val ac = appConfiguration.value appRepositories(ac) map { ars => @@ -2948,11 +2981,11 @@ object Classpaths { Resolver.reorganizeAppResolvers(ars, useMavenCentral) } }, - bootResolvers := { + bootResolvers := Def.uncached { appConfiguration.map(bootRepositories).value }, fullResolvers := - (Def.task { + Def.uncached((Def.task { val proj = projectResolver.value val rs = externalResolvers.value def pluginResolvers: Vector[Resolver] = @@ -2972,7 +3005,7 @@ object Classpaths { val base = if (sbtPlugin.value) sbtResolvers.value ++ rs ++ pr else rs ++ pr (proj +: base).distinct } - }).value, + }).value), moduleName := normalizedName.value, outputPath := { val p = platform.value @@ -3002,13 +3035,13 @@ object Classpaths { val st = state.value BuildPaths.getDependencyDirectory(st, BuildPaths.getGlobalBase(st)) }, - otherResolvers := Resolver.publishMavenLocal +: publishTo.value.toVector, - projectResolver := projectResolverTask.value, - projectDependencies := projectDependenciesTask.value, + otherResolvers := Def.uncached(Resolver.publishMavenLocal +: publishTo.value.toVector), + projectResolver := Def.uncached(projectResolverTask.value), + projectDependencies := Def.uncached(projectDependenciesTask.value), // TODO - Is this the appropriate split? Ivy defines this simply as // just project + library, while the JVM plugin will define it as // having the additional sbtPlugin + autoScala magikz. - allDependencies := { + allDependencies := Def.uncached { projectDependencies.value ++ libraryDependencies.value }, allExcludeDependencies := excludeDependencies.value, @@ -3033,7 +3066,7 @@ object Classpaths { makePom / artifact := Artifact.pom(moduleName.value), projectID := defaultProjectID.value, projectID := pluginProjectID.value, - projectDescriptors := depMap.value, + projectDescriptors := Def.uncached(depMap.value), updateConfiguration := { // Tell the UpdateConfiguration which artifact types are special (for sources and javadocs) val specialArtifactTypes = sourceArtifactTypes.value.toSet union docArtifactTypes.value.toSet @@ -3055,9 +3088,9 @@ object Classpaths { ) else None }, - dependencyResolution := dependencyResolutionTask.value, - publisher := IvyPublisher(ivyConfiguration.value), - ivyConfiguration := mkIvyConfiguration.value, + dependencyResolution := Def.uncached(dependencyResolutionTask.value), + publisher := Def.uncached(IvyPublisher(ivyConfiguration.value)), + ivyConfiguration := Def.uncached(mkIvyConfiguration.value), ivyConfigurations := { val confs = thisProject.value.configurations (confs ++ confs.map(internalConfigurationMap.value) ++ (if (autoCompilerPlugins.value) @@ -3106,7 +3139,7 @@ object Classpaths { confs ++ extraSources.toSeq ++ extraDocs.toSeq }, - moduleSettings := moduleSettings0.value, + moduleSettings := Def.uncached(moduleSettings0.value), makePomConfiguration := { val converter = fileConverter.value val out = converter.toPath((makePom / artifactPath).value) @@ -3119,7 +3152,7 @@ object Classpaths { .withAllRepositories(pomAllRepositories.value) .withConfigurations(Configurations.defaultMavenConfigurations) }, - makeIvyXmlConfiguration := { + makeIvyXmlConfiguration := Def.uncached { makeIvyXmlConfig( publishMavenStyle.value, sbt.Classpaths.deliverPattern(target.value), @@ -3130,7 +3163,7 @@ object Classpaths { isSnapshot.value ) }, - publishConfiguration := { + publishConfiguration := Def.uncached { val s = streams.value val vs = versionScheme.value if (vs.isEmpty) @@ -3155,7 +3188,7 @@ object Classpaths { isSnapshot.value ) }, - makeIvyXmlLocalConfiguration := { + makeIvyXmlLocalConfiguration := Def.uncached { makeIvyXmlConfig( false, // publishMavenStyle.value, sbt.Classpaths.deliverPattern(target.value), @@ -3167,7 +3200,7 @@ object Classpaths { optResolverName = Some("local") ) }, - publishLocalConfiguration := { + publishLocalConfiguration := Def.uncached { val converter = fileConverter.value val artifacts = (publishLocal / packagedArtifacts).value.toVector.map { (a, vf) => a -> converter.toPath(vf).toFile @@ -3183,7 +3216,7 @@ object Classpaths { overwrite = isSnapshot.value ) }, - publishM2Configuration := { + publishM2Configuration := Def.uncached { val converter = fileConverter.value val artifacts = (publishM2 / packagedArtifacts).value.toVector.map { (a, vf) => a -> converter.toPath(vf).toFile @@ -3200,22 +3233,24 @@ object Classpaths { overwrite = isSnapshot.value ) }, - ivySbt := ivySbt0.value, - ivyModule := { val is = ivySbt.value; new is.Module(moduleSettings.value) }, - allCredentials := LMCoursier.allCredentialsTask.value, - transitiveUpdate := transitiveUpdateTask.value, + ivySbt := Def.uncached(ivySbt0.value), + ivyModule := Def.uncached { val is = ivySbt.value; new is.Module(moduleSettings.value) }, + allCredentials := Def.uncached(LMCoursier.allCredentialsTask.value), + transitiveUpdate := Def.uncached(transitiveUpdateTask.value), updateCacheName := { val binVersion = scalaBinaryVersion.value val suffix = if (crossPaths.value) s"_$binVersion" else "" s"update_cache$suffix" }, - dependencyPositions := dependencyPositionsTask.value, - update / unresolvedWarningConfiguration := UnresolvedWarningConfiguration( - dependencyPositions.value + dependencyPositions := Def.uncached(dependencyPositionsTask.value), + update / unresolvedWarningConfiguration := Def.uncached( + UnresolvedWarningConfiguration( + dependencyPositions.value + ) ), - updateFull := updateTask.value, - update := updateWithoutDetails("update").value, - update := { + updateFull := Def.uncached(updateTask.value), + update := Def.uncached(updateWithoutDetails("update").value), + update := Def.uncached { val report = update.value val log = streams.value.log ConflictWarning(conflictWarning.value, report, log) @@ -3223,7 +3258,7 @@ object Classpaths { }, update / evictionWarningOptions := evictionWarningOptions.value, evicted / evictionWarningOptions := EvictionWarningOptions.full, - evicted := { + evicted := Def.uncached { import ShowLines.* val report = updateTask.value val log = streams.value.log @@ -3236,7 +3271,7 @@ object Classpaths { ) ++ inTask(updateClassifiers)( Seq( - classifiersModule := { + classifiersModule := Def.uncached { val key = (m: ModuleID) => (m.organization, m.name, m.revision) val projectDeps = projectDependencies.value.iterator.map(key).toSet val externalModules = update.value.allModules.filterNot(m => projectDeps contains key(m)) @@ -3248,19 +3283,27 @@ object Classpaths { transitiveClassifiers.value.toVector ) }, - dependencyResolution := dependencyResolutionTask.value, - csrConfiguration := LMCoursier.updateClassifierConfigurationTask.value, - TaskZero / updateClassifiers := LibraryManagement.updateClassifiersTask.value, + dependencyResolution := Def.uncached(dependencyResolutionTask.value), + csrConfiguration := Def.uncached(LMCoursier.updateClassifierConfigurationTask.value), + TaskZero / updateClassifiers := Def.uncached(LibraryManagement.updateClassifiersTask.value), ) ) ++ Seq( - csrProject := CoursierInputsTasks.coursierProjectTask.value, - csrConfiguration := LMCoursier.coursierConfigurationTask.value, - csrResolvers := CoursierRepositoriesTasks.coursierResolversTask(fullResolvers).value, - csrRecursiveResolvers := CoursierRepositoriesTasks.coursierRecursiveResolversTask.value, - csrSbtResolvers := CoursierRepositoriesTasks.coursierSbtResolversTask.value, - csrInterProjectDependencies := CoursierInputsTasks.coursierInterProjectDependenciesTask.value, - csrExtraProjects := CoursierInputsTasks.coursierExtraProjectsTask.value, - csrFallbackDependencies := CoursierInputsTasks.coursierFallbackDependenciesTask.value, + csrProject := Def.uncached(CoursierInputsTasks.coursierProjectTask.value), + csrConfiguration := Def.uncached(LMCoursier.coursierConfigurationTask.value), + csrResolvers := Def.uncached( + CoursierRepositoriesTasks.coursierResolversTask(fullResolvers).value + ), + csrRecursiveResolvers := Def.uncached( + CoursierRepositoriesTasks.coursierRecursiveResolversTask.value + ), + csrSbtResolvers := Def.uncached(CoursierRepositoriesTasks.coursierSbtResolversTask.value), + csrInterProjectDependencies := Def.uncached( + CoursierInputsTasks.coursierInterProjectDependenciesTask.value + ), + csrExtraProjects := Def.uncached(CoursierInputsTasks.coursierExtraProjectsTask.value), + csrFallbackDependencies := Def.uncached( + CoursierInputsTasks.coursierFallbackDependenciesTask.value + ), ) ++ IvyXml.generateIvyXmlSettings() ++ LMCoursier.publicationsSetting(Seq(Compile, Test).map(c => c -> CConfiguration(c.name))) @@ -3273,7 +3316,7 @@ object Classpaths { scalaVersion.value ), // Override the default to handle mixing in the sbtPlugin + scala dependencies. - allDependencies := { + allDependencies := Def.uncached { val base = projectDependencies.value ++ libraryDependencies.value val isPlugin = sbtPlugin.value val sbtdeps = @@ -3405,7 +3448,7 @@ object Classpaths { sbtClassifiersGlobalDefaults ++ inTask(updateSbtClassifiers)( Seq( - externalResolvers := { + externalResolvers := Def.uncached { val boot = bootResolvers.value val explicit = buildStructure.value .units(thisProjectRef.value.build) @@ -3415,20 +3458,22 @@ object Classpaths { .resolvers explicit orElse boot getOrElse externalResolvers.value }, - ivyConfiguration := InlineIvyConfiguration( - lock = Option(lock(appConfiguration.value)), - log = Option(streams.value.log), - updateOptions = UpdateOptions(), - paths = Option(ivyPaths.value), - resolvers = externalResolvers.value.toVector, - otherResolvers = Vector.empty, - moduleConfigurations = Vector.empty, - checksums = checksums.value.toVector, - managedChecksums = false, - resolutionCacheDir = Some(target.value / "resolution-cache"), + ivyConfiguration := Def.uncached( + InlineIvyConfiguration( + lock = Option(lock(appConfiguration.value)), + log = Option(streams.value.log), + updateOptions = UpdateOptions(), + paths = Option(ivyPaths.value), + resolvers = externalResolvers.value.toVector, + otherResolvers = Vector.empty, + moduleConfigurations = Vector.empty, + checksums = checksums.value.toVector, + managedChecksums = false, + resolutionCacheDir = Some(target.value / "resolution-cache"), + ) ), - ivySbt := ivySbt0.value, - classifiersModule := classifiersModuleTask.value, + ivySbt := Def.uncached(ivySbt0.value), + classifiersModule := Def.uncached(classifiersModuleTask.value), // Redefine scalaVersion and scalaBinaryVersion specifically for the dependency graph used for updateSbtClassifiers task. // to fix https://github.com/sbt/sbt/issues/2686 scalaVersion := appConfiguration.value.provider.scalaProvider.version, @@ -3446,62 +3491,68 @@ object Classpaths { ).withScalaOrganization(scalaOrganization.value) ) }, - dependencyResolution := dependencyResolutionTask.value, - csrConfiguration := LMCoursier.updateSbtClassifierConfigurationTask.value, - (TaskZero / updateSbtClassifiers) := (Def - .task { - val lm = dependencyResolution.value - val s = streams.value - val is = ivySbt.value - val mod = classifiersModule.value - val updateConfig0 = updateConfiguration.value - val updateConfig = updateConfig0 - .withMetadataDirectory(dependencyCacheDirectory.value) - .withArtifactFilter( - updateConfig0.artifactFilter.map(af => af.withInverted(!af.inverted)) - ) - val app = appConfiguration.value - val srcTypes = sourceArtifactTypes.value - val docTypes = docArtifactTypes.value - val log = s.log - val out = is.withIvy(log)(_.getSettings.getDefaultIvyUserDir) - val uwConfig = (update / unresolvedWarningConfiguration).value - withExcludes(out, mod.classifiers, lock(app)) { excludes => - // val noExplicitCheck = ivy.map(_.withCheckExplicit(false)) - LibraryManagement.transitiveScratch( - lm, - "sbt", - GetClassifiersConfiguration( - mod, - excludes.toVector, - updateConfig, - srcTypes.toVector, - docTypes.toVector - ), - uwConfig, - log - ) match { - case Left(_) => ??? - case Right(ur) => ur + dependencyResolution := Def.uncached(dependencyResolutionTask.value), + csrConfiguration := Def.uncached(LMCoursier.updateSbtClassifierConfigurationTask.value), + (TaskZero / updateSbtClassifiers) := Def.uncached( + (Def + .task { + val lm = dependencyResolution.value + val s = streams.value + val is = ivySbt.value + val mod = classifiersModule.value + val updateConfig0 = updateConfiguration.value + val updateConfig = updateConfig0 + .withMetadataDirectory(dependencyCacheDirectory.value) + .withArtifactFilter( + updateConfig0.artifactFilter.map(af => af.withInverted(!af.inverted)) + ) + val app = appConfiguration.value + val srcTypes = sourceArtifactTypes.value + val docTypes = docArtifactTypes.value + val log = s.log + val out = is.withIvy(log)(_.getSettings.getDefaultIvyUserDir) + val uwConfig = (update / unresolvedWarningConfiguration).value + withExcludes(out, mod.classifiers, lock(app)) { excludes => + // val noExplicitCheck = ivy.map(_.withCheckExplicit(false)) + LibraryManagement.transitiveScratch( + lm, + "sbt", + GetClassifiersConfiguration( + mod, + excludes.toVector, + updateConfig, + srcTypes.toVector, + docTypes.toVector + ), + uwConfig, + log + ) match { + case Left(_) => ??? + case Right(ur) => ur + } } } - } - .tag(Tags.Update, Tags.Network)) - .value + .tag(Tags.Update, Tags.Network)) + .value + ) ) ) ++ inTask(scalaCompilerBridgeScope)( Seq( - dependencyResolution := dependencyResolutionTask.value, - csrConfiguration := LMCoursier.scalaCompilerBridgeConfigurationTask.value, + dependencyResolution := Def.uncached(dependencyResolutionTask.value), + csrConfiguration := Def.uncached(LMCoursier.scalaCompilerBridgeConfigurationTask.value), csrResolvers := - CoursierRepositoriesTasks.coursierResolversTask(scalaCompilerBridgeResolvers).value, - externalResolvers := scalaCompilerBridgeResolvers.value, + Def.uncached( + CoursierRepositoriesTasks.coursierResolversTask(scalaCompilerBridgeResolvers).value + ), + externalResolvers := Def.uncached(scalaCompilerBridgeResolvers.value), ) ) ++ Seq( - bootIvyConfiguration := (updateSbtClassifiers / ivyConfiguration).value, - bootDependencyResolution := (updateSbtClassifiers / dependencyResolution).value, - scalaCompilerBridgeResolvers := { + bootIvyConfiguration := Def.uncached((updateSbtClassifiers / ivyConfiguration).value), + bootDependencyResolution := Def.uncached( + (updateSbtClassifiers / dependencyResolution).value + ), + scalaCompilerBridgeResolvers := Def.uncached { val boot = bootResolvers.value val explicit = buildStructure.value .units(thisProjectRef.value.build) @@ -3519,7 +3570,9 @@ object Classpaths { } (xs ++ ext).distinct }, - scalaCompilerBridgeDependencyResolution := (scalaCompilerBridgeScope / dependencyResolution).value + scalaCompilerBridgeDependencyResolution := Def.uncached( + (scalaCompilerBridgeScope / dependencyResolution).value + ), ) val moduleIdJsonKeyFormat: sjsonnew.JsonKeyFormat[ModuleID] = @@ -4223,7 +4276,7 @@ object Classpaths { } lazy val compilerPluginConfig = Seq( - scalacOptions := { + scalacOptions := Def.uncached { given FileConverter = fileConverter.value val options = scalacOptions.value val newPlugins = autoPlugins( @@ -4468,7 +4521,7 @@ trait BuildExtra extends BuildCommon with DefExtra { /** Constructs a setting that declares a new artifact `a` that is generated by `taskDef`. */ def addArtifact(a: Artifact, taskDef: TaskKey[HashedVirtualFileRef]): SettingsDefinition = { - val pkgd = packagedArtifacts := packagedArtifacts.value.updated(a, taskDef.value) + val pkgd = packagedArtifacts := Def.uncached(packagedArtifacts.value.updated(a, taskDef.value)) Seq(artifacts += a, pkgd) } @@ -4476,13 +4529,19 @@ trait BuildExtra extends BuildCommon with DefExtra { def addArtifact( artifact: Initialize[Artifact], taskDef: Initialize[Task[HashedVirtualFileRef]] - ): SettingsDefinition = { + ): SettingsDefinition = val artLocal = SettingKey.local[Artifact] val taskLocal = TaskKey.local[HashedVirtualFileRef] val art = artifacts := artLocal.value +: artifacts.value - val pkgd = packagedArtifacts := packagedArtifacts.value.updated(artLocal.value, taskLocal.value) - Seq(artLocal := artifact.value, taskLocal := taskDef.value, art, pkgd) - } + val pkgd = packagedArtifacts := Def.uncached( + packagedArtifacts.value.updated(artLocal.value, taskLocal.value) + ) + Seq( + artLocal := artifact.value, + taskLocal := taskDef.value, + art, + pkgd, + ) def runInputTask( config: Configuration, @@ -4522,7 +4581,7 @@ trait BuildExtra extends BuildCommon with DefExtra { } } }.evaluated - ) ++ inTask(scoped)((config / forkOptions) := forkOptionsTask.value) + ) ++ inTask(scoped)((config / forkOptions) := Def.uncached(forkOptionsTask.value)) } // public API @@ -4544,7 +4603,7 @@ trait BuildExtra extends BuildCommon with DefExtra { r.run(mainClass, cp.files, arguments, s.log).get } }.value - ) ++ inTask(scoped)((config / forkOptions) := forkOptionsTask.value) + ) ++ inTask(scoped)((config / forkOptions) := Def.uncached(forkOptionsTask.value)) def initScoped[T](sk: ScopedKey[?], i: Initialize[T]): Initialize[T] = initScope(fillTaskAxis(sk.scope, sk.key), i) @@ -4556,7 +4615,7 @@ trait BuildExtra extends BuildCommon with DefExtra { * This is useful for reducing Test/compile time when not running test. */ def noTestCompletion(config: Configuration = Test): Setting[?] = - inConfig(config)(Seq(definedTests := detectTests.value)).head + inConfig(config)(Seq(definedTests := Def.uncached(detectTests.value))).head def filterKeys(ss: Seq[Setting[?]], transitive: Boolean = false)( f: ScopedKey[?] => Boolean diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index b135a93c9..73f4ed550 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -629,7 +629,7 @@ object EvaluateTask { // if the return type Seq[Setting[_]] is not explicitly given, scalac hangs val injectStreams: ScopedKey[?] => Seq[Setting[?]] = scoped => if (scoped.key == streams.key) { - Seq(scoped.scope / streams := { + Seq(scoped.scope / streams := Def.uncached { (streamsManager.map { mgr => val stream = mgr(scoped) stream.open() diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index a295ba30a..02a5c2a56 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -180,8 +180,12 @@ object Keys { // Output paths @cacheLevel(include = Array.empty) val classDirectory = settingKey[File]("Directory for compiled classes and copied resources.").withRank(AMinusSetting) + + @cacheLevel(include = Array.empty) val earlyOutput = settingKey[VirtualFile]("JAR file for pickles used for build pipelining") val backendOutput = settingKey[VirtualFile]("Output directory of the compiler backend") + + @cacheLevel(include = Array.empty) val cleanFiles = taskKey[Seq[File]]("The files to recursively delete during a clean.").withRank(BSetting) val cleanKeepFiles = settingKey[Seq[File]]("Files or directories to keep during a clean. Must be direct children of target.").withRank(CSetting) val cleanKeepGlobs = settingKey[Seq[Glob]]("Globs to keep during a clean. Must be direct children of target.").withRank(CSetting) @@ -209,6 +213,7 @@ object Keys { val compileInputs = taskKey[Inputs]("Collects all inputs needed for compilation.").withRank(DTask) val compileInputs2 = taskKey[CompileInputs2]("") val scalaHome = settingKey[Option[File]]("If Some, defines the local Scala installation to use for compilation, running, and testing.").withRank(ASetting) + @cacheLevel(include = Array.empty) val scalaInstance = taskKey[ScalaInstance]("Defines the Scala instance to use for compilation, running, and testing.").withRank(DTask) val scalaOrganization = settingKey[String]("Organization/group ID of the Scala used in the project. Default value is 'org.scala-lang'. This is an advanced setting used for clones of the Scala Language. It should be disregarded in standard use cases.").withRank(CSetting) val scalaVersion = settingKey[String]("The version of Scala used for building.").withRank(APlusSetting) @@ -301,7 +306,11 @@ object Keys { val artifact = settingKey[Artifact]("Describes an artifact.").withRank(BMinusSetting) val artifactClassifier = settingKey[Option[String]]("Sets the classifier used by the default artifact definition.").withRank(BSetting) val artifactName = settingKey[(ScalaVersion, ModuleID, Artifact) => String]("Function that produces the artifact name from its definition.").withRank(CSetting) + + @cacheLevel(include = Array.empty) val mappings = taskKey[Seq[(HashedVirtualFileRef, String)]]("Defines the mappings from a file to a path, used by packaging, for example.").withRank(BTask) + + @cacheLevel(include = Array.empty) val fileMappings = taskKey[Seq[(File, File)]]("Defines the mappings from a file to a file, used for copying files, for example.").withRank(BMinusTask) // Run Keys @@ -356,6 +365,8 @@ object Keys { val testOptions = taskKey[Seq[TestOption]]("Options for running tests.").withRank(BPlusTask) private[sbt] val testOptionDigests = taskKey[Seq[Digest]]("Digest for testOptions").withRank(DTask) val testFrameworks = settingKey[Seq[TestFramework]]("Registered, although not necessarily present, test frameworks.").withRank(CTask) + + @cacheLevel(include = Array.empty) val testListeners = taskKey[Seq[TestReportListener]]("Defines test listeners.").withRank(DTask) val testForkedParallel = settingKey[Boolean]("Whether forked tests should be executed in parallel").withRank(CTask) val testExecution = taskKey[Tests.Execution]("Settings controlling test execution").withRank(DTask) @@ -486,6 +497,8 @@ object Keys { val csrExtraProjects = taskKey[Seq[lmcoursier.definitions.Project]]("").withRank(CTask) val csrFallbackDependencies = taskKey[Seq[FallbackDependency]]("") val csrLogger = taskKey[Option[CacheLogger]]("") + + @cacheLevel(include = Array.empty) val csrExtraCredentials = taskKey[Seq[lmcoursier.credentials.Credentials]]("") val csrPublications = taskKey[Seq[(lmcoursier.definitions.Configuration, lmcoursier.definitions.Publication)]]("") val csrReconciliations = settingKey[Seq[(ModuleMatchers, Reconciliation)]]("Strategy to reconcile version conflicts.") @@ -535,7 +548,10 @@ object Keys { val packagedArtifacts = taskKey[Map[Artifact, HashedVirtualFileRef]]("Packages all artifacts for publishing and maps the Artifact definition to the generated file.").withRank(CTask) val publishMavenStyle = settingKey[Boolean]("Configures whether to generate and publish a pom (true) or Ivy file (false).").withRank(BSetting) val sbtPluginPublishLegacyMavenStyle = settingKey[Boolean]("Configuration for generating the legacy pom of sbt plugins, to publish to Maven").withRank(CSetting) + + @cacheLevel(include = Array.empty) val credentials = taskKey[Seq[Credentials]]("The credentials to use for updating and publishing.").withRank(BMinusTask) + @cacheLevel(include = Array.empty) val allCredentials = taskKey[Seq[Credentials]]("Aggregated credentials across current and root subprojects. Do not rewire this task.").withRank(DTask) val makePom = taskKey[HashedVirtualFileRef]("Generates a pom for publishing when publishing Maven-style.").withRank(BPlusTask) @@ -564,9 +580,15 @@ object Keys { val appResolvers = settingKey[Option[Seq[Resolver]]]("The resolvers configured for this application by the sbt launcher.").withRank(BMinusSetting) val externalResolvers = taskKey[Seq[Resolver]]("The external resolvers for automatically managed dependencies.").withRank(BMinusSetting) val resolvers = settingKey[Seq[Resolver]]("The user-defined additional resolvers for automatically managed dependencies.").withRank(BMinusTask) + + @cacheLevel(include = Array.empty) val projectResolver = taskKey[Resolver]("Resolver that handles inter-project dependencies.").withRank(DTask) val fullResolvers = taskKey[Seq[Resolver]]("Combines the project resolver, default resolvers, and user-defined resolvers.").withRank(CTask) + + @cacheLevel(include = Array.empty) val otherResolvers = taskKey[Seq[Resolver]]("Resolvers not included in the main resolver chain, such as those in module configurations.").withRank(CSetting) + + @cacheLevel(include = Array.empty) val scalaCompilerBridgeResolvers = taskKey[Seq[Resolver]]("Resolvers used to resolve compiler bridges.").withRank(CSetting) val includePluginResolvers = settingKey[Boolean]("Include the resolvers from the metabuild.").withRank(CSetting) val moduleConfigurations = settingKey[Seq[ModuleConfiguration]]("Defines module configurations, which override resolvers on a per-module basis.").withRank(BMinusSetting) @@ -585,6 +607,8 @@ object Keys { val scalaModuleInfo = settingKey[Option[ScalaModuleInfo]]("Configures how Scala dependencies are checked, filtered, and injected.").withRank(CSetting) val ivyValidate = settingKey[Boolean]("Enables/disables Ivy validation of module metadata.").withRank(BSetting) val ivyLoggingLevel = settingKey[UpdateLogging]("The logging level for updating.").withRank(BSetting) + + @cacheLevel(include = Array.empty) val publishTo = taskKey[Option[Resolver]]("The resolver to publish to.").withRank(ASetting) val artifacts = settingKey[Seq[Artifact]]("The artifact definitions for the current module. Must be consistent with " + packagedArtifacts.key.label + ".").withRank(BSetting) val projectDescriptors = taskKey[Map[ModuleRevisionId, ModuleDescriptor]]("Project dependency map for the inter-project resolver.").withRank(DTask) @@ -641,6 +665,8 @@ object Keys { val streams = taskKey[TaskStreams]("Provides streams for logging and persisting data.").withRank(DTask) val taskDefinitionKey = Def.taskDefinitionKey val (executionRoots, dummyRoots) = Def.dummy[Seq[ScopedKey[?]]]("executionRoots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.") + + @cacheLevel(include = Array.empty) val state = Def.stateKey val streamsManager = Def.streamsManagerKey // wrapper to work around SI-2915 diff --git a/main/src/main/scala/sbt/Opts.scala b/main/src/main/scala/sbt/Opts.scala index db9060582..07711a489 100644 --- a/main/src/main/scala/sbt/Opts.scala +++ b/main/src/main/scala/sbt/Opts.scala @@ -90,7 +90,7 @@ object DefaultOptions { def credentials(state: State): Credentials = Credentials(getGlobalSettingsDirectory(state, getGlobalBase(state)) / ".credentials") - def addCredentials: Setting[?] = Keys.credentials += { credentials(Keys.state.value) } + def addCredentials: Setting[?] = Keys.credentials += credentials(Keys.state.value) def shellPrompt(version: String): State => String = s => s"${s.configuration.provider.id.name}:${Project.extract(s).currentProject.id}:${version}> " diff --git a/main/src/main/scala/sbt/RemoteCache.scala b/main/src/main/scala/sbt/RemoteCache.scala index b48b6027d..7c100ab95 100644 --- a/main/src/main/scala/sbt/RemoteCache.scala +++ b/main/src/main/scala/sbt/RemoteCache.scala @@ -37,6 +37,7 @@ import sbt.nio.Keys.{ inputFileStamps, outputFileStamps } import sbt.std.TaskExtra.* import sbt.util.InterfaceUtil.toOption import sbt.util.{ DiskActionCacheStore, Logger } +import sbt.util.CacheImplicits.given import sjsonnew.JsonFormat import xsbti.{ FileConverter, HashedVirtualFileRef, VirtualFileRef } import xsbti.compile.CompileAnalysis @@ -74,7 +75,7 @@ object RemoteCache { lazy val globalSettings: Seq[Def.Setting[?]] = Seq( remoteCacheId := "", - remoteCacheIdCandidates := Nil, + remoteCacheIdCandidates :== Nil, pushRemoteCacheTo :== None, localCacheDirectory :== defaultCacheLocation, pushRemoteCache / ivyPaths := { @@ -139,14 +140,14 @@ object RemoteCache { } }) .value, - pushRemoteCacheConfiguration / remoteCacheArtifacts := { + pushRemoteCacheConfiguration / remoteCacheArtifacts := Def.uncached { enabledOnly(remoteCacheArtifact.toSettingKey, defaultArtifactTasks).apply(_.join).value }, pushRemoteCacheConfiguration / publishMavenStyle := true, Compile / packageCache / pushRemoteCacheArtifact := true, Compile / packageCache / artifact := Artifact(moduleName.value, cachedCompileClassifier), remoteCachePom / pushRemoteCacheArtifact := true, - remoteCachePom := { + remoteCachePom := Def.uncached { val s = streams.value val converter = fileConverter.value val config = (remoteCachePom / makePomConfiguration).value @@ -163,14 +164,14 @@ object RemoteCache { val out = converter.toPath((remoteCachePom / artifactPath).value) config.withFile(out.toFile()) }, - remoteCachePom / remoteCacheArtifact := { + remoteCachePom / remoteCacheArtifact := Def.uncached { PomRemoteCacheArtifact((makePom / artifact).value, remoteCachePom) }, remoteCacheResolvers := pushRemoteCacheTo.value.toVector, ) ++ inTask(pushRemoteCache)( Seq( ivyPaths := (Scope.Global / pushRemoteCache / ivyPaths).value, - ivyConfiguration := { + ivyConfiguration := Def.uncached { val config0 = Classpaths.mkIvyConfiguration.value config0 .withResolvers(remoteCacheResolvers.value.toVector) @@ -179,7 +180,7 @@ object RemoteCache { .withPaths(ivyPaths.value) .withUpdateOptions(UpdateOptions().withGigahorse(true)) }, - ivySbt := { + ivySbt := Def.uncached { Credentials.register(credentials.value, streams.value.log) val config0 = ivyConfiguration.value new IvySbt(config0) @@ -187,8 +188,8 @@ object RemoteCache { ) ) ++ inTask(pullRemoteCache)( Seq( - dependencyResolution := Defaults.dependencyResolutionTask.value, - csrConfiguration := { + dependencyResolution := Def.uncached(Defaults.dependencyResolutionTask.value), + csrConfiguration := Def.uncached { val rs = pushRemoteCacheTo.value.toVector ++ remoteCacheResolvers.value.toVector LMCoursier.scalaCompilerBridgeConfigurationTask.value .withResolvers(rs) @@ -207,7 +208,7 @@ object RemoteCache { ): Seq[Def.Setting[?]] = inTask(packageCache)( Seq( - (Defaults.TaskZero / packageCache) := { + (Defaults.TaskZero / packageCache) := Def.uncached { val converter = fileConverter.value val original = (Defaults.TaskZero / packageBin).value val originalFile = converter.toPath(original) @@ -233,13 +234,13 @@ object RemoteCache { converter.toVirtualFile(artpFile) }, pushRemoteCacheArtifact := true, - remoteCacheArtifact := cacheArtifactTask.value, - packagedArtifact := (artifact.value -> packageCache.value), + remoteCacheArtifact := Def.uncached(cacheArtifactTask.value), + packagedArtifact := Def.uncached(artifact.value -> packageCache.value), artifactPath := Defaults.artifactPathSetting(artifact).value ) ) ++ inTask(pushRemoteCache)( Seq( - moduleSettings := { + moduleSettings := Def.uncached { val smi = scalaModuleInfo.value ModuleDescriptorConfiguration(remoteCacheProjectId.value, projectInfo.value) .withScalaModuleInfo(smi) @@ -257,7 +258,7 @@ object RemoteCache { ) ) ++ Seq( remoteCacheIdCandidates := List(remoteCacheId.value), - remoteCacheProjectId := { + remoteCacheProjectId := Def.uncached { val o = organization.value val m = moduleName.value val id = remoteCacheId.value @@ -265,7 +266,7 @@ object RemoteCache { val v = toVersion(id) ModuleID(o, m, v).cross(c) }, - remoteCacheId := { + remoteCacheId := Def.uncached { val inputs = (unmanagedSources / inputFileStamps).value val cp = (externalDependencyClasspath / outputFileStamps).?.value.getOrElse(Nil) val extraInc = (extraIncOptions.value) flatMap { (k, v) => @@ -273,7 +274,7 @@ object RemoteCache { } combineHash(extractHash(inputs) ++ extractHash(cp) ++ extraInc) }, - pushRemoteCacheConfiguration := { + pushRemoteCacheConfiguration := Def.uncached { val converter = fileConverter.value val artifacts = (pushRemoteCacheConfiguration / packagedArtifacts).value.toVector.map { (a, vf) => @@ -291,7 +292,7 @@ object RemoteCache { isSnapshot.value ) }, - pushRemoteCacheConfiguration / packagedArtifacts := + pushRemoteCacheConfiguration / packagedArtifacts := Def.uncached( (Def .task { (pushRemoteCacheConfiguration / remoteCacheArtifacts).value }) .flatMapTask { case artifacts => @@ -300,11 +301,12 @@ object RemoteCache { .join .apply(_.join.map(_.toMap)) } - .value, - pushRemoteCacheConfiguration / remoteCacheArtifacts := { + .value + ), + pushRemoteCacheConfiguration / remoteCacheArtifacts := Def.uncached { List((packageCache / remoteCacheArtifact).value) }, - pullRemoteCache := { + pullRemoteCache := Def.uncached { import scala.jdk.CollectionConverters.* val log = streams.value.log val r = remoteCacheResolvers.value.head diff --git a/main/src/main/scala/sbt/ScriptedPlugin.scala b/main/src/main/scala/sbt/ScriptedPlugin.scala index 84063ea8f..546da5c90 100644 --- a/main/src/main/scala/sbt/ScriptedPlugin.scala +++ b/main/src/main/scala/sbt/ScriptedPlugin.scala @@ -62,16 +62,18 @@ object ScriptedPlugin extends AutoPlugin { override lazy val projectSettings: Seq[Setting[?]] = Seq( ivyConfigurations ++= Seq(ScriptedConf, ScriptedLaunchConf), scriptedSbt := (pluginCrossBuild / sbtVersion).value, - sbtLauncher := getJars(ScriptedLaunchConf) - .map(_.get().head) - .value, + sbtLauncher := Def.uncached( + getJars(ScriptedLaunchConf) + .map(_.get().head) + .value + ), sbtTestDirectory := sourceDirectory.value / "sbt-test", libraryDependencies ++= Seq( "org.scala-sbt" %% "scripted-sbt" % scriptedSbt.value % ScriptedConf, "org.scala-sbt" % "sbt-launch" % scriptedSbt.value % ScriptedLaunchConf ), - scriptedClasspath := getJars(ScriptedConf).value, - scriptedTests := scriptedTestsTask.value, + scriptedClasspath := Def.uncached(getJars(ScriptedConf).value), + scriptedTests := Def.uncached(scriptedTestsTask.value), scriptedParallelInstances := 1, scriptedBatchExecution := { val binVersion = CrossVersionUtil.binarySbtVersion(scriptedSbt.value) @@ -82,8 +84,8 @@ object ScriptedPlugin extends AutoPlugin { case _ => false } }, - scriptedRun := scriptedRunTask.value, - scriptedDependencies := { + scriptedRun := Def.uncached(scriptedRunTask.value), + scriptedDependencies := Def.uncached { def use[A](@deprecated("unused", "") x: A*): Unit = () // avoid unused warnings val analysis = (Test / Keys.compile).value val pub = publishLocal.all(ScopeFilter(projects = inDependencies(ThisProject))).value diff --git a/main/src/main/scala/sbt/coursierint/LMCoursier.scala b/main/src/main/scala/sbt/coursierint/LMCoursier.scala index a0366f9c3..dead879e9 100644 --- a/main/src/main/scala/sbt/coursierint/LMCoursier.scala +++ b/main/src/main/scala/sbt/coursierint/LMCoursier.scala @@ -257,7 +257,9 @@ object LMCoursier { } def publicationsSetting(packageConfigs: Seq[(Configuration, CConfiguration)]): Def.Setting[?] = { - csrPublications := CoursierArtifactsTasks.coursierPublicationsTask(packageConfigs*).value + csrPublications := Def.uncached( + CoursierArtifactsTasks.coursierPublicationsTask(packageConfigs*).value + ) } // This emulates Ivy's credential registration which basically keeps mutating global registry diff --git a/main/src/main/scala/sbt/internal/BuildDef.scala b/main/src/main/scala/sbt/internal/BuildDef.scala index fb79ce20c..181205a23 100644 --- a/main/src/main/scala/sbt/internal/BuildDef.scala +++ b/main/src/main/scala/sbt/internal/BuildDef.scala @@ -16,6 +16,7 @@ import Def.Setting import sbt.io.Hash import sbt.internal.util.{ Attributed, StringAttributeMap } import sbt.internal.inc.{ FileAnalysisStore, ReflectUtilities } +import sbt.util.CacheImplicits.given import xsbti.{ FileConverter, VirtualFileRef } import xsbti.compile.CompileAnalysis diff --git a/main/src/main/scala/sbt/internal/BuildUtil.scala b/main/src/main/scala/sbt/internal/BuildUtil.scala index 5b6cce1f0..3e1c673a6 100644 --- a/main/src/main/scala/sbt/internal/BuildUtil.scala +++ b/main/src/main/scala/sbt/internal/BuildUtil.scala @@ -97,6 +97,8 @@ object BuildUtil { :: "import _root_.sbt.BareBuildSyntax.*" :: "import _root_.sbt.Keys.*" :: "import _root_.sbt.nio.Keys.*" + :: "import _root_.sbt.util.CacheImplicits.given" + :: "import _root_.sbt.librarymanagement.LibraryManagementCodec.given" :: Nil) def getImports(unit: BuildUnit): Seq[String] = diff --git a/main/src/main/scala/sbt/internal/GlobalPlugin.scala b/main/src/main/scala/sbt/internal/GlobalPlugin.scala index 6a36d0786..d3612be3b 100644 --- a/main/src/main/scala/sbt/internal/GlobalPlugin.scala +++ b/main/src/main/scala/sbt/internal/GlobalPlugin.scala @@ -22,6 +22,7 @@ import Keys.* import Configurations.{ Compile, Runtime } import sbt.ProjectExtra.{ extract, runUnloadHooks, setProject } import sbt.SlashSyntax0.* +import sbt.librarymanagement.LibraryManagementCodec.given import java.io.File import org.apache.ivy.core.module.{ descriptor, id } import descriptor.ModuleDescriptor, id.ModuleRevisionId diff --git a/main/src/main/scala/sbt/internal/IvyConsole.scala b/main/src/main/scala/sbt/internal/IvyConsole.scala index 3740bae35..9cb9a500e 100644 --- a/main/src/main/scala/sbt/internal/IvyConsole.scala +++ b/main/src/main/scala/sbt/internal/IvyConsole.scala @@ -52,7 +52,7 @@ object IvyConsole { val depSettings: Seq[Setting[?]] = Seq( libraryDependencies ++= managed.reverse, resolvers ++= repos.reverse.toVector, - Compile / unmanagedJars ++= { + Compile / unmanagedJars ++= Def.uncached { val converter = fileConverter.value val u = unmanaged.reverse.map(_.toPath).map(converter.toVirtualFile) u: Seq[HashedVirtualFileRef] diff --git a/main/src/main/scala/sbt/internal/Load.scala b/main/src/main/scala/sbt/internal/Load.scala index e8d2ed0d1..ca1ac2539 100755 --- a/main/src/main/scala/sbt/internal/Load.scala +++ b/main/src/main/scala/sbt/internal/Load.scala @@ -1331,7 +1331,7 @@ private[sbt] object Load { Seq( sbtPlugin :== true, isMetaBuild :== true, - pluginData := { + pluginData := Def.uncached { val prod = (Configurations.Runtime / exportedProducts).value val cp = (Configurations.Runtime / fullClasspath).value val opts = (Configurations.Compile / scalacOptions).value @@ -1357,7 +1357,7 @@ private[sbt] object Load { converter, ) }, - scalacOptions += "-Wconf:cat=unused-nowarn:s", + scalacOptions += Def.uncached("-Wconf:cat=unused-nowarn:s"), onLoadMessage := ("loading project definition from " + baseDirectory.value) ) ) diff --git a/main/src/main/scala/sbt/internal/Script.scala b/main/src/main/scala/sbt/internal/Script.scala index adda88ab0..9ae66f4b0 100644 --- a/main/src/main/scala/sbt/internal/Script.scala +++ b/main/src/main/scala/sbt/internal/Script.scala @@ -54,8 +54,9 @@ object Script { val embeddedSettings = blocks(script).flatMap { block => evaluate(eval(), vf, block.lines, currentUnit.imports, block.offset + 1)(currentLoader) } - val scriptAsSource = (Compile / sources) := script :: Nil - val asScript = scalacOptions ++= Seq("-Xscript", script.getName.stripSuffix(".scala")) + val scriptAsSource = (Compile / sources) := Def.uncached(script :: Nil) + val asScript = + scalacOptions ++= Def.uncached(Seq("-Xscript", script.getName.stripSuffix(".scala"))) val scriptSettings = Seq( asScript, scriptAsSource, diff --git a/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala b/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala index 0f3faed6b..00635addc 100644 --- a/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala +++ b/main/src/main/scala/sbt/internal/librarymanagement/IvyXml.scala @@ -193,7 +193,7 @@ object IvyXml { task: TaskKey[T], shadedConfigOpt: Option[Configuration] ): Setting[Task[T]] = - task := task.dependsOnTask { + task := Def.uncached(task.dependsOnTask { Def.task { val currentProject = { val proj = csrProject.value @@ -207,7 +207,7 @@ object IvyXml { sbt.Keys.streams.value.log ) } - }.value + }.value) private lazy val needsIvyXmlLocal = Seq(publishLocalConfiguration) ++ getPubConf( "makeIvyXmlLocalConfiguration" diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 9f34204f2..dd606137e 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -336,7 +336,7 @@ object BuildServerProtocol { bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value, bspScalaTestClassesItem := scalaTestClassesTask.value, bspScalaMainClassesItem := scalaMainClassesTask.value, - Keys.compile / bspReporter := { + Keys.compile / bspReporter := Def.uncached { val targetId = bspTargetIdentifier.value val bspCompileStateInstance = bspCompileState.value val converter = fileConverter.value diff --git a/main/src/main/scala/sbt/nio/Keys.scala b/main/src/main/scala/sbt/nio/Keys.scala index 12dfbad4e..816f73c20 100644 --- a/main/src/main/scala/sbt/nio/Keys.scala +++ b/main/src/main/scala/sbt/nio/Keys.scala @@ -20,6 +20,7 @@ import sbt.internal.util.AttributeKey import sbt.internal.util.complete.Parser import sbt.nio.file.{ FileAttributes, FileTreeView, Glob, PathFilter } import sbt.* +import sbt.util.cacheLevel import scala.concurrent.duration.FiniteDuration @@ -39,6 +40,8 @@ object Keys { settingKey[PathFilter]("A filter to apply to the input sources of a task.") val fileInputExcludeFilter = settingKey[PathFilter]("An exclusion filter to apply to the input sources of a task.") + + @cacheLevel(include = Array.empty) val inputFileStamper = settingKey[FileStamper]( "Toggles the file stamping implementation used to determine whether or not a file has been modified." ) @@ -169,9 +172,13 @@ object Keys { private[sbt] val allInputPathsAndAttributes = taskKey[Seq[(Path, FileAttributes)]]("Get all of the file inputs for a task") .withRank(Invisible) + + @cacheLevel(include = Array.empty) private[sbt] val unmanagedFileStampCache = taskKey[FileStamp.Cache]( "Map of managed file stamps that may be cleared between task evaluation runs." ).withRank(Invisible) + + @cacheLevel(include = Array.empty) private[sbt] val managedFileStampCache = taskKey[FileStamp.Cache]( "Map of managed file stamps that may be cleared between task evaluation runs." ).withRank(Invisible) diff --git a/main/src/main/scala/sbt/nio/Settings.scala b/main/src/main/scala/sbt/nio/Settings.scala index f4f1b2672..b22b4e0b0 100644 --- a/main/src/main/scala/sbt/nio/Settings.scala +++ b/main/src/main/scala/sbt/nio/Settings.scala @@ -127,7 +127,7 @@ private[sbt] object Settings { scopedKey.scope.task.toOption.toSeq.map { key => val updatedKey = Def.ScopedKey(scopedKey.scope.copy(task = Zero), key) scopedKey.scope / transitiveDynamicInputs := - WatchTransitiveDependencies.task(updatedKey).value + Def.uncached(WatchTransitiveDependencies.task(updatedKey).value) } case dynamicDependency.key => (scopedKey.scope / dynamicDependency := { () }) :: Nil case transitiveClasspathDependency.key => @@ -158,7 +158,7 @@ private[sbt] object Settings { private[sbt] def inputPathSettings(setting: Def.Setting[?]): Seq[Def.Setting[?]] = { val scopedKey = setting.key val scope = scopedKey.scope - (scope / Keys.allInputPathsAndAttributes := { + (scope / Keys.allInputPathsAndAttributes := Def.uncached { val view = (scope / fileTreeView).value val inputs = (scope / fileInputs).value val stamper = (scope / inputFileStamper).value @@ -186,7 +186,7 @@ private[sbt] object Settings { * @return a task definition that retrieves all of the input paths scoped to the input key. */ private def allFilesImpl(scope: Scope): Def.Setting[?] = { - addTaskDefinition(scope / Keys.allInputFiles := { + addTaskDefinition(scope / Keys.allInputFiles := Def.uncached { val filter = (scope / fileInputIncludeFilter).value && !(scope / fileInputExcludeFilter).value (scope / Keys.allInputPathsAndAttributes).value.collect { @@ -218,7 +218,7 @@ private[sbt] object Settings { changeKey: TaskKey[Seq[(Path, FileStamp)] => FileChanges], stampKey: TaskKey[Seq[(Path, FileStamp)]] ): Def.Setting[?] = - addTaskDefinition(scope / changeKey := { + addTaskDefinition(scope / changeKey := Def.uncached { val current = (scope / stampKey).value changedFiles(_, current) }) @@ -262,7 +262,7 @@ private[sbt] object Settings { * @return a task specific clean implementation */ private[sbt] def cleanImpl(scope: Scope): Def.Setting[?] = addTaskDefinition { - scope / sbt.Keys.clean := Clean.task(scope, full = false).value + scope / sbt.Keys.clean := Def.uncached(Clean.task(scope, full = false).value) } /** @@ -275,7 +275,7 @@ private[sbt] object Settings { private[sbt] def cleanImpl[T: JsonFormat: ToSeqPath](taskKey: TaskKey[T]): Def.Setting[?] = { val taskScope = taskKey.scope.rescope(taskKey.key) addTaskDefinition( - taskScope / sbt.Keys.clean := + taskScope / sbt.Keys.clean := Def.uncached( // the clean file task needs to run first because the previous cache gets blown away // by the second task Def @@ -286,6 +286,7 @@ private[sbt] object Settings { Clean.task(taskScope, full = false) } .value + ) ) } @@ -300,7 +301,7 @@ private[sbt] object Settings { private[sbt] def fileStamps(scopedKey: Def.ScopedKey[?]): Def.Setting[?] = { import scala.collection.parallel.CollectionConverters.* val scope = scopedKey.scope - addTaskDefinition(scope / Keys.inputFileStamps := { + addTaskDefinition(scope / Keys.inputFileStamps := Def.uncached { val cache = (scope / unmanagedFileStampCache).value val stamper = (scope / Keys.inputFileStamper).value val stampFile: Path => Option[(Path, FileStamp)] = @@ -335,7 +336,7 @@ private[sbt] object Settings { } private def allOutputPathsImpl(scope: Scope): Def.Setting[?] = - addTaskDefinition(scope / allOutputFiles := { + addTaskDefinition(scope / allOutputFiles := Def.uncached { val filter = (scope / fileOutputIncludeFilter).value && !(scope / fileOutputExcludeFilter).value val view = (scope / fileTreeView).value @@ -361,7 +362,7 @@ private[sbt] object Settings { }) private def outputFileStampsImpl(scope: Scope): Def.Setting[?] = - addTaskDefinition(scope / outputFileStamps := { + addTaskDefinition(scope / outputFileStamps := Def.uncached { val stamper: Path => Option[FileStamp] = (scope / outputFileStamper).value match { case LastModified => FileStamp.lastModified case Hash => FileStamp.hash diff --git a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala index 93c8065bd..a05956ac7 100644 --- a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala +++ b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala @@ -38,11 +38,11 @@ object DependencyTreeSettings { // dependency tree dependencyTreeIgnoreMissingUpdate / updateOptions := updateOptions.value .withCachedResolution(false), - dependencyTreeIgnoreMissingUpdate / ivyConfiguration := { + dependencyTreeIgnoreMissingUpdate / ivyConfiguration := Def.uncached { // inTask will make sure the new definition will pick up `updateOptions in dependencyTreeIgnoreMissingUpdate` Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.mkIvyConfiguration).value }, - dependencyTreeIgnoreMissingUpdate / ivyModule := { + dependencyTreeIgnoreMissingUpdate / ivyModule := Def.uncached { // concatenating & inlining ivySbt & ivyModule default task implementations, as `SbtAccess.inTask` does // NOT correctly force the scope when applied to `TaskKey.toTask` instances (as opposed to raw // implementations like `Classpaths.mkIvyConfiguration` or `Classpaths.updateTask`) @@ -52,7 +52,7 @@ object DependencyTreeSettings { // don't fail on missing dependencies dependencyTreeIgnoreMissingUpdate / updateConfiguration := updateConfiguration.value .withMissingOk(true), - dependencyTreeIgnoreMissingUpdate := { + dependencyTreeIgnoreMissingUpdate := Def.uncached { // inTask will make sure the new definition will pick up `ivyModule/updateConfiguration in ignoreMissingUpdate` Project.inTask(dependencyTreeIgnoreMissingUpdate, Classpaths.updateTask).value }, @@ -67,7 +67,7 @@ object DependencyTreeSettings { dependencyTreeCrossProjectId := CrossVersion(scalaVersion.value, scalaBinaryVersion.value)( projectID.value ), - dependencyTreeModuleGraph0 := { + dependencyTreeModuleGraph0 := Def.uncached { val sv = scalaVersion.value val g = dependencyTreeIgnoreMissingUpdate.value .configuration(configuration.value) @@ -107,12 +107,14 @@ object DependencyTreeSettings { val config = configuration.value target.value / s"dependencies-${config.toString}.dot" }, - dependencyDot / asString := rendering.DOT.dotGraph( - dependencyTreeModuleGraph0.value, - dependencyDotHeader.value, - dependencyDotNodeLabel.value, - rendering.DOT.HTMLLabelRendering.AngleBrackets, - dependencyDotNodeColors.value + dependencyDot / asString := Def.uncached( + rendering.DOT.dotGraph( + dependencyTreeModuleGraph0.value, + dependencyDotHeader.value, + dependencyDotNodeLabel.value, + rendering.DOT.HTMLLabelRendering.AngleBrackets, + dependencyDotNodeColors.value + ) ), dependencyDot := writeToFile(dependencyDot / asString, dependencyDotFile).value, dependencyDotHeader := diff --git a/main/src/main/scala/sbt/plugins/JUnitXmlReportPlugin.scala b/main/src/main/scala/sbt/plugins/JUnitXmlReportPlugin.scala index 3acf6638d..9e3d02544 100644 --- a/main/src/main/scala/sbt/plugins/JUnitXmlReportPlugin.scala +++ b/main/src/main/scala/sbt/plugins/JUnitXmlReportPlugin.scala @@ -42,11 +42,13 @@ object JUnitXmlReportPlugin extends AutoPlugin { lazy val testReportSettings: Seq[Setting[?]] = Seq( testReportsDirectory := target.value / (prefix(configuration.value.name) + "reports"), - testListeners += new JUnitXmlTestsListener( - testReportsDirectory.value, - SysProp.legacyTestReport, - streams.value.log - ) + testListeners += Def.uncached { + JUnitXmlTestsListener( + testReportsDirectory.value, + SysProp.legacyTestReport, + streams.value.log + ) + } ) } diff --git a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala index 8fcd295ed..bd6a7b264 100644 --- a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala +++ b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala @@ -15,6 +15,7 @@ import Keys.* import sbt.internal.SysProp import sbt.librarymanagement.syntax.* import sbt.librarymanagement.{ Configuration, CrossVersion } +import sbt.librarymanagement.LibraryManagementCodec.given import ProjectExtra.inConfig import sbt.internal.inc.ScalaInstance import sbt.ScopeFilter.Make.* diff --git a/sbt-app/src/sbt-test/actions/all/build.sbt b/sbt-app/src/sbt-test/actions/all/build.sbt index 21a4f4a7f..c713e3dd3 100644 --- a/sbt-app/src/sbt-test/actions/all/build.sbt +++ b/sbt-app/src/sbt-test/actions/all/build.sbt @@ -6,4 +6,7 @@ val updateReports = Def.taskDyn { updateClassifiers.all(ScopeFilter(configuratio val newTask = taskKey[Unit]("") -newTask := updateReports.value +newTask := { + updateReports.value + () +} diff --git a/sbt-app/src/sbt-test/actions/compile-time-only/build.sbt b/sbt-app/src/sbt-test/actions/compile-time-only/build.sbt index 99ce64624..813a44b90 100644 --- a/sbt-app/src/sbt-test/actions/compile-time-only/build.sbt +++ b/sbt-app/src/sbt-test/actions/compile-time-only/build.sbt @@ -1,9 +1,11 @@ +Global / localCacheDirectory := baseDirectory.value / "diskcache" + ThisBuild / evictionErrorLevel := Level.Info libraryDependencies += "org.scala-sbt" % "sbt" % sbtVersion.value lazy val expectErrorNotCrash = taskKey[Unit]("Ensures that sbt properly set types on Trees so that the compiler doesn't crash on a bad reference to .value, but gives a proper error instead.") -expectErrorNotCrash := { +expectErrorNotCrash := Def.uncached { val fail = (Compile / compileIncremental).failure.value Incomplete.allExceptions(fail).headOption match case Some(x: xsbti.CompileFailed) => () diff --git a/sbt-app/src/sbt-test/actions/compile-time-only/changes/A1.scala b/sbt-app/src/sbt-test/actions/compile-time-only/changes/A1.scala index 0975dfda7..e04f7b48e 100644 --- a/sbt-app/src/sbt-test/actions/compile-time-only/changes/A1.scala +++ b/sbt-app/src/sbt-test/actions/compile-time-only/changes/A1.scala @@ -1,14 +1,14 @@ -import sbt._, Keys._ +import sbt.*, Keys.* import Def.Initialize import complete.{DefaultParsers, Parser} +import sbt.librarymanagement.LibraryManagementCodec.given -object A { - val x1: Initialize[Task[Int]] = Def.task { 3 } - val y1 = Def.task { x1.value } +object A: + val x1: Initialize[Task[Int]] = Def.task { 3 } + val y1 = Def.task { x1.value } - val x2: Initialize[Parser[Int]] = Def.setting { DefaultParsers.success(3) } - val y2 = Def.inputTask { x1.value + x2.parsed } - - val x3: Initialize[Int] = Def.setting { 3 } - val y3 = Def.setting { x3.value } -} + val x2: Initialize[Parser[Int]] = Def.setting { DefaultParsers.success(3) } + val y2 = Def.inputTask { x1.value + x2.parsed } + + val x3: Initialize[Int] = Def.setting { 3 } + val y3 = Def.setting { x3.value } diff --git a/sbt-app/src/sbt-test/actions/compile-time-only/changes/A2.scala b/sbt-app/src/sbt-test/actions/compile-time-only/changes/A2.scala index b2d5e5148..20189970d 100644 --- a/sbt-app/src/sbt-test/actions/compile-time-only/changes/A2.scala +++ b/sbt-app/src/sbt-test/actions/compile-time-only/changes/A2.scala @@ -1,7 +1,7 @@ -import sbt._ +import sbt.* import Def.Initialize +import sbt.librarymanagement.LibraryManagementCodec.given -object A { - val x1: Initialize[Task[Int]] = Def.task { 3 } - val y1 = x1.value -} \ No newline at end of file +object A: + val x1: Initialize[Task[Int]] = Def.task { 3 } + val y1 = x1.value diff --git a/sbt-app/src/sbt-test/actions/compile-time-only/changes/A3.scala b/sbt-app/src/sbt-test/actions/compile-time-only/changes/A3.scala index 83a45ead8..f309fd936 100644 --- a/sbt-app/src/sbt-test/actions/compile-time-only/changes/A3.scala +++ b/sbt-app/src/sbt-test/actions/compile-time-only/changes/A3.scala @@ -1,8 +1,8 @@ -import sbt._, Keys._ +import sbt.*, Keys.* import Def.Initialize import complete.{DefaultParsers, Parser} +import sbt.librarymanagement.LibraryManagementCodec.given -object A { - val x1: Initialize[Parser[Int]] = Def.setting { DefaultParsers.success(3) } - val y1 = Def.task { x1.parsed } -} +object A: + val x1: Initialize[Parser[Int]] = Def.setting { DefaultParsers.success(3) } + val y1 = Def.task { x1.parsed } diff --git a/sbt-app/src/sbt-test/actions/compile/test b/sbt-app/src/sbt-test/actions/compile/test index 9978a9516..ce9f0cb28 100644 --- a/sbt-app/src/sbt-test/actions/compile/test +++ b/sbt-app/src/sbt-test/actions/compile/test @@ -1,5 +1,5 @@ -> compile -> 'set Compile / compile / sources := { val src = (Compile / compile / sources).value; src.filterNot(_.getName contains "C") }' +> 'set Compile / compile / sources := Def.uncached { val src = (Compile / compile / sources).value; src.filterNot(_.getName contains "C") }' > compile diff --git a/sbt-app/src/sbt-test/actions/completions/project/FooPlugin.scala b/sbt-app/src/sbt-test/actions/completions/project/FooPlugin.scala index 4bef386d9..67c3517c4 100644 --- a/sbt-app/src/sbt-test/actions/completions/project/FooPlugin.scala +++ b/sbt-app/src/sbt-test/actions/completions/project/FooPlugin.scala @@ -1,4 +1,4 @@ -import sbt._ +import sbt.* object FooPlugin extends AutoPlugin { override def trigger = noTrigger @@ -9,6 +9,6 @@ object FooPlugin extends AutoPlugin { import autoImport._ override def buildSettings = super.buildSettings ++ Seq( - myTask := println("Called my task") + myTask := Def.uncached(println("Called my task")) ) } diff --git a/sbt-app/src/sbt-test/actions/conditional/build.sbt b/sbt-app/src/sbt-test/actions/conditional/build.sbt index 02077559b..bafecc264 100644 --- a/sbt-app/src/sbt-test/actions/conditional/build.sbt +++ b/sbt-app/src/sbt-test/actions/conditional/build.sbt @@ -35,10 +35,10 @@ lazy val root = (project in file(".")) zeroAction := { IO.write(output.value, s"zero\n", append = true) }, posAction := { IO.write(output.value, s"pos\n", append = true) }, - TaskKey[Unit]("checkTrue") := checkLines("true"), - TaskKey[Unit]("checkFalse") := checkLines("false"), - TaskKey[Unit]("checkNeg") := checkLines("neg"), - TaskKey[Unit]("checkZero") := checkLines("zero"), + TaskKey[Unit]("checkTrue") := checkLines("true").value, + TaskKey[Unit]("checkFalse") := checkLines("false").value, + TaskKey[Unit]("checkNeg") := checkLines("neg").value, + TaskKey[Unit]("checkZero") := checkLines("zero").value, // https://github.com/sbt/sbt/issues/5625 javacOptions ++= ( @@ -49,6 +49,6 @@ lazy val root = (project in file(".")) def checkLines(content: String) = Def.task { val lines = IO.read(output.value).linesIterator.toList - assert(lines == List("true"), s"$content was expected but found: $lines") + assert(lines == List(content), s"$content was expected but found: $lines") () } diff --git a/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt b/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt index 2788b5952..e88a82cba 100644 --- a/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt +++ b/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt @@ -16,11 +16,11 @@ lazy val foo = project .settings( crossScalaVersions := Seq(scala212, scala213), libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.0", - check := { + check := Def.uncached { // This tests that +check will respect bar's crossScalaVersions and not switch val x = (LocalProject("bar") / scalaVersion).value assert(x == scala212, s"$x == $scala212") - (Compile / compile).value + Def.unit((Compile / compile).value) }, (Test / testOnly) := { // This tests that +testOnly will respect bar's crossScalaVersions and not switch @@ -28,35 +28,37 @@ lazy val foo = project assert(x == scala212, s"$x == $scala212") val _ = (Test / testOnly).evaluated }, - compile2 := { + compile2 := Def.uncached { // This tests that +build will ignore bar's crossScalaVersions and use root's like sbt 0.13 val x = (LocalProject("bar") / scalaVersion).value assert(x == scalaVersion.value, s"$x == ${scalaVersion.value}") - (Compile / compile).value + Def.unit((Compile / compile).value) }, ) lazy val bar = project .settings( crossScalaVersions := Seq(scala212), - check := (Compile / compile).value, - compile2 := (Compile / compile).value, + check := Def.uncached { + Def.unit((Compile / compile).value) + }, + compile2 := Def.uncached(Def.unit((Compile / compile).value)), ) lazy val baz = project .settings( crossScalaVersions := Seq(scala213), - check := { + check := Def.uncached { // This tests that +baz/check will respect bar's crossScalaVersions and not switch val x = (LocalProject("bar") / scalaVersion).value assert(x == scala212, s"$x == $scala212") - (Compile / compile).value + Def.unit((Compile / compile).value) }, ) lazy val client = project .settings( crossScalaVersions := Seq(scala212, scala213), - check := (Compile / compile).value, - compile2 := (Compile / compile).value, + check := Def.uncached(Def.unit((Compile / compile).value)), + compile2 := Def.uncached(Def.unit((Compile / compile).value)), ) diff --git a/sbt-app/src/sbt-test/actions/external-doc/build.sbt b/sbt-app/src/sbt-test/actions/external-doc/build.sbt index 2ef387419..2b4bfd8f5 100644 --- a/sbt-app/src/sbt-test/actions/external-doc/build.sbt +++ b/sbt-app/src/sbt-test/actions/external-doc/build.sbt @@ -68,14 +68,14 @@ val c = project.settings(apiBaseSetting) val d = project .dependsOn(c) .settings( - externalResolvers := Seq(aResolver.value, bResolver.value), + externalResolvers := Def.uncached(Seq(aResolver.value, bResolver.value)), addDep("a"), addDep("b"), - checkApiMappings := { + checkApiMappings := Def.uncached { val actual = (Compile / doc / apiMappings).value println("Actual API Mappings: " + actual.mkString("\n\t", "\n\t", "")) val expected = expectedMappings.value println("Expected API Mappings: " + expected.mkString("\n\t", "\n\t", "")) - assert(actual == expected) + assert(actual.toString.replaceAll(">sha256-.*/256", "") == expected.toString) } ) diff --git a/sbt-app/src/sbt-test/actions/external-doc/test b/sbt-app/src/sbt-test/actions/external-doc/disabled similarity index 100% rename from sbt-app/src/sbt-test/actions/external-doc/test rename to sbt-app/src/sbt-test/actions/external-doc/disabled diff --git a/sbt-app/src/sbt-test/actions/previous-in-input-task/build.sbt b/sbt-app/src/sbt-test/actions/previous-in-input-task/build.sbt index a7e169d7e..510456eb8 100644 --- a/sbt-app/src/sbt-test/actions/previous-in-input-task/build.sbt +++ b/sbt-app/src/sbt-test/actions/previous-in-input-task/build.sbt @@ -1,10 +1,10 @@ import sjsonnew.BasicJsonProtocol._ val cacheTask = taskKey[Int]("task") -cacheTask := 1 +cacheTask := Def.uncached(1) val checkTask = inputKey[Unit]("validate that the correct value is set by cacheTask") checkTask := { val expected = Def.spaceDelimited("").parsed.head.toInt assert(cacheTask.previous.getOrElse(0) == expected) -} \ No newline at end of file +} diff --git a/sbt-app/src/sbt-test/actions/previous/build.sbt b/sbt-app/src/sbt-test/actions/previous/build.sbt index 95440022d..29e8e0794 100644 --- a/sbt-app/src/sbt-test/actions/previous/build.sbt +++ b/sbt-app/src/sbt-test/actions/previous/build.sbt @@ -1,3 +1,5 @@ +Global / localCacheDirectory := baseDirectory.value / "diskcache" + import sjsonnew.BasicJsonProtocol._ lazy val a0 = 1 @@ -12,11 +14,11 @@ lazy val checkNext = inputKey[Unit]("check-next") // Also, it is ok for b to refer to b.previous: // normally, b's definition could not refer to plain b.value because it would be undefined -a := b.previous.getOrElse(a0) +a := Def.uncached(b.previous.getOrElse(a0)) -b := a.previous.getOrElse(a0) + b.previous.getOrElse(b0) +b := Def.uncached(a.previous.getOrElse(a0) + b.previous.getOrElse(b0)) -next := (a.value, b.value) +next := Def.uncached((a.value, b.value)) def parser = { import complete.DefaultParsers._ @@ -24,9 +26,9 @@ def parser = { } checkNext := { - val (expectedA, expectedB) = parser.parsed - val actualA = a.value - val actualB = b.value - assert(actualA == expectedA, s"Expected 'a' to be $expectedA, got $actualA") - assert(actualB == expectedB, s"Expected 'b' to be $expectedB, got $actualB") + val (expectedA, expectedB) = parser.parsed + val actualA = a.value + val actualB = b.value + assert(actualA == expectedA, s"Expected 'a' to be $expectedA, got $actualA") + assert(actualB == expectedB, s"Expected 'b' to be $expectedB, got $actualB") } diff --git a/sbt-app/src/sbt-test/actions/previous/scopes.sbt b/sbt-app/src/sbt-test/actions/previous/scopes.sbt index 16af91fad..a62ef634a 100644 --- a/sbt-app/src/sbt-test/actions/previous/scopes.sbt +++ b/sbt-app/src/sbt-test/actions/previous/scopes.sbt @@ -7,13 +7,13 @@ lazy val checkScopes = inputKey[Unit]("check scopes") lazy val subA = project lazy val subB = project -x := 3 +x := Def.uncached(3) -Compile / y / x := 7 +Compile / y / x := Def.uncached(7) -Runtime / y / x := 13 +Runtime / y / x := Def.uncached(13) -subA / Compile / x := { +subA / Compile / x := Def.uncached { val xcy = (Compile / y / x).previous getOrElse 0 // 7 // verify that This is properly resolved to Global and not the defining key's scope val xg = x.previous getOrElse 0 // 3 @@ -22,7 +22,7 @@ subA / Compile / x := { } inConfig(Compile)(Seq( - subB / y := { + subB / y := Def.uncached { // verify that the referenced key gets delegated val xty = (Test / y / x).previous getOrElse 0 // 13 // verify that inConfig gets applied @@ -37,7 +37,7 @@ def parser = { (Space ~> IntBasic) ~ (Space ~> IntBasic) } -checkScopes := { +checkScopes := Def.uncached { val (expectedX, expectedY) = parser.parsed val actualX = (subA/ Compile / x).value val actualY = (subB / Test / y).value diff --git a/sbt-app/src/sbt-test/actions/previous/test b/sbt-app/src/sbt-test/actions/previous/test index 4593dbd51..a1b43c4f7 100644 --- a/sbt-app/src/sbt-test/actions/previous/test +++ b/sbt-app/src/sbt-test/actions/previous/test @@ -7,4 +7,4 @@ > checkScopes 0 0 > all x Compile/y/x Runtime/y/x y -> checkScopes 21 91 \ No newline at end of file +> checkScopes 21 91 diff --git a/sbt-app/src/sbt-test/actions/promise/build.sbt b/sbt-app/src/sbt-test/actions/promise/build.sbt index 977218fb9..8dc2dee28 100644 --- a/sbt-app/src/sbt-test/actions/promise/build.sbt +++ b/sbt-app/src/sbt-test/actions/promise/build.sbt @@ -8,8 +8,8 @@ lazy val root = (project in file(".")) .settings( name := "promise", output := baseDirectory.value / "output.txt", - midpoint := Def.promise[Int], - longRunning := { + midpoint := Def.uncached(Def.promise[Int]), + longRunning := Def.uncached { val p = midpoint.value val st = streams.value IO.write(output.value, "start\n", append = true) @@ -18,21 +18,21 @@ lazy val root = (project in file(".")) Thread.sleep(100) IO.write(output.value, "end\n", append = true) }, - midTask := { + midTask := Def.uncached { val st = streams.value val x = midpoint.await.value IO.write(output.value, s"$x in the middle\n", append = true) }, - joinTwo := { + joinTwo := Def.uncached { val x = longRunning.value val y = midTask.value }, - TaskKey[Unit]("check") := { + TaskKey[Unit]("check") := Def.uncached { val lines = IO.read(output.value).linesIterator.toList assert(lines == List("start", "5 in the middle", "end")) () }, - TaskKey[Unit]("check2") := { + TaskKey[Unit]("check2") := Def.uncached { val lines = IO.read(output.value).linesIterator.toList assert(lines == List("start", "end", "5 in the middle")) () diff --git a/sbt-app/src/sbt-test/actions/query/build.sbt b/sbt-app/src/sbt-test/actions/query/build.sbt index ff3f4c354..aafdeb6af 100644 --- a/sbt-app/src/sbt-test/actions/query/build.sbt +++ b/sbt-app/src/sbt-test/actions/query/build.sbt @@ -15,9 +15,10 @@ lazy val baz = project scalaVersion := "2.12.20", ) -someTask := { +someTask := Def.uncached { val x = target.value / (name.value + ".txt") val s = streams.value s.log.info(s"writing $x") IO.touch(x) + () } diff --git a/sbt-app/src/sbt-test/actions/reload/log-in-setting.sbt b/sbt-app/src/sbt-test/actions/reload/log-in-setting.sbt index 671118f0b..a7b7b12cc 100644 --- a/sbt-app/src/sbt-test/actions/reload/log-in-setting.sbt +++ b/sbt-app/src/sbt-test/actions/reload/log-in-setting.sbt @@ -4,7 +4,7 @@ version := { version.value } -TaskKey[Unit]("evil-clear-logger") := { +TaskKey[Unit]("evil-clear-logger") := Def.uncached { val logger = sLog.value val cls = logger.getClass val field = cls.getDeclaredField("ref") diff --git a/sbt-app/src/sbt-test/actions/set/build.sbt b/sbt-app/src/sbt-test/actions/set/build.sbt index 3fcd996cc..d4b9dd7c4 100644 --- a/sbt-app/src/sbt-test/actions/set/build.sbt +++ b/sbt-app/src/sbt-test/actions/set/build.sbt @@ -8,7 +8,7 @@ TaskKey[Unit]("checkBuildSbtDefined", "") := { assert(notExistingThing.?.value == Some(5), "Failed to set a settingKey defined in build.sbt") } -TaskKey[Unit]("evil-clear-logger") := { +TaskKey[Unit]("evil-clear-logger") := Def.uncached { val logger = sLog.value val cls = logger.getClass val field = cls.getDeclaredField("ref") @@ -16,6 +16,7 @@ TaskKey[Unit]("evil-clear-logger") := { val ref = field.get(logger).asInstanceOf[java.lang.ref.WeakReference[_]] // MUHAHAHHAHAHAHAHHAHA, I am de evil GC, I clear things. ref.clear() + () } commands ++= Seq( diff --git a/sbt-app/src/sbt-test/actions/task-map/build.sbt b/sbt-app/src/sbt-test/actions/task-map/build.sbt index 72b1d8047..ba036da3a 100644 --- a/sbt-app/src/sbt-test/actions/task-map/build.sbt +++ b/sbt-app/src/sbt-test/actions/task-map/build.sbt @@ -6,23 +6,45 @@ val taskF = taskKey[File]("") scalaVersion := "3.3.1" name := "task-map" -taskA := touch(target.value / "a") -taskB := touch(target.value / "b") +taskA := { + val c = fileConverter.value + touch(target.value / "a") + Def.declareOutput(c.toVirtualFile((target.value / "a").toPath())) + target.value / "a" +} -taskE := touch(target.value / "e") -taskF := touch(target.value / "f") +taskB := { + val c = fileConverter.value + touch(target.value / "b") + Def.declareOutput(c.toVirtualFile((target.value / "b").toPath())) + target.value / "b" +} + +taskE := { + val c = fileConverter.value + touch(target.value / "e") + Def.declareOutput(c.toVirtualFile((target.value / "e").toPath())) + target.value / "e" +} + +taskF := { + val c = fileConverter.value + touch(target.value / "f") + Def.declareOutput(c.toVirtualFile((target.value / "f").toPath())) + target.value / "f" +} // a <<= a triggeredBy b // means "a" will be triggered by "b" // said differently, invoking "b" will run "b" and then run "a" -taskA := taskA.triggeredBy(taskB).value +taskA := Def.uncached(taskA.triggeredBy(taskB).value) // e <<= e runBefore f // means "e" will be run before running "f" // said differently, invoking "f" will run "e" and then run "f" -taskE := taskE.runBefore(taskF).value +taskE := Def.uncached(taskE.runBefore(taskF).value) // test utils def touch(f: File): File = { IO.touch(f); f } diff --git a/sbt-app/src/sbt-test/actions/task-map/test b/sbt-app/src/sbt-test/actions/task-map/test index e5c2c2d81..a3bec9fa7 100644 --- a/sbt-app/src/sbt-test/actions/task-map/test +++ b/sbt-app/src/sbt-test/actions/task-map/test @@ -1,7 +1,7 @@ > taskB -$ exists target/**/task-map/**/b -$ exists target/**/task-map/**/a +$ exists target/**/b +$ exists target/**/a > taskF -$ exists target/**/task-map/e -$ exists target/**/task-map/f +$ exists target/**/e +$ exists target/**/f diff --git a/sbt-app/src/sbt-test/apiinfo/show-circular-structure/build.sbt b/sbt-app/src/sbt-test/apiinfo/show-circular-structure/build.sbt index 21146aa3d..9c3c5a8af 100644 --- a/sbt-app/src/sbt-test/apiinfo/show-circular-structure/build.sbt +++ b/sbt-app/src/sbt-test/apiinfo/show-circular-structure/build.sbt @@ -4,7 +4,7 @@ logLevel := Level.Debug incOptions ~= { _.withApiDebug(true) } -TaskKey[Unit]("show-apis") := { +TaskKey[Unit]("show-apis") := Def.uncached { val a = (Compile / compile).value match { case a: Analysis => a } val scalaSrc = (Compile / scalaSource).value val javaSrc = (Compile / javaSource).value @@ -14,4 +14,5 @@ TaskKey[Unit]("show-apis") := { import DefaultShowAPI._ DefaultShowAPI(aApi) DefaultShowAPI(jApi) + () } diff --git a/sbt-app/src/sbt-test/apiinfo/unstable-existential-names/build.sbt b/sbt-app/src/sbt-test/apiinfo/unstable-existential-names/build.sbt index 3888dda98..215418ce9 100644 --- a/sbt-app/src/sbt-test/apiinfo/unstable-existential-names/build.sbt +++ b/sbt-app/src/sbt-test/apiinfo/unstable-existential-names/build.sbt @@ -3,7 +3,7 @@ import complete.DefaultParsers._ // Reset compiler iterations, necessary because tests run in batch mode val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") -recordPreviousIterations := { +recordPreviousIterations := Def.uncached { val log = streams.value.log CompileState.previousIterations = { val previousAnalysis = (Compile / previousCompile).value.analysis.asScala @@ -14,6 +14,7 @@ recordPreviousIterations := { case Some(a: Analysis) => a.compilations.allCompilations.size } } + () } val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.") diff --git a/sbt-app/src/sbt-test/cache/basic/build.sbt b/sbt-app/src/sbt-test/cache/basic/build.sbt index d25840be4..30f1f6298 100644 --- a/sbt-app/src/sbt-test/cache/basic/build.sbt +++ b/sbt-app/src/sbt-test/cache/basic/build.sbt @@ -8,33 +8,34 @@ val checkMapN1 = taskKey[Unit]("") Global / localCacheDirectory := baseDirectory.value / "diskcache" -pure1 := (Def.cachedTask { +pure1 := { val output = StringVirtualFile1("target/out/a.txt", "foo") Def.declareOutput(output) () -}).value +} -map1 := (Def.cachedTask { +map1 := { pure1.value val output1 = StringVirtualFile1("target/out/b1.txt", "foo") val output2 = StringVirtualFile1("target/out/b2.txt", "foo") Def.declareOutput(output1) Def.declareOutput(output2) "something" -}).value +} -mapN1 := (Def.cachedTask { +mapN1 := { pure1.value map1.value val output = StringVirtualFile1("target/out/c.txt", "foo") Def.declareOutput(output) () -}).value +} -checkMapN1 := { +checkMapN1 := Def.uncached { + val s = streams.value val config = Def.cacheConfiguration.value val prev = config.cacheEventLog.previous match case s: CacheEventSummary.Data => s - case s => sys.error(s"empty event log") - assert(prev.hitCount == 2, s"prev.hitCount = ${prev.hitCount}") + case s => sys.error(s"empty event log") + assert(prev.hitCount == 2, s"prev.hitCount = ${prev.hitCount} (expected 2)") } diff --git a/sbt-app/src/sbt-test/cache/cached-compile/build.sbt b/sbt-app/src/sbt-test/cache/cached-compile/build.sbt index c1c98f24f..33a4d8af5 100644 --- a/sbt-app/src/sbt-test/cache/cached-compile/build.sbt +++ b/sbt-app/src/sbt-test/cache/cached-compile/build.sbt @@ -1,16 +1,18 @@ import sbt.internal.util.CacheEventSummary +import complete.DefaultParsers.* -lazy val checkMiss = taskKey[Unit]("") +lazy val checkMiss = inputKey[Unit]("") Global / localCacheDirectory := baseDirectory.value / "diskcache" scalaVersion := "3.7.1" checkMiss := { + val expected: Int = (Space ~> NatBasic).parsed val s = streams.value val config = Def.cacheConfiguration.value val prev = config.cacheEventLog.previous match case s: CacheEventSummary.Data => s case _ => sys.error(s"empty event log") s.log.info(prev.missCount.toString) - assert(prev.missCount == 2, s"prev.missCount = ${prev.missCount}") + assert(prev.missCount > 0, s"prev.missCount = ${prev.missCount}") } diff --git a/sbt-app/src/sbt-test/cache/cached-compile/test b/sbt-app/src/sbt-test/cache/cached-compile/test index 8be7f374b..2cfd138fe 100644 --- a/sbt-app/src/sbt-test/cache/cached-compile/test +++ b/sbt-app/src/sbt-test/cache/cached-compile/test @@ -1,7 +1,7 @@ $ copy-file changes/A1.scala A.scala > run 1 -> checkMiss +> checkMiss 1 $ copy-file changes/A2.scala A.scala > run 2 -> checkMiss +> checkMiss 1 diff --git a/sbt-app/src/sbt-test/cache/compiler-plugin/build.sbt b/sbt-app/src/sbt-test/cache/compiler-plugin/build.sbt index 5a8fbde09..5d237d7d7 100644 --- a/sbt-app/src/sbt-test/cache/compiler-plugin/build.sbt +++ b/sbt-app/src/sbt-test/cache/compiler-plugin/build.sbt @@ -7,12 +7,14 @@ Global / localCacheDirectory := baseDirectory.value / "diskcache" scalaVersion := "2.13.16" addCompilerPlugin(("org.typelevel" % "kind-projector" % "0.13.3").cross(CrossVersion.full)) -check := { +check := Def.uncached { + val s = streams.value val config = Def.cacheConfiguration.value val prev = config.cacheEventLog.previous match case s: CacheEventSummary.Data => s - case s => sys.error(s"empty event log") - assert(prev.hitCount == 1, s"prev.hitCount = ${prev.hitCount}") + case s => sys.error(s"empty event log") + s.log.info(s"prev.missCount = ${prev.missCount}") + assert(prev.missCount == 0, s"prev.missCount = ${prev.missCount}") } lazy val foo = (project in file("foo")) diff --git a/sbt-app/src/sbt-test/cache/optout/build.sbt b/sbt-app/src/sbt-test/cache/optout/build.sbt index 0d34f05b6..f300a13a9 100644 --- a/sbt-app/src/sbt-test/cache/optout/build.sbt +++ b/sbt-app/src/sbt-test/cache/optout/build.sbt @@ -4,22 +4,22 @@ import CustomKeys.* Global / localCacheDirectory := baseDirectory.value / "diskcache" -aa := A() +aa := Def.uncached(A()) // This tests that aa is opted out from caching -map1 := (Def.cachedTask { +map1 := { aa.value val output1 = StringVirtualFile1("target/out/b1.txt", "foo") val output2 = StringVirtualFile1("target/out/b2.txt", "foo") Def.declareOutput(output1) Def.declareOutput(output2) "something" -}).value +} -mapN1 := (Def.cachedTask { +mapN1 := { aa.value map1.value val output = StringVirtualFile1("target/out/c.txt", "foo") Def.declareOutput(output) () -}).value +} 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 0856775ce..1508b62a5 100644 --- a/sbt-app/src/sbt-test/classloader-cache/jni/build.sbt +++ b/sbt-app/src/sbt-test/classloader-cache/jni/build.sbt @@ -18,22 +18,25 @@ val root = (project in file(".")).settings( sourceDirectory.value.toPath.resolve("main/native/include").toString), libraryDependencies += "com.lihaoyi" %% "utest" % "0.6.6" % "test", testFrameworks := Seq(new TestFramework("utest.runner.Framework")), - copyTestResources := { + copyTestResources := Def.uncached { val key = Def.spaceDelimited().parsed.head val base = baseDirectory.value.toPath val resources = (baseDirectory.value / "src" / "main" / "resources" / key).toPath Files.walk(resources).iterator.asScala.foreach { p => Files.copy(p, base.resolve(p.getFileName), StandardCopyOption.REPLACE_EXISTING) } + () }, - appendToLibraryPath := { + appendToLibraryPath := Def.uncached { val cp = System.getProperty("java.library.path", "").split(":") val newCp = if (cp.contains(".")) cp else cp :+ "." System.setProperty("java.library.path", newCp.mkString(":")) + () }, - dropLibraryPath := { + dropLibraryPath := Def.uncached { val cp = System.getProperty("java.library.path", "").split(":").dropRight(1) System.setProperty("java.library.path", cp.mkString(":")) + () }, wrappedRun := wrap(Runtime / run).value, wrappedTest := wrap(Test / testOnly).value diff --git a/sbt-app/src/sbt-test/compiler-project/error-in-invalidated/build.sbt b/sbt-app/src/sbt-test/compiler-project/error-in-invalidated/build.sbt index 442a697f7..e90b27327 100644 --- a/sbt-app/src/sbt-test/compiler-project/error-in-invalidated/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/error-in-invalidated/build.sbt @@ -2,5 +2,5 @@ ThisBuild / scalaVersion := "2.12.20" lazy val root = (project in file(".")). settings( - incOptions := xsbti.compile.IncOptions.of() + incOptions := Def.uncached(xsbti.compile.IncOptions.of()) ) diff --git a/sbt-app/src/sbt-test/compiler-project/inc-package-class-dependency/build.sbt b/sbt-app/src/sbt-test/compiler-project/inc-package-class-dependency/build.sbt index ce36e14da..870f885c9 100644 --- a/sbt-app/src/sbt-test/compiler-project/inc-package-class-dependency/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/inc-package-class-dependency/build.sbt @@ -1,6 +1,6 @@ import sbt.internal.inc.Analysis -TaskKey[Unit]("verify-binary-deps") := { +TaskKey[Unit]("verify-binary-deps") := Def.uncached { val a = (Compile / compile).value match { case a: Analysis => a } val classDir = (Compile / classDirectory).value val base = baseDirectory.value diff --git a/sbt-app/src/sbt-test/compiler-project/inc-pickled-existential/build.sbt b/sbt-app/src/sbt-test/compiler-project/inc-pickled-existential/build.sbt index aa808c75e..e5a6a4bfa 100644 --- a/sbt-app/src/sbt-test/compiler-project/inc-pickled-existential/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/inc-pickled-existential/build.sbt @@ -5,7 +5,7 @@ logLevel := Level.Debug // Reset compiler iterations, necessary because tests run in batch mode val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") -recordPreviousIterations := { +recordPreviousIterations := Def.uncached { val log = streams.value.log CompileState.previousIterations = { val previousAnalysis = (Compile / previousCompile).value.analysis.asScala diff --git a/sbt-app/src/sbt-test/compiler-project/inc-pickled-refinement/build.sbt b/sbt-app/src/sbt-test/compiler-project/inc-pickled-refinement/build.sbt index b27b7f236..e9e2e6c19 100644 --- a/sbt-app/src/sbt-test/compiler-project/inc-pickled-refinement/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/inc-pickled-refinement/build.sbt @@ -3,7 +3,7 @@ import complete.DefaultParsers._ // Reset compiler iterations, necessary because tests run in batch mode val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") -recordPreviousIterations := { +recordPreviousIterations := Def.uncached { val log = streams.value.log CompileState.previousIterations = { val previousAnalysis = (Compile / previousCompile).value.analysis.asScala diff --git a/sbt-app/src/sbt-test/compiler-project/no-bootclasspath/build.sbt b/sbt-app/src/sbt-test/compiler-project/no-bootclasspath/build.sbt index edd870753..61aa060ec 100644 --- a/sbt-app/src/sbt-test/compiler-project/no-bootclasspath/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/no-bootclasspath/build.sbt @@ -1,5 +1,5 @@ -TaskKey[Unit]("check212") := checkCp(true) -TaskKey[Unit]("check213") := checkCp(false) +TaskKey[Unit]("check212") := checkCp(true).value +TaskKey[Unit]("check213") := checkCp(false).value def checkCp(auto: Boolean) = Def.task { val opts = compilers.value.scalac.classpathOptions diff --git a/sbt-app/src/sbt-test/compiler-project/scala3-tasty-management/build.sbt b/sbt-app/src/sbt-test/compiler-project/scala3-tasty-management/build.sbt index 8264fcba0..47ff77e0f 100644 --- a/sbt-app/src/sbt-test/compiler-project/scala3-tasty-management/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/scala3-tasty-management/build.sbt @@ -3,9 +3,10 @@ import xsbti.compile.TastyFiles ThisBuild / scalaVersion := "3.3.1" -TaskKey[Unit]("check") := { +TaskKey[Unit]("check") := Def.uncached { assert((Compile / auxiliaryClassFiles).value == Seq(TastyFiles.instance)) assert((Test / auxiliaryClassFiles).value == Seq(TastyFiles.instance)) + () } TaskKey[Unit]("check2") := checkTastyFiles(true, true).value diff --git a/sbt-app/src/sbt-test/compiler-project/semantic-errors/build.sbt b/sbt-app/src/sbt-test/compiler-project/semantic-errors/build.sbt index 9633a5cf7..1e99e90fc 100644 --- a/sbt-app/src/sbt-test/compiler-project/semantic-errors/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/semantic-errors/build.sbt @@ -1,4 +1,4 @@ -TaskKey[Unit]("checkJavaFailures") := { +TaskKey[Unit]("checkJavaFailures") := Def.uncached { val reporter = savedReporter.value val ignore = (Compile / compile).failure.value val ps = reporter.problems.filter(_.severity() != xsbti.Severity.Info) @@ -9,9 +9,10 @@ TaskKey[Unit]("checkJavaFailures") := { val expected = "${BASE}/src/main/java/bad.java" val sourcePath = first.position.sourcePath.get assert(sourcePath == expected, s"$sourcePath == $expected was false") + () } -TaskKey[Unit]("checkScalaFailures") := { +TaskKey[Unit]("checkScalaFailures") := Def.uncached { val reporter = savedReporter.value val ignore = (Compile / compile).failure.value val ps = reporter.problems @@ -22,4 +23,5 @@ TaskKey[Unit]("checkScalaFailures") := { val expected = "${BASE}/src/main/scala/bad.scala" val sourcePath = first.position.sourcePath.get assert(sourcePath == expected, s"$sourcePath == $expected was false") + () } diff --git a/sbt-app/src/sbt-test/compiler-project/semantic-errors/project/src/main/scala/sbt/TestPlugin.scala b/sbt-app/src/sbt-test/compiler-project/semantic-errors/project/src/main/scala/sbt/TestPlugin.scala index 165405526..93c6e3f1b 100644 --- a/sbt-app/src/sbt-test/compiler-project/semantic-errors/project/src/main/scala/sbt/TestPlugin.scala +++ b/sbt-app/src/sbt-test/compiler-project/semantic-errors/project/src/main/scala/sbt/TestPlugin.scala @@ -14,8 +14,8 @@ object TestPlugin extends AutoPlugin { import autoImport._ override def projectSettings = Seq( savedReporter := new CollectingReporter, - Compile / compile / compilerReporter := savedReporter.value, - problems := savedReporter.value.problems + Compile / compile / compilerReporter := Def.uncached(savedReporter.value), + problems := Def.uncached(savedReporter.value.problems), ) } diff --git a/sbt-app/src/sbt-test/compiler-project/separate-analysis-per-scala/build.sbt b/sbt-app/src/sbt-test/compiler-project/separate-analysis-per-scala/build.sbt index ebd76a32e..9aa5d7ce8 100644 --- a/sbt-app/src/sbt-test/compiler-project/separate-analysis-per-scala/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/separate-analysis-per-scala/build.sbt @@ -6,10 +6,10 @@ lazy val root = (project in file(".")) .settings( name := "foo", crossScalaVersions := List(scala212, scala213), - incOptions := incOptions.value.withClassfileManagerType( + incOptions := Def.uncached(incOptions.value.withClassfileManagerType( Option(xsbti.compile.TransactionalManagerType.of( crossTarget.value / "classes.bak", (Compile / compile / streams).value.log ): xsbti.compile.ClassFileManagerType).asJava - ) + )) ) diff --git a/sbt-app/src/sbt-test/dependency-management/cache-local/changes/resolver.sbt b/sbt-app/src/sbt-test/dependency-management/cache-local/changes/resolver.sbt index 642794849..c425175c9 100644 --- a/sbt-app/src/sbt-test/dependency-management/cache-local/changes/resolver.sbt +++ b/sbt-app/src/sbt-test/dependency-management/cache-local/changes/resolver.sbt @@ -1,5 +1,5 @@ -publishTo := baseDirectory(base => Some(Resolver.file("filesys-publish", base / "repo")) ).value +publishTo := Def.uncached(baseDirectory(base => Some(Resolver.file("filesys-publish", base / "repo")) ).value) resolvers += baseDirectory(base => "filesys" at (base / "repo").toURI.toString).value diff --git a/sbt-app/src/sbt-test/dependency-management/chainresolver/build.sbt b/sbt-app/src/sbt-test/dependency-management/chainresolver/build.sbt index 26e67e2d3..6e54bdb5c 100644 --- a/sbt-app/src/sbt-test/dependency-management/chainresolver/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/chainresolver/build.sbt @@ -22,7 +22,7 @@ lazy val realCommonsIoClient = project. libraryDependencies := Seq( "commons-io" % "commons-io" % "1.3" ), - fullResolvers := fullResolvers.value.filterNot(_.name == "inter-project") + fullResolvers := Def.uncached(fullResolvers.value.filterNot(_.name == "inter-project")) ) lazy val fakeCommonsIo = project. diff --git a/sbt-app/src/sbt-test/dependency-management/default-resolvers/build.sbt b/sbt-app/src/sbt-test/dependency-management/default-resolvers/build.sbt index d0675d775..b7ec030e8 100644 --- a/sbt-app/src/sbt-test/dependency-management/default-resolvers/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/default-resolvers/build.sbt @@ -2,9 +2,10 @@ lazy val check = taskKey[Unit]("") lazy val root = (project in file(".")). settings( - check := { + check := Def.uncached { val fr = fullResolvers.value assert(!(fr exists { _.name == "jcenter" })) assert(fr exists { _.name == "public" }) + () }, ) diff --git a/sbt-app/src/sbt-test/dependency-management/evicted-semver-spec/build.sbt b/sbt-app/src/sbt-test/dependency-management/evicted-semver-spec/build.sbt index 9fee7ba51..7f007ae81 100644 --- a/sbt-app/src/sbt-test/dependency-management/evicted-semver-spec/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/evicted-semver-spec/build.sbt @@ -6,7 +6,7 @@ ThisBuild / csrCacheDirectory := (ThisBuild / baseDirectory).value / "coursier-c def commonSettings: Seq[Def.Setting[_]] = Seq( - fullResolvers := fullResolvers.value.filterNot(_.name == "inter-project"), + fullResolvers := Def.uncached(fullResolvers.value.filterNot(_.name == "inter-project")), publishTo := Some(MavenCache("local-maven", (LocalRootProject / target).value / "local-maven")), scalaCompilerBridgeResolvers += userLocalFileResolver(appConfiguration.value), resolvers += MavenCache("local-maven", (LocalRootProject / target).value / "local-maven"), diff --git a/sbt-app/src/sbt-test/dependency-management/exclude-dependencies/build.sbt b/sbt-app/src/sbt-test/dependency-management/exclude-dependencies/build.sbt index 11e675987..88ef1fd52 100644 --- a/sbt-app/src/sbt-test/dependency-management/exclude-dependencies/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/exclude-dependencies/build.sbt @@ -23,7 +23,7 @@ lazy val b = (project in file("b")). lazy val root = (project in file(".")). settings( - check := { + check := Def.uncached { (a / update).value (b / update).value val acp = (a / Compile / externalDependencyClasspath).value.sortBy {_.data.name} diff --git a/sbt-app/src/sbt-test/dependency-management/make-pom/build.sbt b/sbt-app/src/sbt-test/dependency-management/make-pom/build.sbt index 388f35898..ff88b76d0 100644 --- a/sbt-app/src/sbt-test/dependency-management/make-pom/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/make-pom/build.sbt @@ -1,7 +1,7 @@ import scala.xml._ lazy val root = (project in file(".")) settings ( - readPom := { + readPom := Def.uncached { val vf = makePom.value val converter = fileConverter.value XML.loadFile(converter.toPath(vf).toFile) @@ -37,13 +37,12 @@ def withRepositories[T](pomXML: Elem)(f: NodeSeq => T) = { else sys.error("'repositories' element not found in generated pom") } -lazy val checkExtra = readPom map { pomXML => +lazy val checkExtra = readPom.map: pomXML => checkProject(pomXML) val extra = pomXML \ extraTagName if (extra.isEmpty) sys.error("'" + extraTagName + "' not found in generated pom.xml.") else () -} -lazy val checkVersionPlusMapping = (readPom) map { (pomXml) => +lazy val checkVersionPlusMapping = readPom.map: pomXml => var found = false for { dep <- pomXml \ "dependencies" \ "dependency" @@ -52,19 +51,18 @@ lazy val checkVersionPlusMapping = (readPom) map { (pomXml) => if (dep \ "version").text != "[1.3,1.4)" } sys.error(s"Found dependency with invalid maven version: $dep") () -} -lazy val checkAPIURL = (readPom) map { (pomXml) => +lazy val checkAPIURL = readPom.map: pomXml => val notes = pomXml \ "properties" \ "info.apiURL" - if (notes.isEmpty) sys.error("'apiURL' not found in generated pom.xml.") else () -} + if (notes.isEmpty) sys.error("'apiURL' not found in generated pom.xml.") + else () -lazy val checkReleaseNotesURL = (readPom) map { (pomXml) => +lazy val checkReleaseNotesURL = readPom.map: pomXml => val notes = pomXml \ "properties" \ "info.releaseNotesUrl" - if (notes.isEmpty) sys.error("'releaseNotesUrl' not found in generated pom.xml.") else () -} + if (notes.isEmpty) sys.error("'releaseNotesUrl' not found in generated pom.xml.") + else () -lazy val checkPom = Def task { +lazy val checkPom = Def.task { val pomXML = readPom.value checkProject(pomXML) val ivyRepositories = fullResolvers.value diff --git a/sbt-app/src/sbt-test/dependency-management/module-name/build.sbt b/sbt-app/src/sbt-test/dependency-management/module-name/build.sbt index edbd9b91e..a369e73ab 100644 --- a/sbt-app/src/sbt-test/dependency-management/module-name/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/module-name/build.sbt @@ -4,7 +4,7 @@ moduleName := "asdf" crossPaths := false -TaskKey[Unit]("checkName") := Def task { +TaskKey[Unit]("checkName") := Def.uncached { val converter = fileConverter.value val vf = (Compile / packageBin).value val path = converter.toPath(vf).toAbsolutePath.toString @@ -12,4 +12,5 @@ TaskKey[Unit]("checkName") := Def task { val n = name.value assert(path contains module, s"Path $path did not contain module name $module") assert(!path.contains(n), s"Path $path contained $n") + () } diff --git a/sbt-app/src/sbt-test/dependency-management/publish-to-maven-local-file/build.sbt b/sbt-app/src/sbt-test/dependency-management/publish-to-maven-local-file/build.sbt index 06c06a9dc..37e203ebe 100644 --- a/sbt-app/src/sbt-test/dependency-management/publish-to-maven-local-file/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/publish-to-maven-local-file/build.sbt @@ -9,7 +9,7 @@ lazy val common = name := "config", organization := "com.typesafe", version := "0.4.9-SNAPSHOT", - publishTo := Some(localRemote), + publishTo := Def.uncached(Some(localRemote)), autoScalaLibrary := false, crossPaths := false ) @@ -24,7 +24,7 @@ lazy val analyze = resolvers += localRemote, resolvers += Resolver.mavenLocal, resolvers += Resolver.sonatypeRepo("snapshots"), - fullResolvers := fullResolvers.value.filterNot(_.name == "inter-project") + fullResolvers := Def.uncached(fullResolvers.value.filterNot(_.name == "inter-project")) ) diff --git a/sbt-app/src/sbt-test/dependency-management/scala3-compiler-bridge-binary/build.sbt b/sbt-app/src/sbt-test/dependency-management/scala3-compiler-bridge-binary/build.sbt index 2b8d468cc..1bc19a8ca 100644 --- a/sbt-app/src/sbt-test/dependency-management/scala3-compiler-bridge-binary/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/scala3-compiler-bridge-binary/build.sbt @@ -2,7 +2,8 @@ ThisBuild / scalaVersion := "3.3.4" lazy val check = taskKey[Unit]("") -check := { +check := Def.uncached { val bridge = scalaCompilerBridgeBinaryJar.value bridge.getOrElse(sys.error(s"bridge JAR is missing")) + () } diff --git a/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/build.sbt b/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/build.sbt index 706a6ca08..05b883844 100644 --- a/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/build.sbt @@ -2,7 +2,7 @@ scalaVersion := "3.3.4" val makeHome = taskKey[Unit]("Populates the 'home/lib' directory with Scala jars from the default ScalaInstance") -makeHome := { +makeHome := Def.uncached { val lib = baseDirectory.value / "home" / "lib" for(jar <- scalaInstance.value.allJars) IO.copyFile(jar, lib / jar.getName) diff --git a/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/changes/real-build.sbt b/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/changes/real-build.sbt index 876da64cf..b1776e7e4 100644 --- a/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/changes/real-build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/scala3-scala-home/changes/real-build.sbt @@ -3,7 +3,7 @@ scalaHome := Some(baseDirectory.value / "home") val checkUpdate = taskKey[Unit]("Ensures that resolved Scala artifacts are replaced with ones from the configured Scala home directory") -checkUpdate := { +checkUpdate := Def.uncached { val report = update.value val lib = (scalaHome.value.get / "lib").getCanonicalFile for(f <- report.allFiles) diff --git a/sbt-app/src/sbt-test/dependency-management/snapshot-local/build.sbt b/sbt-app/src/sbt-test/dependency-management/snapshot-local/build.sbt index 64097d033..d4b63e5a9 100644 --- a/sbt-app/src/sbt-test/dependency-management/snapshot-local/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/snapshot-local/build.sbt @@ -33,6 +33,6 @@ lazy val dependent = project .settings( // Ignore the inter-project resolver, so we force to look remotely. resolvers += sharedResolver, - fullResolvers := fullResolvers.value.filterNot(_==projectResolver.value), + fullResolvers := Def.uncached(fullResolvers.value.filterNot(_==projectResolver.value)), libraryDependencies += "com.badexample" % "badexample" % "1.0-SNAPSHOT" ) diff --git a/sbt-app/src/sbt-test/dependency-management/update-sbt-classifiers/build.sbt b/sbt-app/src/sbt-test/dependency-management/update-sbt-classifiers/build.sbt index 4725b5c1a..05607d0bd 100644 --- a/sbt-app/src/sbt-test/dependency-management/update-sbt-classifiers/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/update-sbt-classifiers/build.sbt @@ -1,8 +1,8 @@ -ivyConfiguration := { +ivyConfiguration := Def.uncached { throw new RuntimeException("updateSbtClassifiers should use updateSbtClassifiers / ivyConfiguration") } -dependencyResolution := { +dependencyResolution := Def.uncached { throw new RuntimeException("updateSbtClassifiers should use updateSbtClassifiers / dependencyResolution") } @@ -12,7 +12,7 @@ lazy val root = (project in file(".")) scalaOrganization := "doesnt.exist", name := "myProjectName", - TaskKey[Unit]("checkModuleIdsInUpdateSbtClassifiers") := { + TaskKey[Unit]("checkModuleIdsInUpdateSbtClassifiers") := Def.uncached { val updateReport = updateSbtClassifiers.value val moduleReports = updateReport.configurations.find(_.configuration.name == "default").get.modules @@ -82,7 +82,7 @@ lazy val root = (project in file(".")) ) def assertCollectionsEqual(message: String, expected: Seq[String], actual: Seq[String]): Unit = // using the new line for a more readable comparison failure output - org.junit.Assert.assertEquals(message: String, expected.mkString("\n"), actual.mkString("\n")) + assert(expected.mkString("\n") == actual.mkString("\n"), message) assertCollectionsEqual( "Unexpected module ids in updateSbtClassifiers", diff --git a/sbt-app/src/sbt-test/lm-coursier/coursier-cache/build.sbt b/sbt-app/src/sbt-test/lm-coursier/coursier-cache/build.sbt index 7566b5462..059b49c25 100644 --- a/sbt-app/src/sbt-test/lm-coursier/coursier-cache/build.sbt +++ b/sbt-app/src/sbt-test/lm-coursier/coursier-cache/build.sbt @@ -1,12 +1,14 @@ -TaskKey[Unit]("checkIsDefaultCache") := { +TaskKey[Unit]("checkIsDefaultCache") := Def.uncached { val csrCacheDir = csrCacheDirectory.value assert(csrCacheDir == sbt.coursierint.LMCoursier.defaultCacheLocation, csrCacheDir.toString) val expectedPath = if Util.isWindows then "Coursier\\Cache\\v1" else ".cache/coursier/v1" - assert(csrCacheDir.toString.endsWith(expectedPath), csrCacheDir.toString) + assert(csrCacheDir.toString.endsWith(expectedPath), s"$csrCacheDir does not end with $expectedPath") + () } -TaskKey[Unit]("checkIsCustomCache") := { +TaskKey[Unit]("checkIsCustomCache") := Def.uncached { val csrCacheDir = csrCacheDirectory.value val ip = ivyPaths.value assert(csrCacheDir == file(ip.ivyHome.get) / "coursier-cache", csrCacheDir.toString) + () } diff --git a/sbt-app/src/sbt-test/lm-coursier/logger/build.sbt b/sbt-app/src/sbt-test/lm-coursier/logger/build.sbt index 46eeca01f..844f37888 100644 --- a/sbt-app/src/sbt-test/lm-coursier/logger/build.sbt +++ b/sbt-app/src/sbt-test/lm-coursier/logger/build.sbt @@ -6,7 +6,7 @@ libraryDependencies += "org.slf4j" % "slf4j-api" % "1.7.25" csrCacheDirectory := baseDirectory.value / "cache" logFile := baseDirectory.value / "log" -csrLogger := { +csrLogger := Def.uncached { var logStream: java.io.PrintStream = null def log(msg: String): Unit = { println(msg) diff --git a/sbt-app/src/sbt-test/package/mappings-directory/build.sbt b/sbt-app/src/sbt-test/package/mappings-directory/build.sbt index 7e6a058a3..8e9d512fa 100644 --- a/sbt-app/src/sbt-test/package/mappings-directory/build.sbt +++ b/sbt-app/src/sbt-test/package/mappings-directory/build.sbt @@ -9,8 +9,9 @@ Compile / packageBin / mappings ++= { } lazy val unzipPackage = taskKey[Unit]("extract jar file") -unzipPackage := { +unzipPackage := Def.uncached { val converter = fileConverter.value val p = converter.toPath((Compile / packageBin).value) IO.unzip(p.toFile(), target.value / "extracted") + () } diff --git a/sbt-app/src/sbt-test/package/mappings/build.sbt b/sbt-app/src/sbt-test/package/mappings/build.sbt index 3cf1bf928..dab5b8c87 100644 --- a/sbt-app/src/sbt-test/package/mappings/build.sbt +++ b/sbt-app/src/sbt-test/package/mappings/build.sbt @@ -15,8 +15,9 @@ Compile / packageBin / mappings ++= { } lazy val unzipPackage = taskKey[Unit]("extract jar file") -unzipPackage := { +unzipPackage := Def.uncached { val converter = fileConverter.value val p = converter.toPath((Compile / packageBin).value) IO.unzip(p.toFile(), target.value / "extracted") + () } diff --git a/sbt-app/src/sbt-test/run/classpath/build.sbt b/sbt-app/src/sbt-test/run/classpath/build.sbt index 219847e8c..1713eff84 100644 --- a/sbt-app/src/sbt-test/run/classpath/build.sbt +++ b/sbt-app/src/sbt-test/run/classpath/build.sbt @@ -1,4 +1,4 @@ -(Runtime / externalDependencyClasspath) += { +(Runtime / externalDependencyClasspath) += Def.uncached { val converter = fileConverter.value converter.toVirtualFile(file("conf").toPath): HashedVirtualFileRef } \ No newline at end of file diff --git a/sbt-app/src/sbt-test/run/concurrent/build.sbt b/sbt-app/src/sbt-test/run/concurrent/build.sbt index 4578d405f..99c670a19 100644 --- a/sbt-app/src/sbt-test/run/concurrent/build.sbt +++ b/sbt-app/src/sbt-test/run/concurrent/build.sbt @@ -1,7 +1,7 @@ lazy val runTest = taskKey[Unit]("Run the test applications.") def runTestTask(pre: Def.Initialize[Task[Unit]]) = - runTest := { + runTest := Def.uncached { val _ = pre.value val r = (Compile / run / runner).value val cp = (Compile / fullClasspath).value @@ -9,11 +9,12 @@ def runTestTask(pre: Def.Initialize[Task[Unit]]) = val args = baseDirectory.value.getAbsolutePath :: Nil given FileConverter = fileConverter.value r.run(main, cp.files, args, streams.value.log).get + () } lazy val b = project.settings( runTestTask( waitForCStart ), - runTest := { + runTest := Def.uncached { val _ = runTest.value val cFinished = (c / baseDirectory).value / "finished" assert( !cFinished.exists, "C finished before B") diff --git a/sbt-app/src/sbt-test/source-dependencies/abstract-type-override/build.sbt b/sbt-app/src/sbt-test/source-dependencies/abstract-type-override/build.sbt index 3888dda98..215418ce9 100644 --- a/sbt-app/src/sbt-test/source-dependencies/abstract-type-override/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/abstract-type-override/build.sbt @@ -3,7 +3,7 @@ import complete.DefaultParsers._ // Reset compiler iterations, necessary because tests run in batch mode val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") -recordPreviousIterations := { +recordPreviousIterations := Def.uncached { val log = streams.value.log CompileState.previousIterations = { val previousAnalysis = (Compile / previousCompile).value.analysis.asScala @@ -14,6 +14,7 @@ recordPreviousIterations := { case Some(a: Analysis) => a.compilations.allCompilations.size } } + () } val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.") diff --git a/sbt-app/src/sbt-test/source-dependencies/canon/build.sbt b/sbt-app/src/sbt-test/source-dependencies/canon/build.sbt index 3888dda98..215418ce9 100644 --- a/sbt-app/src/sbt-test/source-dependencies/canon/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/canon/build.sbt @@ -3,7 +3,7 @@ import complete.DefaultParsers._ // Reset compiler iterations, necessary because tests run in batch mode val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") -recordPreviousIterations := { +recordPreviousIterations := Def.uncached { val log = streams.value.log CompileState.previousIterations = { val previousAnalysis = (Compile / previousCompile).value.analysis.asScala @@ -14,6 +14,7 @@ recordPreviousIterations := { case Some(a: Analysis) => a.compilations.allCompilations.size } } + () } val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.") diff --git a/sbt-app/src/sbt-test/source-dependencies/compactify/build.sbt b/sbt-app/src/sbt-test/source-dependencies/compactify/build.sbt index 10eb6d602..de3794234 100644 --- a/sbt-app/src/sbt-test/source-dependencies/compactify/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/compactify/build.sbt @@ -1,4 +1,4 @@ -TaskKey[Unit]("outputEmpty") := { +TaskKey[Unit]("outputEmpty") := Def.uncached { val c = fileConverter.value val dir = c.toPath((Compile / backendOutput).value).toFile() def classes = dir.**("*.class").get() diff --git a/sbt-app/src/sbt-test/source-dependencies/restore-classes/build.sbt b/sbt-app/src/sbt-test/source-dependencies/restore-classes/build.sbt index cf56984fa..f10e1a56f 100644 --- a/sbt-app/src/sbt-test/source-dependencies/restore-classes/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/restore-classes/build.sbt @@ -5,7 +5,7 @@ import complete.DefaultParsers._ // Reset compiler iterations, necessary because tests run in batch mode val recordPreviousIterations = taskKey[Unit]("Record previous iterations.") -recordPreviousIterations := { +recordPreviousIterations := Def.uncached { val log = streams.value.log CompileState.previousIterations = { val previousAnalysis = (Compile / previousCompile).value.analysis.asScala @@ -17,6 +17,7 @@ recordPreviousIterations := { case Some(_) => -1 // should be unreachable but causes warnings } } + () } val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.") diff --git a/sbt-app/src/sbt-test/source-dependencies/trait-member-modified/build.sbt b/sbt-app/src/sbt-test/source-dependencies/trait-member-modified/build.sbt index d095d9c32..0038b708e 100644 --- a/sbt-app/src/sbt-test/source-dependencies/trait-member-modified/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/trait-member-modified/build.sbt @@ -3,7 +3,7 @@ import sbt.internal.inc.Analysis import xsbti.compile.{PreviousResult, CompileAnalysis, MiniSetup} import xsbti.compile.analysis.{ Compilation => XCompilation } -(Compile / previousCompile) := { +(Compile / previousCompile) := Def.uncached { val previous = (Compile / previousCompile).value if (!CompileState.isNew) { val res = PreviousResult.of(none[CompileAnalysis].asJava, none[MiniSetup].asJava) @@ -16,7 +16,7 @@ import xsbti.compile.analysis.{ Compilation => XCompilation } * a) checks in which compilation given set of files was recompiled * b) checks overall number of compilations performed */ -TaskKey[Unit]("checkCompilations") := { +TaskKey[Unit]("checkCompilations") := Def.uncached { val analysis = (Compile / compile).value match { case a: Analysis => a } val srcDir = (Compile / scalaSource).value def findFile(className: String): VirtualFileRef = { diff --git a/sbt-app/src/sbt-test/source-dependencies/transitive-memberRef/build.sbt b/sbt-app/src/sbt-test/source-dependencies/transitive-memberRef/build.sbt index 868664c24..24ed68988 100644 --- a/sbt-app/src/sbt-test/source-dependencies/transitive-memberRef/build.sbt +++ b/sbt-app/src/sbt-test/source-dependencies/transitive-memberRef/build.sbt @@ -7,7 +7,7 @@ import xsbti.compile.analysis.{ Compilation => XCompilation } logLevel := Level.Debug // Reset compile status because scripted tests are run in batch mode -(Compile / previousCompile) := { +(Compile / previousCompile) := Def.uncached { val previous = (Compile / previousCompile).value if (!CompileState.isNew) { val res = PreviousResult.of(none[CompileAnalysis].asJava, none[MiniSetup].asJava) @@ -20,7 +20,7 @@ logLevel := Level.Debug // some fraction (e.g. 50%) of files is scheduled to be recompiled // in this test we want precise information about recompiled files // which that heuristic would distort -incOptions := incOptions.value.withRecompileAllFraction(1.0) +incOptions := Def.uncached(incOptions.value.withRecompileAllFraction(1.0)) Global / allowMachinePath := false @@ -28,7 +28,7 @@ Global / allowMachinePath := false * a) checks in which compilation given set of files was recompiled * b) checks overall number of compilations performed */ -TaskKey[Unit]("checkCompilations") := { +TaskKey[Unit]("checkCompilations") := Def.uncached { val log = streams.value.log val c = fileConverter.value val vs = (Compile / sources).value.toVector map { x => @@ -66,4 +66,5 @@ TaskKey[Unit]("checkCompilations") := { // Note that Y.scala is not recompiled because it depends just on X through member reference dependency recompiledFilesInIteration(2, Set("B.scala", "C.scala", "D.scala")) assert(allCompilations.size == 3) + () } diff --git a/sbt-app/src/sbt-test/tests/arguments/build.sbt b/sbt-app/src/sbt-test/tests/arguments/build.sbt index e424bc0e4..97cf62c81 100644 --- a/sbt-app/src/sbt-test/tests/arguments/build.sbt +++ b/sbt-app/src/sbt-test/tests/arguments/build.sbt @@ -16,7 +16,7 @@ lazy val root = (project in file(".")) // testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-f", "result.txt", "-eNDXEHLO") Configurations.Test / testOptions ++= { def args(path: String, args: String*): Seq[TestOption] = - if(file(path).exists) Tests.Argument(args : _*) :: Nil + if file(path).exists then Tests.Argument(args*) :: Nil else Nil args("success1", "-n", "test2 test3") ++ args("success2", "-n", "test2") ++ diff --git a/sbt-app/src/sbt-test/tests/bak/build.sbt b/sbt-app/src/sbt-test/tests/bak/build.sbt index 63777d713..b92d11dea 100644 --- a/sbt-app/src/sbt-test/tests/bak/build.sbt +++ b/sbt-app/src/sbt-test/tests/bak/build.sbt @@ -1,5 +1,7 @@ // https://github.com/sbt/sbt/issues/1673#issuecomment-537327439 +Global / localCacheDirectory := baseDirectory.value / "diskcache" + val Config_0 = config("config-0").extend(Compile) val Config_1 = config("config-1").extend(Compile) val Config_2 = config("config-2").extend(Compile) @@ -23,7 +25,7 @@ val t = taskKey[Unit]("") val p1 = project .configs(CustomConfigs: _*) .settings( - t := { + t := Def.uncached { (Config_0 / compile).value (Config_1 / compile).value (Config_2 / compile).value @@ -40,6 +42,7 @@ val p1 = project (Config_13 / compile).value (Config_14 / compile).value (Config_15 / compile).value + () } ) .settings(CustomConfigs.flatMap(c => inConfig(c)(Defaults.testSettings))) diff --git a/sbt-app/src/sbt-test/tests/empty/build.sbt b/sbt-app/src/sbt-test/tests/empty/build.sbt index e9ed5a04a..275454168 100644 --- a/sbt-app/src/sbt-test/tests/empty/build.sbt +++ b/sbt-app/src/sbt-test/tests/empty/build.sbt @@ -1,4 +1,4 @@ -testGrouping := { +testGrouping := Def.uncached { val tests = (Test / definedTests).value tests map { test => new Tests.Group( diff --git a/sbt-app/src/sbt-test/tests/fork-test-group-parallel-custom-tags/build.sbt b/sbt-app/src/sbt-test/tests/fork-test-group-parallel-custom-tags/build.sbt index 9cb595477..50f0f5eb7 100644 --- a/sbt-app/src/sbt-test/tests/fork-test-group-parallel-custom-tags/build.sbt +++ b/sbt-app/src/sbt-test/tests/fork-test-group-parallel-custom-tags/build.sbt @@ -8,7 +8,7 @@ Global / concurrentRestrictions := Seq(Tags.limit(TestATypeTag, 1), Tags.limit(T libraryDependencies += specs % Test inConfig(Test)(Seq( - testGrouping := { + testGrouping := Def.uncached { val home = javaHome.value val strategy = outputStrategy.value val baseDir = baseDirectory.value @@ -29,5 +29,8 @@ inConfig(Test)(Seq( ), Seq((if (test.name.contains("TestA")) TestATypeTag else TestBTypeTag) -> 1)) } }, - TaskKey[Unit]("test-failure") := testFull.failure.value + TaskKey[Unit]("test-failure") := Def.uncached { + testFull.failure.value + () + } )) diff --git a/sbt-app/src/sbt-test/tests/fork-test-group-parallel/build.sbt b/sbt-app/src/sbt-test/tests/fork-test-group-parallel/build.sbt index f11b03e89..5c84166af 100644 --- a/sbt-app/src/sbt-test/tests/fork-test-group-parallel/build.sbt +++ b/sbt-app/src/sbt-test/tests/fork-test-group-parallel/build.sbt @@ -4,7 +4,7 @@ ThisBuild / scalaVersion := "2.12.20" Global / concurrentRestrictions := Seq(Tags.limitAll(4)) libraryDependencies += specs % Test inConfig(Test)(Seq( - testGrouping := { + testGrouping := Def.uncached { val home = javaHome.value val strategy = outputStrategy.value val baseDir = baseDirectory.value @@ -23,5 +23,8 @@ inConfig(Test)(Seq( ) ))} }, - TaskKey[Unit]("test-failure") := testFull.failure.value + TaskKey[Unit]("test-failure") := Def.uncached { + testFull.failure.value + () + } )) diff --git a/sbt-app/src/sbt-test/tests/fork/build.sbt b/sbt-app/src/sbt-test/tests/fork/build.sbt index ba8afcd46..04553d69d 100644 --- a/sbt-app/src/sbt-test/tests/fork/build.sbt +++ b/sbt-app/src/sbt-test/tests/fork/build.sbt @@ -16,7 +16,7 @@ ThisBuild / organization := "org.example" lazy val root = (project in file(".")) .settings( - Test / testGrouping := { + Test / testGrouping := Def.uncached { val tests = (Test / definedTests).value assert(tests.size == 3) for (idx <- 0 until groups) yield @@ -26,7 +26,7 @@ lazy val root = (project in file(".")) SubProcess(ForkOptions().withRunJVMOptions(Vector("-Dgroup.prefix=" + groupPrefix(idx)))) ) }, - check := { + check := Def.uncached { val files = for(i <- 0 until groups; j <- 1 to groupSize) yield file(groupPrefix(i) + j) diff --git a/sbt-app/src/sbt-test/tests/many-values/build.sbt b/sbt-app/src/sbt-test/tests/many-values/build.sbt index b210990e3..ff51438b9 100644 --- a/sbt-app/src/sbt-test/tests/many-values/build.sbt +++ b/sbt-app/src/sbt-test/tests/many-values/build.sbt @@ -48,7 +48,7 @@ a21 := 21 a22 := 22 a23 := 23 -TaskKey[Unit]("check") := { +TaskKey[Unit]("check") := Def.uncached { val sum = ( a1.value ++ List( a2.value, @@ -76,4 +76,5 @@ TaskKey[Unit]("check") := { ) ).sum assert(sum == 276, sum) + () } diff --git a/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt b/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt index 3e6c71bef..d8c20ef35 100644 --- a/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt +++ b/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt @@ -11,11 +11,12 @@ lazy val root = (project in file(".")) libraryDependencies += { "org.scala-lang" % "scala-compiler" % scalaVersion.value % OtherScala.name }, - OtherScala / managedClasspath := - Classpaths.managedJars(OtherScala, classpathTypes.value, update.value, fileConverter.value), + OtherScala / managedClasspath := Def.uncached { + Classpaths.managedJars(OtherScala, classpathTypes.value, update.value, fileConverter.value) + }, // Hack in the scala instance - scalaInstance := { + scalaInstance := Def.uncached { val converter = fileConverter.value val rawJars = (OtherScala / managedClasspath).value.map(c => converter.toPath(c.data).toFile) val scalaHome = (target.value / "scala-home") diff --git a/sbt-app/src/sbt-test/tests/source-directory-name/build.sbt b/sbt-app/src/sbt-test/tests/source-directory-name/build.sbt index fdde0b775..72db2fad3 100644 --- a/sbt-app/src/sbt-test/tests/source-directory-name/build.sbt +++ b/sbt-app/src/sbt-test/tests/source-directory-name/build.sbt @@ -5,4 +5,5 @@ TaskKey[Unit]("check") := { val c = fileConverter.value Using.jarFile(false)(c.toPath(p).toFile()): jar => assert(jar.getJarEntry("ch/epfl/scala/Client.class") ne null) + () } diff --git a/server-test/src/server-test/buildserver/build.sbt b/server-test/src/server-test/buildserver/build.sbt index 5ce45cc78..62465c8e5 100644 --- a/server-test/src/server-test/buildserver/build.sbt +++ b/server-test/src/server-test/buildserver/build.sbt @@ -25,7 +25,7 @@ lazy val reportWarning = project.in(file("report-warning")) // check that the buildTarget/compile request fails with the custom message defined below lazy val respondError = project.in(file("respond-error")) .settings( - Compile / compile := { + Compile / compile := Def.uncached { val _ = (Compile / compile).value throw new MessageOnlyException("custom message") } @@ -51,14 +51,14 @@ def somethingBad = throw new MessageOnlyException("I am a bad build target") // other build targets should not be affected by this bad build target lazy val badBuildTarget = project.in(file("bad-build-target")) .settings( - Compile / bspBuildTarget := somethingBad, - Compile / bspBuildTargetSourcesItem := somethingBad, - Compile / bspBuildTargetResourcesItem := somethingBad, - Compile / bspBuildTargetDependencySourcesItem := somethingBad, - Compile / bspBuildTargetScalacOptionsItem := somethingBad, - Compile / bspBuildTargetCompileItem := somethingBad, - Compile / bspBuildTargetOutputPathsItem := somethingBad, - Compile / bspScalaMainClasses := somethingBad, - Test / bspBuildTarget := somethingBad, - Test / bspScalaTestClasses := somethingBad, + Compile / bspBuildTarget := Def.uncached(somethingBad), + Compile / bspBuildTargetSourcesItem := Def.uncached(somethingBad), + Compile / bspBuildTargetResourcesItem := Def.uncached(somethingBad), + Compile / bspBuildTargetDependencySourcesItem := Def.uncached(somethingBad), + Compile / bspBuildTargetScalacOptionsItem := Def.uncached(somethingBad), + Compile / bspBuildTargetCompileItem := Def.uncached(somethingBad), + Compile / bspBuildTargetOutputPathsItem := Def.uncached(somethingBad), + Compile / bspScalaMainClasses := Def.uncached(somethingBad), + Test / bspBuildTarget := Def.uncached(somethingBad), + Test / bspScalaTestClasses := Def.uncached(somethingBad), ) diff --git a/server-test/src/server-test/response/build.sbt b/server-test/src/server-test/response/build.sbt index d60077a88..c3eb77523 100644 --- a/server-test/src/server-test/response/build.sbt +++ b/server-test/src/server-test/response/build.sbt @@ -66,7 +66,7 @@ lazy val root = (project in file(".")) s0.notifyEvent("foo/something", "something") s0 }, - fooClasspath := { + fooClasspath := Def.uncached { val s = state.value val converter = fileConverter.value val cp = (Compile / fullClasspath).value diff --git a/util-cache/src/main/scala/sbt/util/ActionCache.scala b/util-cache/src/main/scala/sbt/util/ActionCache.scala index ee554a10b..59436ab31 100644 --- a/util-cache/src/main/scala/sbt/util/ActionCache.scala +++ b/util-cache/src/main/scala/sbt/util/ActionCache.scala @@ -215,6 +215,12 @@ class BuildWideCacheConfiguration( s"BuildWideCacheConfiguration(store = $store, outputDirectory = $outputDirectory)" end BuildWideCacheConfiguration +object Uncached: + /** + * Marker function to make the task uncached. + */ + def apply[A1](a: A1): A1 = a + @meta.getter class cacheLevel( include: Array[CacheLevelTag],