mirror of https://github.com/sbt/sbt.git
* always create symlinks to the cache in the target locations, even if the digest matches #8445 * create a test (currently failing even on #develop) that fails because if `zipPath` in `sbt.util.ActionCache.packageDirectory` is a symlink to the CAS, in later calls, this path in the CAS gets overridden by the new sources. - in this test, after "run 1" in line 15, the produced file "target/out/jvm/scala-3.7.4/a/classes.sbtdir.zip" is a symlink to the CAS, let's call it SH1. - when "run 3" is executed, `IO.zip` saves the new value to `zipPath`, which is "target/out/jvm/scala-3.7.4/a/classes.sbtdir.zip -> SH1", so SH1 gets overridden. - when the last "run 1" is executed, the cache retrieves SH1, but it contains the data from "run 3" (the test fails with "actual A.x is 3"). * when packaging a directory into a zip, use a temp directory to avoid overwriting the cache #8461
This commit is contained in:
parent
81b6408f49
commit
106b8b9978
|
|
@ -0,0 +1,4 @@
|
|||
lazy val root = (project in file(".")).
|
||||
dependsOn(a)
|
||||
|
||||
lazy val a = (project in file("a"))
|
||||
|
|
@ -0,0 +1 @@
|
|||
object A { val x = 1 }
|
||||
|
|
@ -0,0 +1 @@
|
|||
object A { val x = 2 }
|
||||
|
|
@ -0,0 +1 @@
|
|||
object A { def x = 3 }
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object B {
|
||||
def main(args: Array[String]) = assert(args(0).toInt == A.x, s"actual A.x is ${A.x}")
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
exportJars := true
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
$ copy-file changes/B.scala B.scala
|
||||
|
||||
$ copy-file changes/A1.scala a/A.scala
|
||||
$ sleep 1000
|
||||
|
||||
> run 1
|
||||
$ copy-file changes/A2.scala a/A.scala
|
||||
$ sleep 1000
|
||||
|
||||
# done this way because last modified times often have ~1s resolution
|
||||
> run 2
|
||||
$ copy-file changes/A1.scala a/A.scala
|
||||
$ sleep 1000
|
||||
|
||||
> run 1
|
||||
|
||||
$ copy-file changes/A3.scala a/A.scala
|
||||
$ sleep 1000
|
||||
|
||||
> run 3
|
||||
$ copy-file changes/A1.scala a/A.scala
|
||||
$ sleep 1000
|
||||
|
||||
> run 1
|
||||
|
|
@ -10,7 +10,7 @@ package sbt.util
|
|||
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.{ Path, Paths }
|
||||
import java.nio.file.{ Files, Path, Paths, StandardCopyOption }
|
||||
import sbt.internal.util.{ ActionCacheEvent, CacheEventLog, StringVirtualFile1 }
|
||||
import sbt.io.syntax.*
|
||||
import sbt.io.IO
|
||||
|
|
@ -268,7 +268,15 @@ object ActionCache:
|
|||
case p if p == dirPath => Nil
|
||||
case p if p == mPath => (mPath.toFile() -> manifestFileName) :: Nil
|
||||
case f => (f.toFile() -> outputDirectory.relativize(f).toString) :: Nil
|
||||
IO.zip((allPaths ++ Seq(mPath)).flatMap(rebase), zipPath.toFile(), Some(default2010Timestamp))
|
||||
// Create the zip in a temp directory to avoid overwriting the cache if `zipPath` is a symlink to the CAS
|
||||
val tempZipPath = (tempDir / (dirPath.getFileName.toString + dirZipExt)).toPath()
|
||||
IO.zip(
|
||||
(allPaths ++ Seq(mPath)).flatMap(rebase),
|
||||
tempZipPath.toFile(),
|
||||
Some(default2010Timestamp)
|
||||
)
|
||||
Files.copy(tempZipPath, zipPath, StandardCopyOption.REPLACE_EXISTING)
|
||||
|
||||
conv.toVirtualFile(zipPath)
|
||||
|
||||
inline def actionResult[A1](inline value: A1): InternalActionResult[A1] =
|
||||
|
|
|
|||
|
|
@ -318,7 +318,9 @@ class DiskActionCacheStore(base: Path, converter: FileConverter) extends Abstrac
|
|||
writeFileAndNotify(p)
|
||||
case p =>
|
||||
try
|
||||
if Digest.sameDigest(p, d) then p
|
||||
// `!symlinkSupported` prevents unnecessary deletion of files and then copying them again
|
||||
// in #writeFileAndNotify on machines that don't support symlinks.
|
||||
if Digest.sameDigest(p, d) && (!symlinkSupported.get() || Files.isSymbolicLink(p)) then p
|
||||
else
|
||||
// println(s"- syncFile: $p has different digest")
|
||||
IO.delete(p.toFile())
|
||||
|
|
|
|||
Loading…
Reference in New Issue