mirror of
https://github.com/sbt/sbt.git
synced 2026-10-06 18:14:04 +02:00
[2.x] fix: include compileOrder and pipelining in compile cache key (#9749)
compileOrder and usePipelining were missing from CompileInputs2, so two builds differing only in those settings shared one cache entry and replayed each other's results. Adds both to the key, with a unit test on the hash and a scripted test that fails without the change.
This commit is contained in:
@@ -1005,6 +1005,8 @@ object Defaults extends BuildCommon with DefExtra:
|
||||
c.toVirtualFile(inputs.setup.cacheFile.toPath),
|
||||
extraIncOptions.value.toVector,
|
||||
scalaVersion.value,
|
||||
compileOrder.value.name,
|
||||
incOptions.value.pipelining,
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -2570,6 +2572,8 @@ object Defaults extends BuildCommon with DefExtra:
|
||||
c.toVirtualFile(inputs.setup.cacheFile.toPath),
|
||||
incrementalOptions,
|
||||
scalaVersion.value,
|
||||
compileOrder.value.name,
|
||||
incOptions.value.pipelining,
|
||||
)
|
||||
},
|
||||
bspCompileTask :=
|
||||
|
||||
@@ -14,6 +14,8 @@ case class CompileInputs2(
|
||||
cachePath: VirtualFileRef,
|
||||
incrementalOptions: Vector[(String, String)],
|
||||
scalaVersion: String,
|
||||
compileOrder: String,
|
||||
pipelining: Boolean,
|
||||
)
|
||||
|
||||
object CompileInputs2:
|
||||
@@ -23,7 +25,7 @@ object CompileInputs2:
|
||||
CompileInputs2,
|
||||
Vector[HashedVirtualFileRef] :*: Vector[HashedVirtualFileRef] :*: Vector[String] :*:
|
||||
Vector[String] :*: VirtualFileRef :*: VirtualFileRef :*: Vector[(String, String)] :*:
|
||||
String :*: LNil
|
||||
String :*: String :*: Boolean :*: LNil
|
||||
] =
|
||||
LList.iso(
|
||||
{ (v: CompileInputs2) =>
|
||||
@@ -35,12 +37,14 @@ object CompileInputs2:
|
||||
("cachePath", v.cachePath) :*:
|
||||
("incrementalOptions", v.incrementalOptions) :*:
|
||||
("scalaVersion", v.scalaVersion) :*:
|
||||
("compileOrder", v.compileOrder) :*:
|
||||
("pipelining", v.pipelining) :*:
|
||||
LNil
|
||||
},
|
||||
{
|
||||
(in: Vector[HashedVirtualFileRef] :*: Vector[HashedVirtualFileRef] :*: Vector[String] :*:
|
||||
Vector[String] :*: VirtualFileRef :*: VirtualFileRef :*: Vector[(String, String)] :*:
|
||||
String :*: LNil) =>
|
||||
String :*: String :*: Boolean :*: LNil) =>
|
||||
CompileInputs2(
|
||||
in.head,
|
||||
in.tail.head,
|
||||
@@ -50,6 +54,8 @@ object CompileInputs2:
|
||||
in.tail.tail.tail.tail.tail.head,
|
||||
in.tail.tail.tail.tail.tail.tail.head,
|
||||
in.tail.tail.tail.tail.tail.tail.tail.head,
|
||||
in.tail.tail.tail.tail.tail.tail.tail.tail.head,
|
||||
in.tail.tail.tail.tail.tail.tail.tail.tail.tail.head,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* sbt
|
||||
* Copyright 2023, Scala center
|
||||
* Copyright 2011 - 2022, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal
|
||||
|
||||
import hedgehog.*
|
||||
import hedgehog.runner.*
|
||||
import _root_.sbt.util.CacheImplicits.given
|
||||
import _root_.sbt.util.DigestHasher
|
||||
import xsbti.{ HashedVirtualFileRef, VirtualFileRef }
|
||||
|
||||
/**
|
||||
* The compile action cache is keyed on [[CompileInputs2]], so every setting that changes the
|
||||
* compile outcome has to be part of it (#9748).
|
||||
*/
|
||||
object CompileInputs2HashTest extends Properties:
|
||||
override def tests: List[Test] = List(
|
||||
example("compileOrder changes the hash", compileOrderChangesHash),
|
||||
example("pipelining changes the hash", pipeliningChangesHash),
|
||||
example("identical inputs hash the same", identicalInputsHashTheSame),
|
||||
)
|
||||
|
||||
private def base = CompileInputs2(
|
||||
classpath = Vector(HashedVirtualFileRef.of("${BASE}/lib/dep.jar", "sha256-abc", 1L)),
|
||||
sources = Vector(HashedVirtualFileRef.of("${BASE}/src/main/scala/A.scala", "sha256-def", 2L)),
|
||||
scalacOptions = Vector("-deprecation"),
|
||||
javacOptions = Vector.empty,
|
||||
outputPath = VirtualFileRef.of("${BASE}/target/classes"),
|
||||
cachePath = VirtualFileRef.of("${BASE}/target/inc_compile.zip"),
|
||||
incrementalOptions = Vector.empty,
|
||||
scalaVersion = "2.13.18",
|
||||
compileOrder = "Mixed",
|
||||
pipelining = false,
|
||||
)
|
||||
|
||||
private def compileOrderChangesHash: Result =
|
||||
val mixed = DigestHasher.hashUnsafe(base)
|
||||
val javaThenScala = DigestHasher.hashUnsafe(base.copy(compileOrder = "JavaThenScala"))
|
||||
Result.assert(mixed != javaThenScala)
|
||||
|
||||
private def pipeliningChangesHash: Result =
|
||||
val off = DigestHasher.hashUnsafe(base)
|
||||
val on = DigestHasher.hashUnsafe(base.copy(pipelining = true))
|
||||
Result.assert(off != on)
|
||||
|
||||
private def identicalInputsHashTheSame: Result =
|
||||
DigestHasher.hashUnsafe(base) ==== DigestHasher.hashUnsafe(base)
|
||||
end CompileInputs2HashTest
|
||||
@@ -0,0 +1,21 @@
|
||||
Global / localCacheDirectory := baseDirectory.value / "diskcache"
|
||||
|
||||
val checkClasses = taskKey[Unit]("asserts the Java class was compiled")
|
||||
|
||||
// A distinct project id keeps this fixture's output paths from colliding with same-named
|
||||
// sibling fixtures in scripted's shared batch directory.
|
||||
lazy val compileOrderKey = project
|
||||
.in(file("."))
|
||||
.settings(
|
||||
scalaVersion := "3.9.0",
|
||||
compileOrder := (
|
||||
if ((baseDirectory.value / "mixed.marker").exists) CompileOrder.Mixed
|
||||
else CompileOrder.JavaThenScala
|
||||
),
|
||||
)
|
||||
|
||||
checkClasses := Def.uncached {
|
||||
val dir = (compileOrderKey / Compile / classDirectory).value
|
||||
val cls = dir / "example" / "J.class"
|
||||
assert(cls.exists, s"$cls does not exist")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package example;
|
||||
|
||||
public class J {
|
||||
public static String go() {
|
||||
return new S().hello();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package example
|
||||
|
||||
class S:
|
||||
def hello: String = "hi"
|
||||
@@ -0,0 +1,11 @@
|
||||
# Regression for #9748: compileOrder has to take part in the compile cache key. Under
|
||||
# JavaThenScala javac runs before the Scala class exists and the build fails. Flipping to
|
||||
# Mixed has to recompile, not replay that failure from an entry filed under the same key.
|
||||
|
||||
-> compile
|
||||
|
||||
$ touch mixed.marker
|
||||
> reload
|
||||
|
||||
> compile
|
||||
> checkClasses
|
||||
Reference in New Issue
Block a user