mirror of
https://github.com/sbt/sbt.git
synced 2026-10-06 18:14:04 +02:00
[2.x] fix: hash the boot classpath in a deterministic order (#9809)
The launcher enumerates the boot directory, so `AppProvider.mainClasspath` and `ScalaProvider.jars` come back
in filesystem order, and sbt 2 folds that classpath into the metabuild's `CompileInputs2`. Two machines with
identical inputs therefore compute different keys: measured on one project at the same commit, same sbt and
same JDK, 439 classpath entries on both sides, the same set, 83 of them at a different index and all under
${SBT_BOOT}.
Sorting happens after conversion to the rooted virtual path, so the order is independent of the filesystem
and of where the boot directory lives. The order being replaced is a directory listing, not one anybody
chose. `Main.rawEval` builds the same list but never reaches a cache key, so it is left alone.
Generated-by: Claude Opus 5 (Claude Code)
This commit is contained in:
@@ -4702,9 +4702,11 @@ object Classpaths:
|
||||
val app = appConfiguration.value
|
||||
def isJansiOrJLine(f: File) = f.getName.contains("jline") || f.getName.contains("jansi")
|
||||
val scalaInstanceJars = app.provider.scalaProvider.jars.filterNot(isJansiOrJLine)
|
||||
// Sorted for the same reason as the metabuild classpath in `Load`.
|
||||
val sbtCp = (scalaInstanceJars ++ app.provider.mainClasspath)
|
||||
.map(_.toPath)
|
||||
.map(p => converter.toVirtualFile(p): HashedVirtualFileRef)
|
||||
.sortBy(_.id)
|
||||
.map(Attributed.blank)
|
||||
val cpConfig = classpathConfiguration.value
|
||||
val up = update.value
|
||||
|
||||
@@ -100,8 +100,9 @@ private[sbt] object Load:
|
||||
val loader = getClass.getClassLoader
|
||||
val converter = MappedFileConverter(rootPaths, true)
|
||||
val cp0 = provider.mainClasspath.toIndexedSeq ++ scalaProvider.jars.toIndexedSeq
|
||||
// The launcher's order is a directory listing, and this classpath is hashed into the compile key.
|
||||
val classpath = Attributed.blankSeq(
|
||||
cp0.map(_.toPath).map(p => converter.toVirtualFile(p): HashedVirtualFileRef)
|
||||
cp0.map(_.toPath).map(p => converter.toVirtualFile(p): HashedVirtualFileRef).sortBy(_.id)
|
||||
)
|
||||
val csrConfig = CoursierConfiguration()
|
||||
.withResolvers(Resolver.combineDefaultResolvers(Vector.empty).toVector)
|
||||
|
||||
Reference in New Issue
Block a user