From 1c03463e190f7e4e89c11df97a421b160260e543 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Thu, 4 Apr 2024 12:28:52 +0200 Subject: [PATCH] Fix test-quick --- main/src/main/scala/sbt/Defaults.scala | 43 ++++++++----------- main/src/main/scala/sbt/RemoteCache.scala | 28 +++++------- .../src/sbt-test/tests/test-quick/build.sbt | 2 + .../tests/test-quick/{pending => test} | 2 +- 4 files changed, 33 insertions(+), 42 deletions(-) rename sbt-app/src/sbt-test/tests/test-quick/{pending => test} (98%) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index b52fca223..1caf725f4 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1427,40 +1427,35 @@ object Defaults extends BuildCommon { Def.task { val cp = (test / fullClasspath).value val s = (test / streams).value - val ans: Seq[Analysis] = cp + val analyses: Seq[Analysis] = cp .flatMap(_.metadata.get(Keys.analysis)) .map: str => RemoteCache.getCachedAnalysis(str).asInstanceOf[Analysis] val succeeded = TestStatus.read(succeededFile(s.cacheDirectory)) val stamps = collection.mutable.Map.empty[String, Long] - def stamp(dep: String): Long = { - val stamps = for (a <- ans) yield intlStamp(dep, a, Set.empty) - if (stamps.isEmpty) Long.MinValue - else stamps.max - } - def intlStamp(c: String, analysis: Analysis, s: Set[String]): Long = { - if (s contains c) Long.MinValue + def stamp(dep: String): Option[Long] = + analyses.flatMap(internalStamp(dep, _, Set.empty)).maxOption + def internalStamp(c: String, analysis: Analysis, alreadySeen: Set[String]): Option[Long] = { + if (alreadySeen.contains(c)) None else - stamps.getOrElse( - c, { - val x = { - import analysis.{ apis, relations } - relations.internalClassDeps(c).map(intlStamp(_, analysis, s + c)) ++ - relations.externalDeps(c).map(stamp) ++ - relations.productClassName.reverse(c).flatMap { pc => - apis.internal.get(pc).map(_.compilationTimestamp) - } + Long.MinValue - }.max - if (x != Long.MinValue) { - stamps(c) = x - } - x + def computeAndStoreStamp: Option[Long] = { + import analysis.{ apis, relations } + val internalDeps = relations + .internalClassDeps(c) + .flatMap(internalStamp(_, analysis, alreadySeen + c)) + val externalDeps = relations.externalDeps(c).flatMap(stamp) + val classStamps = relations.productClassName.reverse(c).flatMap { pc => + apis.internal.get(pc).map(_.compilationTimestamp) } - ) + val maxStamp = (internalDeps ++ externalDeps ++ classStamps).maxOption + maxStamp.foreach(maxStamp => stamps(c) = maxStamp) + maxStamp + } + stamps.get(c).orElse(computeAndStoreStamp) } def noSuccessYet(test: String) = succeeded.get(test) match { case None => true - case Some(ts) => stamps.synchronized(stamp(test)) > ts + case Some(ts) => stamps.synchronized(stamp(test)).exists(_ > ts) } args => for (filter <- selectedFilter(args)) diff --git a/main/src/main/scala/sbt/RemoteCache.scala b/main/src/main/scala/sbt/RemoteCache.scala index 91801f920..a4c593a89 100644 --- a/main/src/main/scala/sbt/RemoteCache.scala +++ b/main/src/main/scala/sbt/RemoteCache.scala @@ -22,16 +22,10 @@ import sbt.ProjectExtra.* import sbt.ScopeFilter.Make._ import sbt.SlashSyntax0._ import sbt.coursierint.LMCoursier -import sbt.internal.inc.{ - CompileOutput, - FileAnalysisStore, - HashUtil, - JarUtils, - MappedFileConverter -} +import sbt.internal.inc.{ CompileOutput, HashUtil, JarUtils, MappedFileConverter } import sbt.internal.librarymanagement._ import sbt.internal.remotecache._ -import sbt.internal.inc.Analysis +import sbt.internal.inc.{ Analysis, MixedAnalyzingCompiler } import sbt.io.IO import sbt.io.syntax._ import sbt.librarymanagement._ @@ -50,7 +44,7 @@ import sbt.util.{ } import sjsonnew.JsonFormat import xsbti.{ HashedVirtualFileRef, VirtualFileRef } -import xsbti.compile.{ AnalysisContents, CompileAnalysis, MiniSetup, MiniOptions } +import xsbti.compile.{ AnalysisContents, AnalysisStore, CompileAnalysis, MiniSetup, MiniOptions } import scala.collection.mutable @@ -83,13 +77,10 @@ object RemoteCache { private[sbt] def getCachedAnalysis(ref: HashedVirtualFileRef): CompileAnalysis = analysisStore.getOrElseUpdate( ref, { - val vfs = cacheStore.getBlobs(ref :: Nil) - if vfs.nonEmpty then - val outputDirectory = Def.cacheConfiguration.outputDirectory - cacheStore.syncBlobs(vfs, outputDirectory).headOption match - case Some(file) => FileAnalysisStore.binary(file.toFile()).get.get.getAnalysis - case None => Analysis.empty - else Analysis.empty + val outputDirectory = Def.cacheConfiguration.outputDirectory + cacheStore.syncBlobs(ref :: Nil, outputDirectory).headOption match + case Some(file) => analysisStore(file).get.get.getAnalysis + case None => Analysis.empty } ) @@ -106,7 +97,7 @@ object RemoteCache { false, Array() ) - FileAnalysisStore.binary(file).set(AnalysisContents.create(analysis, setup)) + analysisStore(file.toPath).set(AnalysisContents.create(analysis, setup)) val vf = tempConverter.toVirtualFile(file.toPath) val refs = cacheStore.putBlobs(vf :: Nil) refs.headOption match @@ -115,6 +106,9 @@ object RemoteCache { Some(ref) case None => None + private def analysisStore(file: Path): AnalysisStore = + MixedAnalyzingCompiler.staticCachedStore(file, true) + private[sbt] def artifactToStr(art: Artifact): String = { import LibraryManagementCodec._ import sjsonnew.support.scalajson.unsafe._ diff --git a/sbt-app/src/sbt-test/tests/test-quick/build.sbt b/sbt-app/src/sbt-test/tests/test-quick/build.sbt index 9fd396d27..9153720ef 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/build.sbt +++ b/sbt-app/src/sbt-test/tests/test-quick/build.sbt @@ -1,3 +1,5 @@ +Global / cacheStores := Seq.empty + val scalatest = "org.scalatest" %% "scalatest" % "3.0.5" ThisBuild / scalaVersion := "2.12.12" diff --git a/sbt-app/src/sbt-test/tests/test-quick/pending b/sbt-app/src/sbt-test/tests/test-quick/test similarity index 98% rename from sbt-app/src/sbt-test/tests/test-quick/pending rename to sbt-app/src/sbt-test/tests/test-quick/test index b3afce6e3..c86f0276f 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/pending +++ b/sbt-app/src/sbt-test/tests/test-quick/test @@ -9,7 +9,7 @@ $ copy-file changed/A.scala src/main/scala/A.scala > compile $ sleep 2000 # Create is run. Delete is not since it doesn't have src/main dependency. -> testQuick +-> testQuick > testOnly Delete # Previous run of Create failed, re-run. > testQuick Create