Commit Graph
18191 Commits
Author SHA1 Message Date
Mai Huy HoàngandClaude Opus 5 b4a4b8d827 [2.x] perf: Intern the values an UpdateReport is built of
The projects of a build mostly depend on the same libraries, and each project's
report materializes its own copies of every coordinate it names, so one value
exists once per project that mentions it: on a 302-module monorepo the cached
reports hold 949,492 ModuleReports for 2,036 distinct values.

UpdateReportInterner adds weak pools for ConfigRef, InclExclRule, File,
Artifact, ModuleID, Caller and ModuleReport itself. Pooling the report is worth
more than pooling its parts alone, because sharing it also shares its licenses
vector, extraAttributes map, homepage string and artifacts vector. Reports
carrying a publicationDate are canonicalized but never pooled, since that
java.util.Calendar is mutable; everything else reachable from a ModuleReport is
immutable, so sharing is semantically invisible.

The pools are weak, so a value lives exactly as long as some report references
it and nothing accumulates across a reload.

Two sites cover a freshly resolved report. SbtUpdateReport interns each report
as it builds it rather than sweeping the finished one, so only the module under
construction is ever un-interned. That alone would not survive, though:
coursier memoizes moduleReport on a key that includes the dependees, so each
project builds its own instance of a shared coordinate, and transformDetails
then rebuilt every report to drop the callers -- discarding the sharing and
leaving a copy per module per configuration. Dropping the callers is what makes
those reports value-equal in the first place, so transformDetails now re-interns
what it rebuilds, and only rebuilds when there is something to drop. A scripted
test pins it: two projects resolving one coordinate must end up holding one
ModuleReport instance, on the fresh path and from the cache.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-29 09:43:09 +07:00
Mai Huy HoàngandClaude Opus 5 8cea7c1cbc [2.x] Add a dependency-free weak interner to lm-core
WeakInterner is a ConcurrentHashMap keyed by a WeakReference subclass that
hashes and compares by its referent, with dead entries expunged on each
operation. Ported from zinc's sbt.internal.inc.WeakInterner, so lm-core gains
no interning dependency.

internWith derives the instance to pool only when the value is not pooled yet.
Equality is structural, so a value finds its pooled twin whatever the identity
of the values inside it, which lets a caller whose canonical form is itself
expensive to build skip building it on a hit. intern is internWith with
identity.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-29 09:35:47 +07:00
Mai Huy HoàngandClaude Opus 5 6698589c59 [2.x] perf: Stop content-hashing artifacts when writing update caches (#9524)
sjsonnew serializes a File as a (uri, Long) pair whose Long is a SHA-256 of the
file's contents, and the read direction discards it. A report names each
artifact once per configuration it resolved in, and the projects of a build
largely share their dependencies, so writing the caches re-reads the whole
downloaded classpath many times over: on a 302-module monorepo, 755 GB of jars
and about 11 minutes of CPU for bytes no reader looks at.

Staleness comes from LibraryManagement.fileUptodate instead, which checks
File.exists and the modification time against UpdateReport.stamps.

UpdateReportPersistence.CacheCodec extends the LibraryManagementCodec trait and overrides
the inherited fileStringLongIso so the pair carries 0. That member is virtual,
so the override also reaches the Vector[(Artifact, File)] nested inside the
generated ModuleReportFormat, which a locally-scoped JsonFormat[File] could
not. The inputs store keeps the stock codec, so Tracked.inputChanged still
hashes contents for invalidation.

The JSON shape is unchanged, so caches stay readable in both directions.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-07-28 09:34:37 -04:00
Fabrizio Colonna d95b50d8e0 [2.x] fix: sbt.bat fails to start client/server mode on Windows (#9520)
sbt.bat fails to start in client/server mode on Windows, falling back to running the full JVM in the foreground.

sbtn uses CreateProcess to spawn the server process. The original %%20 path encoding doesn't work in batch delayed expansion context, and the default install path C:\Program Files (x86) contains spaces that CreateProcess splits at.
2026-07-27 19:58:39 -04:00
eugene yokota 67924298f2 [2.x] fix: Fixes sbtn stdin race condition (#9521)
**Problem**
There's a race condition between per-byte readSystemIn notification
and one-byte-read thread lifecycle.

Note: One-byte-read thread was introduced as a solution to the problem
that switching the terminal between raw and canonical mode cannot happen
if it's blocked by read.

**Solution**
This eliminates the thread lifecycle issue by keeping the thread alive
throughout the lifecycle of sbtn itself.
read is still called on demand by the server readSystemIn notification.
2026-07-27 19:52:30 -04:00
eugene yokota ab340b02bd [2.x] fix: Fixes a/build.sbt leakage (#9519)
**Problem**
subproject build.sbt like a/build.sbt leaks to siblings.

**Solution**
Don't forward freshly computed common settings unless
the build.sbt is at root.
2026-07-27 15:43:20 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 1e2f70601b build(deps): bump actions/cache from 4 to 6 (#9513)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-27 01:46:50 -04:00
eugene yokota b130cbcd05 [2.x] Use sbt 2.0.4 (#9512) 2026-07-27 00:02:28 -04:00
kenji yoshida 551857bbd4 [2.x] ci: Update mima setting (#9511) 2026-07-26 23:17:06 -04:00
Jozef Koval 8e3c25c1f1 [2.x] fix: Make forked run inherit sbt's working directory (#9442)
forked run used the project's baseDirectory as the working directory, while non-forked execution inherits sbt's own working directory — so toggling fork silently changed how relative paths resolved.

forked run (and forked console) now inherit sbt's working directory, consistent with non-forked execution and `sbtn` expectations.
2026-07-26 14:48:37 -04:00
eugene yokota 017ee92527 [2.x] Zinc 2.0.4 (#9508) 2026-07-26 14:45:03 -04:00
eugene yokota f6cb28bd22 [2.x] fix: Fixes scalaCompilerBridgeBin (#9506)
**Problem/Solution**
Fixes scalaCompilerBridgeBin leaking project names
across different builds.
2026-07-26 14:04:04 -04:00
eugene yokota f59c12559f [2.x] ci: Fix publishLocalBin (#9505)
**Problem/Solution**
dummyDoc was not cached properly.
2026-07-26 02:08:54 -04:00
BrianHotoppandClaude Opus 4.8 c78d6af748 [2.x] fix: Complete server teardown before logging so reboot works from sbtn (#9497)
Running reboot in the sbt shell dropped to the OS shell instead of rebooting.
The break was in teardown: Server.shutdown opened with
log.info, and during a client-initiated reboot the terminal in scope is that
client's already-closed virtual terminal, so the log write throws
ClosedChannelException through the terminal proxy. That aborted teardown
before the portfile was deleted and the server socket closed, and the
exception was swallowed by the shutdown hook (whose own error print goes to
the same dead terminal).

Server.shutdown now completes its state cleanup (portfile, tokenfile, running
flag, server socket) before logging, and CommandExchange.shutdown wraps each
channel shutdown and the server shutdown individually so one failing step
cannot skip the rest.

Fixes #9095

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-26 01:06:36 -04:00
eugene yokota 9f0a459f81 Merge pull request #9502 from eed3si9n/wip/grpc
[2.x] fix: Intern GrpcActionCacheStore
2026-07-26 01:01:27 -04:00
eugene yokota b81265bdb5 [2.x] sbtn 2.0.0-a0c4773a (#9503) 2026-07-26 00:57:19 -04:00
Eugene Yokota b98c443b5c Add remote-cache test 2026-07-25 23:27:49 -04:00
Eugene Yokota 65e8f34696 [2.x] fix: Intern GrpcActionCacheStore
**Problem**
GrpcActionCacheStore gets recreated per reload.

**Solution**
This interns GrpcActionCacheStore based on the parameters.
2026-07-25 22:38:32 -04:00
eugene yokota a0c4773a73 [2.x] fix: Skip checksum generation for asc file, take 2 (#9499)
**Problem**
Checksums are still generated for asc file.
1. localStaging is a file repo, which was not handled
2. It was checking Artifact name, not the file name

**Solution**
This fixes both.
2026-07-24 16:42:04 -04:00
eugene yokota 0a0d6f67df [2.x] Zinc 2.0.3 (#9498) 2026-07-24 15:53:41 -04:00
BrianHotoppandClaude Opus 4.8 5a8cc7c9c2 [2.x] fix: Keep file I/O out of cache-write serialization (#9496)
putBlobsIfNeeded reads each blob's hash and size once, up front, and
returns only plain HashedVirtualFileRef values, so serializing an ActionResult
(disk, in-memory, or remote store) performs no file I/O and nothing re-stats a
blob after its CAS entry is written: a file vanishing once stored no longer
prevents the write, and I/O errors on an output file surface upfront at blob
storage time rather than mid-serialization.

Fixes #9349

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-24 13:51:33 -04:00
31f232c84a [2.x] fix: Register every Def.declareOutput execution, not one per call site (#9492)
The cached-task macro allocated one mutable slot per syntactic
Def.declareOutput / Def.declareOutputDirectory call site and snapshotted the
slots into the task's outputs after the body ran. A call inside a loop or .map
over a runtime-determined list is a single syntactic site executed many times,
so each iteration overwrote the same slot and only the last file was cached and
restored on a cache hit. There was also no way for a conditional call site that
did not execute to stay out of the outputs: its slot remained null.

Declared outputs now accumulate in a per-task ListBuffer: the macro emits one
buffer at the top of the cached body and rewrites each call site to
ActionCache.registerOutput(vf, buffer), which appends and returns the value.
Every execution registers, an unexecuted site contributes nothing, and the
static multi-site shape is unchanged.

Refs #9462 (the declareOutput-in-a-loop half)

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: eugene yokota <[email protected]>
2026-07-24 02:55:33 -04:00
eugene yokota 2e303787a5 [2.x] Allow opt-out of transient warning (#9437)
**Problem**
We want to opt out of the transient key warning.

**Solution**
This implements an optout via nowarn annotation.
2026-07-24 01:42:06 -04:00
eugene yokota 3520576a54 [2.x] clean task cleans sona-staging (#9479)
**Problem/Solution**
1. clean task cleans sona-staging directory.
2. cleanFull calls clean task.
2026-07-23 22:30:16 -04:00
eugene yokota fc3666586a [2.x] fix: Fixes common settings with extraProjects (#9495)
**Problem**
The presence of extraProjects broke common settings.

**Solution**
This fixes it by passing finalRoot.commonSettings.
2026-07-23 20:16:54 -04:00
kenji yoshida 110a140295 [2.x] ci: Fix warnings in build.sbt (#9494) 2026-07-23 19:09:40 -04:00
75263ec61b [2.x] fix: Re-extract a declared output directory on cache hit when it is missing (#9473)
A directory declared via Def.declareOutputDirectory is packaged as a sibling
<dir>.sbtdir.zip, so deleting the directory leaves the zip behind. On a cache
hit, syncFile's up-to-date short-circuit saw the zip in sync (same digest,
already a CAS symlink) and returned without the unpack side effect, which only
ran from the file-write path: the directory was never restored. For sbt's own
compile, whose classes directory is declared this way, rm -rf of the classes
directory with a warm cache meant run failed with ClassNotFoundException and no
recompile; only deleting the zip as well (or the whole cache) recovered.

The up-to-date branch now re-extracts when the extracted directory itself is
missing: a single stat on the warm path, per review preference over a
manifest-based per-file check. Partial deletions inside a still-existing
directory are not repaired, consistent with treating target/ contents as
sbt-managed.

Refs #9462 (the directory-restoration half; the declareOutput-in-a-loop half is
a separate macro-layer issue)

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: eugene yokota <[email protected]>
2026-07-23 18:06:17 -04:00
Kevin Lee 97a1dc360b [2.x] fix: Fixes three test-classloader / jar-handle leaks in the sbt server JVM (#9485)
Three independent, pre-existing retention bugs kept the classloader of a
finished in-process test run -- and the open jar handles it holds -- alive
for the rest of the server session.

- JUnitXmlTestsListener: testSuite is an InheritableThreadLocal, so
  threads spawned during a run (e.g. async-framework pool workers) inherit
  a copy of the suite reference that remove() cannot reach.

- TestRecap.collect: the recap is stashed on State.attributes and outlives
  the command, so it must not retain live throwables.

- ClassLoaderCache: loaders evicted from delegate by clearExpiredLoaders
  are unreachable from the map and never enqueued on the ReferenceQueue, so
  neither clear()/close() nor the cleanup thread could ever close them.

SuiteResult now documents the retention hazard on throwables. Adds
deterministic, cross-platform tests for all three severed chains.
2026-07-23 18:05:37 -04:00
kenji yoshida 4721f7f496 [2.x] ci: Update project/plugins.sbt (#9491) 2026-07-23 12:48:00 -04:00
eugene yokota d4e8fb583c [2.x] Zinc 2.0.2 (#9489) 2026-07-23 02:47:12 -04:00
eugene yokota 3f073b0059 [2.x] Use JDK's Unix domain socket for bootserver (#9427)
Use JDK's Unix domain socket for bootserver.
2026-07-22 23:57:13 -04:00
Stas Shevchenkoandsshevchenko 4b3fc911a7 [2.x] fix: Fixes partial cache restoration (#9488)
A genuinely broken restore now degrades to the onsite task instead of a
silent cache hit with incomplete outputs. Related to #9349.

Co-authored-by: sshevchenko <[email protected]>
2026-07-22 19:28:59 -04:00
eugene yokota c352da8cf9 [2.x] ci: Use --server (#9483) 2026-07-20 16:34:10 -04:00
kenji yoshida e1f118743c [2.x] ci: Build sbt/sbt using sbt 2 (#9244) 2026-07-20 12:38:53 -04:00
kenji yoshida 868f59c33c [2.x] ci: Remove unused code in launcher-package/build.sbt (#9480) 2026-07-20 11:56:38 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 5642771a2c build(deps): bump actions/setup-python from 6 to 7 (#9476)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 01:20:11 -04:00
kenji yoshida b3b1a3477e [2.x] refactor: Use java.util.Arrays.copyOf in JsonRpcReader (#9213)
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html#copyOf(byte%5B%5D,int)
2026-07-18 15:19:37 -04:00
BrianHotoppandClaude Opus 4.8 b411ade704 [2.x] fix: Don't cache environmental (position-less) compile failures (#9464)
Failure caching assumes a CompileFailed is a function of
the sources, which is true for source errors. But zinc also surfaces I/O write
failures ("error writing X.class") as compiler problems, so an environmental
failure (a concurrent target/ deletion, a permission blip) was cached under the
same mechanism and replayed from the global action cache on every later build,
even after the cause was gone. When the poisoned task is the metabuild compile
this is self-sustaining and unrecoverable from inside sbt: project loading
fails, so no task -- including clean -- can run, and only deleting the global
cache by hand recovers. The replayed diagnostics also name files/permissions
that no longer exist.

Refs #9455

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-18 09:49:05 -04:00
eugene yokota 204468b84c [2.x] fix: Fixes stale resources in test (#9469)
**Problem**
sbt 2.x currently constructs the test classloader using symlinks
to the JARs in CAS (content-addressable storage).
This causes issues because JVM apparently caches opened JAR files by path,
and since the symlink itself doesn't change it could end up
serving stale resource files.

**Solution**
We can workaround this issue by resolving the symlinks to the real path.
2026-07-18 09:24:09 -04:00
eugene yokota b76ac09d44 [2.x] Bump version number (#9470) 2026-07-17 18:53:28 -04:00
BrianHotoppandClaude Opus 4.8 df6c6c454e [2.x] fix: Sequence server start before publish in ivyless HTTP scripted tests (#9463)
The ivyless-publish-http and ivyless-publish-http-plugin scripted tests
defined publishToHttp as three unordered `.value` dependencies
(startPublishServer, publish, stopPublishServer). sbt evaluates task
dependencies before the task body in an unspecified order, so publish
could run before the HTTP server was listening and fail intermittently
with "Connection refused". It is reproducible under CPU contention (a
2-vCPU runner), which is why it began flaking on the JDK-25 shard and
turned develop red.

Use Def.sequential to guarantee start -> publish -> stop ordering, the
way the sibling ivyless-publish-maven-http test already sequences via
separate scripted commands.

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-16 12:44:34 -04:00
Anatolii Kmetiuk 271cde7025 [2.x] restore JVM option capability in the launcher config (#9452)
Restores override-build-repos config option responsible for passing the JVM flag to the launcher.
2026-07-16 02:39:59 -04:00
eugene yokota e68edc51a3 [2.x] sjson-new 0.15.1 (#9458) 2026-07-16 01:02:56 -04:00
eugene yokota 427b444ba5 [2.x] Ivy 2.3.0-sbt-f686954b0021a5c3245766ced0cdaeca8ba2fd7a (#9457) 2026-07-16 01:02:39 -04:00
BrianHotoppandClaude Opus 4.8 3de18d446f [2.x] fix: Propagate -java-home to a server the thin client starts (#9448)
The thin client (sbtn) parsed the launcher value flags (-java-home, -mem,
-jvm-debug, -sbt-dir, ...) but then dropped them. The space form was consumed
and discarded; the flag=value form fell through to the residual arguments and
was forwarded to the server verbatim, where --java-home=/path was rejected as a
command (`Not a valid command: --`).

When the client had to start a server (none running, no --server), the consumed
-java-home never reached the forked sbt launcher, so the server came up under
the default JVM and, in CI where the intended JDK is only reachable via
-java-home, failed to connect.

parseArgs now captures the consumed launcher value flags (both `flag value` and
`flag=value`) into Arguments.launcherValueArgs, and the cold-start fork re-passes
them to the sbt launcher so the server runs under the requested JVM. The client
tokenizes arguments by splitting on whitespace, which would otherwise fragment a
value that contains spaces (a Windows path like C:\Program Files\Java); parseArgs
tracks those split boundaries and rejoins a value flag's value. An empty flag=
value and a dangling flag with no value are consumed but not propagated, since
the launcher's require_arg would otherwise fail the fork.

The fork command construction is extracted into a pure, package-visible
serverCommand so a test can assert the propagated flag reaches the started
server. The sbt-launch-jar path is unchanged: it invokes java directly, with no
launcher to interpret the flag.

Fixes #9418

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-16 10:14:20 +09:00
kenji yoshida 5ff0c638d4 [2.x] Avoid deprecated url method in test (#9453) 2026-07-15 10:56:04 -04:00
Anatolii Kmetiuk 972d574750 [2.x] fix dependency parsing for bsp (#9450) 2026-07-14 23:04:38 -04:00
Anatolii Kmetiuk da1a94bea9 [2.x] Add native client startup diagnostics regression test (#9447)
Add native client startup diagnostics regression test
2026-07-14 18:27:28 -04:00
Anatolii Kmetiuk 2d2d5136ef [2.x] fix sjson downgrade (#9426)
Extend metabuild exclusion to all sbt-provided deps.
2026-07-12 22:25:40 -04:00
Anatolii Kmetiuk e7d25a0971 [2.x] Fix ivyless sbt plugin publish cross paths (#9416)
Problem:
When useIvy := false, ivyless publishing dropped the optional
scala_[scalaVersion]/ and sbt_[sbtVersion]/ path segments from Ivy-style
plugin publish patterns. This caused sbt 1 plugins published from sbt 2 builds
to land under non-plugin Ivy paths, so consumers looking under
scala_2.12/sbt_1.0/ could not resolve them.

Solution:
Read the plugin cross-version attributes from the CsrProject module and use
them when constructing ivyless Ivy-layout publish paths. Apply the same
substitution for local/file Ivy publishing and remote Ivy-style URL publishing,
while continuing to omit those optional segments when the attributes are absent.
Add scripted regressions for local and HTTP Ivy-style publishing of an sbt 1
plugin with useIvy := false.
2026-07-12 22:24:41 -04:00