mirror of
https://github.com/sbt/sbt.git
synced 2026-08-22 14:17:13 +02:00
Use fileConverter in cacheStore
Otherwise the store cannot sync files that are not in the out folder.
This commit is contained in:
@@ -88,8 +88,6 @@ import sbt.util.CacheImplicits.given
|
|||||||
import sbt.util.InterfaceUtil.{ t2, toJavaFunction => f1 }
|
import sbt.util.InterfaceUtil.{ t2, toJavaFunction => f1 }
|
||||||
import sbt.util._
|
import sbt.util._
|
||||||
import sjsonnew._
|
import sjsonnew._
|
||||||
import xsbti.compile.TastyFiles
|
|
||||||
import xsbti.{ FileConverter, Position }
|
|
||||||
|
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
import scala.collection.immutable.ListMap
|
import scala.collection.immutable.ListMap
|
||||||
@@ -108,7 +106,16 @@ import sbt.internal.inc.{
|
|||||||
ScalaInstance
|
ScalaInstance
|
||||||
}
|
}
|
||||||
import sbt.internal.io.Retry
|
import sbt.internal.io.Retry
|
||||||
import xsbti.{ CompileFailed, CrossValue, HashedVirtualFileRef, VirtualFile, VirtualFileRef }
|
import xsbti.{
|
||||||
|
AppConfiguration,
|
||||||
|
CompileFailed,
|
||||||
|
CrossValue,
|
||||||
|
FileConverter,
|
||||||
|
HashedVirtualFileRef,
|
||||||
|
Position,
|
||||||
|
VirtualFile,
|
||||||
|
VirtualFileRef
|
||||||
|
}
|
||||||
import xsbti.compile.{
|
import xsbti.compile.{
|
||||||
AnalysisContents,
|
AnalysisContents,
|
||||||
AnalysisStore,
|
AnalysisStore,
|
||||||
@@ -129,6 +136,7 @@ import xsbti.compile.{
|
|||||||
PerClasspathEntryLookup,
|
PerClasspathEntryLookup,
|
||||||
PreviousResult,
|
PreviousResult,
|
||||||
Setup,
|
Setup,
|
||||||
|
TastyFiles,
|
||||||
TransactionalManagerType
|
TransactionalManagerType
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,8 +240,28 @@ object Defaults extends BuildCommon {
|
|||||||
closeClassLoaders :== SysProp.closeClassLoaders,
|
closeClassLoaders :== SysProp.closeClassLoaders,
|
||||||
allowZombieClassLoaders :== true,
|
allowZombieClassLoaders :== true,
|
||||||
packageTimestamp :== Pkg.defaultTimestamp,
|
packageTimestamp :== Pkg.defaultTimestamp,
|
||||||
|
rootPaths := {
|
||||||
|
val app = appConfiguration.value
|
||||||
|
val coursierCache = csrCacheDirectory.value.toPath
|
||||||
|
val out = rootOutputDirectory.value
|
||||||
|
getRootPaths(out, app) + ("CSR_CACHE" -> coursierCache)
|
||||||
|
},
|
||||||
|
fileConverter := MappedFileConverter(rootPaths.value, allowMachinePath.value)
|
||||||
) ++ BuildServerProtocol.globalSettings
|
) ++ BuildServerProtocol.globalSettings
|
||||||
|
|
||||||
|
private[sbt] def getRootPaths(out: NioPath, app: AppConfiguration): ListMap[String, NioPath] =
|
||||||
|
val base = app.baseDirectory.getCanonicalFile.toPath
|
||||||
|
val boot = app.provider.scalaProvider.launcher.bootDirectory.toPath
|
||||||
|
val ih = app.provider.scalaProvider.launcher.ivyHome.toPath
|
||||||
|
val javaHome = Paths.get(sys.props("java.home"))
|
||||||
|
ListMap(
|
||||||
|
"OUT" -> out,
|
||||||
|
"BASE" -> base,
|
||||||
|
"SBT_BOOT" -> boot,
|
||||||
|
"IVY_HOME" -> ih,
|
||||||
|
"JAVA_HOME" -> javaHome
|
||||||
|
)
|
||||||
|
|
||||||
private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =
|
private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =
|
||||||
Seq(
|
Seq(
|
||||||
internalConfigurationMap :== Configurations.internalMap _,
|
internalConfigurationMap :== Configurations.internalMap _,
|
||||||
@@ -282,6 +310,10 @@ object Defaults extends BuildCommon {
|
|||||||
csrLogger := LMCoursier.coursierLoggerTask.value,
|
csrLogger := LMCoursier.coursierLoggerTask.value,
|
||||||
csrMavenProfiles :== Set.empty,
|
csrMavenProfiles :== Set.empty,
|
||||||
csrReconciliations :== LMCoursier.relaxedForAllModules,
|
csrReconciliations :== LMCoursier.relaxedForAllModules,
|
||||||
|
csrCacheDirectory := {
|
||||||
|
if (useCoursier.value) LMCoursier.defaultCacheLocation
|
||||||
|
else Classpaths.dummyCoursierDirectory(appConfiguration.value)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/** Core non-plugin settings for sbt builds. These *must* be on every build or the sbt engine will fail to run at all. */
|
/** Core non-plugin settings for sbt builds. These *must* be on every build or the sbt engine will fail to run at all. */
|
||||||
@@ -410,24 +442,6 @@ object Defaults extends BuildCommon {
|
|||||||
|
|
||||||
private[sbt] lazy val buildLevelJvmSettings: Seq[Setting[_]] = Seq(
|
private[sbt] lazy val buildLevelJvmSettings: Seq[Setting[_]] = Seq(
|
||||||
exportPipelining := usePipelining.value,
|
exportPipelining := usePipelining.value,
|
||||||
rootPaths := {
|
|
||||||
val app = appConfiguration.value
|
|
||||||
val base = app.baseDirectory.getCanonicalFile
|
|
||||||
val boot = app.provider.scalaProvider.launcher.bootDirectory
|
|
||||||
val ih = app.provider.scalaProvider.launcher.ivyHome
|
|
||||||
val coursierCache = csrCacheDirectory.value
|
|
||||||
val javaHome = Paths.get(sys.props("java.home"))
|
|
||||||
val out = rootOutputDirectory.value
|
|
||||||
ListMap(
|
|
||||||
"OUT" -> out,
|
|
||||||
"BASE" -> base.toPath,
|
|
||||||
"SBT_BOOT" -> boot.toPath,
|
|
||||||
"CSR_CACHE" -> coursierCache.toPath,
|
|
||||||
"IVY_HOME" -> ih.toPath,
|
|
||||||
"JAVA_HOME" -> javaHome,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
fileConverter := MappedFileConverter(rootPaths.value, allowMachinePath.value),
|
|
||||||
sourcePositionMappers := Nil, // Never set a default sourcePositionMapper, see #6352! Whatever you are trying to solve, do it in the foldMappers method.
|
sourcePositionMappers := 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.
|
// The virtual file value cache needs to be global or sbt will run out of direct byte buffer memory.
|
||||||
classpathDefinesClassCache := VirtualFileValueCache.definesClassCache(fileConverter.value),
|
classpathDefinesClassCache := VirtualFileValueCache.definesClassCache(fileConverter.value),
|
||||||
@@ -526,14 +540,6 @@ object Defaults extends BuildCommon {
|
|||||||
.getOrElse(pos)
|
.getOrElse(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// csrCacheDirectory is scoped to ThisBuild to allow customization.
|
|
||||||
private[sbt] lazy val buildLevelIvySettings: Seq[Setting[_]] = Seq(
|
|
||||||
csrCacheDirectory := {
|
|
||||||
if (useCoursier.value) LMCoursier.defaultCacheLocation
|
|
||||||
else Classpaths.dummyCoursierDirectory(appConfiguration.value)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
def defaultTestTasks(key: Scoped): Seq[Setting[_]] =
|
def defaultTestTasks(key: Scoped): Seq[Setting[_]] =
|
||||||
inTask(key)(
|
inTask(key)(
|
||||||
Seq(
|
Seq(
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import sbt.ProjectExtra.*
|
|||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
import sbt.coursierint.LMCoursier
|
import sbt.coursierint.LMCoursier
|
||||||
import sbt.internal.inc.{ HashUtil, JarUtils }
|
import sbt.internal.inc.{ MappedFileConverter, HashUtil, JarUtils }
|
||||||
import sbt.internal.librarymanagement._
|
import sbt.internal.librarymanagement._
|
||||||
import sbt.internal.remotecache._
|
import sbt.internal.remotecache._
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
@@ -36,7 +36,7 @@ import sbt.std.TaskExtra._
|
|||||||
import sbt.util.InterfaceUtil.toOption
|
import sbt.util.InterfaceUtil.toOption
|
||||||
import sbt.util.{ ActionCacheStore, AggregateActionCacheStore, DiskActionCacheStore, Logger }
|
import sbt.util.{ ActionCacheStore, AggregateActionCacheStore, DiskActionCacheStore, Logger }
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
import xsbti.{ HashedVirtualFileRef, VirtualFileRef }
|
import xsbti.{ FileConverter, HashedVirtualFileRef, VirtualFileRef }
|
||||||
import xsbti.compile.CompileAnalysis
|
import xsbti.compile.CompileAnalysis
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
@@ -46,8 +46,6 @@ object RemoteCache {
|
|||||||
final val cachedTestClassifier = "cached-test"
|
final val cachedTestClassifier = "cached-test"
|
||||||
final val commitLength = 10
|
final val commitLength = 10
|
||||||
|
|
||||||
def cacheStore: ActionCacheStore = Def.cacheStore
|
|
||||||
|
|
||||||
// TODO: cap with caffeine
|
// TODO: cap with caffeine
|
||||||
private[sbt] val analysisStore: mutable.Map[HashedVirtualFileRef, CompileAnalysis] =
|
private[sbt] val analysisStore: mutable.Map[HashedVirtualFileRef, CompileAnalysis] =
|
||||||
mutable.Map.empty
|
mutable.Map.empty
|
||||||
@@ -56,14 +54,22 @@ object RemoteCache {
|
|||||||
// currently this is called twice so metabuild can call compile with a minimal setting
|
// currently this is called twice so metabuild can call compile with a minimal setting
|
||||||
private[sbt] def initializeRemoteCache(s: State): Unit =
|
private[sbt] def initializeRemoteCache(s: State): Unit =
|
||||||
val outDir =
|
val outDir =
|
||||||
s.get(BasicKeys.rootOutputDirectory).getOrElse((s.baseDir / "target" / "out").toPath())
|
s.get(BasicKeys.rootOutputDirectory).getOrElse((s.baseDir / "target" / "out").toPath)
|
||||||
Def._outputDirectory = Some(outDir)
|
Def._outputDirectory = Some(outDir)
|
||||||
val caches = s.get(BasicKeys.cacheStores)
|
def defaultCache =
|
||||||
caches match
|
val fileConverter = s
|
||||||
case Some(xs) if xs.nonEmpty => Def._cacheStore = AggregateActionCacheStore(xs)
|
.get(Keys.fileConverter.key)
|
||||||
case _ =>
|
.getOrElse {
|
||||||
val tempDiskCache = (s.baseDir / "target" / "bootcache").toPath()
|
MappedFileConverter(
|
||||||
Def._cacheStore = DiskActionCacheStore(tempDiskCache)
|
Defaults.getRootPaths(outDir, s.configuration),
|
||||||
|
allowMachinePath = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DiskActionCacheStore((s.baseDir / "target" / "bootcache").toPath, fileConverter)
|
||||||
|
Def._cacheStore = s
|
||||||
|
.get(BasicKeys.cacheStores)
|
||||||
|
.collect { case xs if xs.nonEmpty => AggregateActionCacheStore(xs) }
|
||||||
|
.getOrElse(defaultCache)
|
||||||
|
|
||||||
private[sbt] def artifactToStr(art: Artifact): String = {
|
private[sbt] def artifactToStr(art: Artifact): String = {
|
||||||
import LibraryManagementCodec._
|
import LibraryManagementCodec._
|
||||||
@@ -104,7 +110,7 @@ object RemoteCache {
|
|||||||
},
|
},
|
||||||
cacheStores := {
|
cacheStores := {
|
||||||
List(
|
List(
|
||||||
DiskActionCacheStore(localCacheDirectory.value.toPath())
|
DiskActionCacheStore(localCacheDirectory.value.toPath(), fileConverter.value)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ object IvyPlugin extends AutoPlugin {
|
|||||||
|
|
||||||
override lazy val globalSettings: Seq[Setting[_]] =
|
override lazy val globalSettings: Seq[Setting[_]] =
|
||||||
Defaults.globalIvyCore
|
Defaults.globalIvyCore
|
||||||
override lazy val buildSettings: Seq[Setting[_]] =
|
|
||||||
Defaults.buildLevelIvySettings
|
|
||||||
override lazy val projectSettings: Seq[Setting[_]] =
|
override lazy val projectSettings: Seq[Setting[_]] =
|
||||||
Classpaths.ivyPublishSettings ++ Classpaths.ivyBaseSettings
|
Classpaths.ivyPublishSettings ++ Classpaths.ivyBaseSettings
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import scala.reflect.ClassTag
|
|||||||
import scala.util.control.NonFatal
|
import scala.util.control.NonFatal
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
import sbt.io.syntax.*
|
import sbt.io.syntax.*
|
||||||
import xsbti.{ HashedVirtualFileRef, PathBasedFile, VirtualFile }
|
import xsbti.{ FileConverter, HashedVirtualFileRef, PathBasedFile, VirtualFile }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstraction of a remote or local cache store.
|
* An abstraction of a remote or local cache store.
|
||||||
@@ -129,7 +129,7 @@ class InMemoryActionCacheStore extends ActionCacheStore:
|
|||||||
underlying.toString()
|
underlying.toString()
|
||||||
end InMemoryActionCacheStore
|
end InMemoryActionCacheStore
|
||||||
|
|
||||||
class DiskActionCacheStore(base: Path) extends ActionCacheStore:
|
class DiskActionCacheStore(base: Path, fileConverter: FileConverter) extends ActionCacheStore:
|
||||||
lazy val casBase: Path = {
|
lazy val casBase: Path = {
|
||||||
val dir = base.resolve("cas")
|
val dir = base.resolve("cas")
|
||||||
IO.createDirectory(dir.toFile)
|
IO.createDirectory(dir.toFile)
|
||||||
@@ -181,13 +181,10 @@ class DiskActionCacheStore(base: Path) extends ActionCacheStore:
|
|||||||
else None
|
else None
|
||||||
|
|
||||||
override def syncBlobs(refs: Seq[HashedVirtualFileRef], outputDirectory: Path): Seq[Path] =
|
override def syncBlobs(refs: Seq[HashedVirtualFileRef], outputDirectory: Path): Seq[Path] =
|
||||||
refs.flatMap: r =>
|
refs.flatMap: ref =>
|
||||||
val casFile = casBase.toFile / Digest(r.contentHashStr).toString
|
val casFile = casBase.toFile / Digest(ref.contentHashStr).toString
|
||||||
if casFile.exists then
|
if casFile.exists then
|
||||||
val shortPath =
|
val outPath = fileConverter.toPath(ref)
|
||||||
if r.id.startsWith("${OUT}/") then r.id.drop(7)
|
|
||||||
else r.id
|
|
||||||
val outPath = outputDirectory.resolve(shortPath)
|
|
||||||
Files.createDirectories(outPath.getParent())
|
Files.createDirectories(outPath.getParent())
|
||||||
if outPath.toFile().exists() then IO.delete(outPath.toFile())
|
if outPath.toFile().exists() then IO.delete(outPath.toFile())
|
||||||
Some(Files.createSymbolicLink(outPath, casFile.toPath))
|
Some(Files.createSymbolicLink(outPath, casFile.toPath))
|
||||||
|
|||||||
@@ -4,7 +4,13 @@ import sbt.internal.util.StringVirtualFile1
|
|||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
import sbt.io.syntax.*
|
import sbt.io.syntax.*
|
||||||
import verify.BasicTestSuite
|
import verify.BasicTestSuite
|
||||||
|
import xsbti.FileConverter
|
||||||
import xsbti.VirtualFile
|
import xsbti.VirtualFile
|
||||||
|
import xsbti.VirtualFileRef
|
||||||
|
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
object ActionCacheTest extends BasicTestSuite:
|
object ActionCacheTest extends BasicTestSuite:
|
||||||
val tags = CacheLevelTag.all.toList
|
val tags = CacheLevelTag.all.toList
|
||||||
@@ -13,10 +19,10 @@ object ActionCacheTest extends BasicTestSuite:
|
|||||||
withDiskCache(testHoldBlob)
|
withDiskCache(testHoldBlob)
|
||||||
|
|
||||||
def testHoldBlob(cache: ActionCacheStore): Unit =
|
def testHoldBlob(cache: ActionCacheStore): Unit =
|
||||||
val in = StringVirtualFile1("a.txt", "foo")
|
|
||||||
val hashRefs = cache.putBlobs(in :: Nil)
|
|
||||||
assert(hashRefs.size == 1)
|
|
||||||
IO.withTemporaryDirectory: tempDir =>
|
IO.withTemporaryDirectory: tempDir =>
|
||||||
|
val in = StringVirtualFile1(s"$tempDir/a.txt", "foo")
|
||||||
|
val hashRefs = cache.putBlobs(in :: Nil)
|
||||||
|
assert(hashRefs.size == 1)
|
||||||
val actual = cache.syncBlobs(hashRefs, tempDir.toPath()).head
|
val actual = cache.syncBlobs(hashRefs, tempDir.toPath()).head
|
||||||
assert(actual.getFileName().toString() == "a.txt")
|
assert(actual.getFileName().toString() == "a.txt")
|
||||||
|
|
||||||
@@ -48,14 +54,14 @@ object ActionCacheTest extends BasicTestSuite:
|
|||||||
withDiskCache(testActionCacheWithBlob)
|
withDiskCache(testActionCacheWithBlob)
|
||||||
|
|
||||||
def testActionCacheWithBlob(cache: ActionCacheStore): Unit =
|
def testActionCacheWithBlob(cache: ActionCacheStore): Unit =
|
||||||
import sjsonnew.BasicJsonProtocol.*
|
|
||||||
var called = 0
|
|
||||||
val action: ((Int, Int)) => (Int, Seq[VirtualFile]) = { case (a, b) =>
|
|
||||||
called += 1
|
|
||||||
val out = StringVirtualFile1("a.txt", (a + b).toString)
|
|
||||||
(a + b, Seq(out))
|
|
||||||
}
|
|
||||||
IO.withTemporaryDirectory: (tempDir) =>
|
IO.withTemporaryDirectory: (tempDir) =>
|
||||||
|
import sjsonnew.BasicJsonProtocol.*
|
||||||
|
var called = 0
|
||||||
|
val action: ((Int, Int)) => (Int, Seq[VirtualFile]) = { case (a, b) =>
|
||||||
|
called += 1
|
||||||
|
val out = StringVirtualFile1(s"$tempDir/a.txt", (a + b).toString)
|
||||||
|
(a + b, Seq(out))
|
||||||
|
}
|
||||||
val config = BuildWideCacheConfiguration(cache, tempDir.toPath())
|
val config = BuildWideCacheConfiguration(cache, tempDir.toPath())
|
||||||
val v1 =
|
val v1 =
|
||||||
ActionCache.cache[(Int, Int), Int]((1, 1), Digest.zero, Digest.zero, tags)(action)(config)
|
ActionCache.cache[(Int, Int), Int]((1, 1), Digest.zero, Digest.zero, tags)(action)(config)
|
||||||
@@ -81,9 +87,15 @@ object ActionCacheTest extends BasicTestSuite:
|
|||||||
IO.withTemporaryDirectory(
|
IO.withTemporaryDirectory(
|
||||||
{ tempDir0 =>
|
{ tempDir0 =>
|
||||||
val tempDir = tempDir0.toPath
|
val tempDir = tempDir0.toPath
|
||||||
val cache = DiskActionCacheStore(tempDir)
|
val cache = DiskActionCacheStore(tempDir, fileConverter)
|
||||||
f(cache)
|
f(cache)
|
||||||
},
|
},
|
||||||
keepDirectory = false
|
keepDirectory = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def fileConverter = new FileConverter:
|
||||||
|
override def toPath(ref: VirtualFileRef): Path = Paths.get(ref.id)
|
||||||
|
override def toVirtualFile(path: Path): VirtualFile =
|
||||||
|
val content = if Files.isRegularFile(path) then new String(Files.readAllBytes(path)) else ""
|
||||||
|
StringVirtualFile1(path.toString, content)
|
||||||
end ActionCacheTest
|
end ActionCacheTest
|
||||||
|
|||||||
Reference in New Issue
Block a user