Commit Graph
4056 Commits
Author SHA1 Message Date
eugene yokota c8a0007d6e [2.x] feat: Persistent worker for test (#9678) 2026-09-25 03:30:09 -04:00
eugene yokota f9ca5f5ee6 [2.x] fix: Fixes inMemoryAnalysisCache limit (#9500)
**Problem**
The in-memory Analysis cache is currently weighted by on-disk size,
but according to the user report it expands out 50x, so 100MB
size limit doesn't hit.

**Solution**
This set maxCount instead, default 20 and configurable by system property
sbt.local_cache.analysis_count.
2026-09-24 18:38:55 -04:00
eugene yokota 754d0d5e37 [2.x] fix: Remove duplicate self JAR from Runtime (#9820)
**Problem**
Since #9471, Runtime/fullClasspath combines exportedProducts
(unversioned) with the Runtime internal dependency classpath
(packageBin, versioned), so the project's own JAR appears twice.

**Solution**
In Runtime, build fullClasspath and fullClasspathAsJar from
the versioned exported products.
2026-09-24 18:38:14 -04:00
eugene yokota dd7b23b0d2 [2.x] Update user-agent to major.minor (#9818)
To avoid user-agent being used for tracking, use only major.minor.
2026-09-24 16:57:45 -04:00
Albert Meltzer c7e8ce5f55 [2.x] refactor: VirtualAxis: refactor constructing ScalaVersionAxis (#9789) 2026-09-22 18:52:45 -04:00
Albert MeltzerandClaude Fable 5.1 b9c722a95f [2.x] refactor: ProjectMatrix: re-use xxxPlatform methods (#9788)
* [2.x] ProjectMatrix: re-use xxxPlatform methods
* [2.x] ProjectMatrix: pass configure directly

---------

Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-09-22 18:30:27 -04:00
Jozef Koval 27f1792e91 [2.x] fix: publishLocal must overwrite, remote publish must not (#9814)
Fixes #9813.

With overwrite = false, the default for non-snapshot versions, the ivyless
publisher kept an existing file and reported success, leaving stale bytes and
checksums. The HTTP paths took overwrite and never read it. sbt 1.x did the
opposite in both cases: file repositories warned and overwrote (22f47be29),
remote ones refused.

Restore that. File targets now warn and write through a temp file; HTTP targets
refuse after a HEAD probe that fails open. Also route a file: URLRepository,
Ivy or Maven layout, to the filesystem instead of httpPut.
2026-09-22 17:02:43 -04:00
PhoenixmitX 31f571314a [2.x] fix: restore the pipelining early output on an action-cache hit (#9793)
Problem
compileIncremental declares the analysis file and the classes directory
as cache outputs, but not the early (pickle) jar or the early analysis.
A cache hit therefore leaves a subproject with a restored analysis and
no early jar. On the next incremental round Zinc has no jar to merge
scalac's pickles into, so the early jar ends up holding only that
round's TASTy/sig files, afterEarlyOutput(true) fires, and every
downstream subproject is compiled against it and fails with "Not found"
for each upstream type that was not just recompiled.

Solution
- Declare the early jar and the early analysis file as outputs of
  compileIncremental when exportPipelining produced them, so a hit
  restores them.
- Restored outputs are symlinks into the CAS, and Zinc rewrites the
  early jar in place when it merges a round's pickles. Replace a
  symlinked early jar by a real copy before Zinc runs so the cached
  blob is never modified.
- When a previous analysis exists but the early jar does not (a cache
  written before the jar was an output, exportPipelining switched on
  for an existing build, a deleted early directory), recompile the
  subproject from scratch, which writes a complete jar.
2026-09-22 14:49:30 -04:00
Matthias Kurz 0c6ffced79 [2.x] fix: Derive Maven paths from module and artifact names (#9811)
**Problem**

The non-Ivy Maven publisher derived the repository directory and every
filename from the first POM artifact. Custom-named artifacts could collide
with and replace the main JAR, while legacy sbt 1 plugin publishing depended
on artifact map order and collapsed crossed and uncrossed files.

**Solution**

Derive the directory from module coordinates and each filename from the
platform-aware cross-versioned artifact name. Reject target-path collisions
before publishing, de-duplicate remote snapshot metadata, and cover ordinary,
platform, snapshot, and legacy plugin layouts with unit, property, and
scripted tests.

Generated-by: OpenAI Codex
2026-09-22 14:07:40 -04:00
Mai Huy Hoàng 52ac4e02ee [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)
2026-09-22 01:41:59 -04:00
Matthias Kurz 2124f13ac6 [2.x] fix: Restore sbt 1 plugin POM metadata (#9806)
**Problem**

sbt 1 plugin variants published by sbt 2 omitted the sbtVersion,
scalaVersion, and extraDependencyAttributes POM properties. Without this
metadata, sbt 1 consumers could resolve direct and transitive versions of
the same plugin as separate modules.

**Solution**

Restore module extra properties and Ivy-compatible dependency metadata in
generic POM generation. Preserve multiple dependency records through XML
formatting and cover publication and eviction with unit and scripted tests.

Fixes #9805

Generated-by: OpenAI Codex
2026-09-21 14:29:57 -04:00
Matthias Kurz 8c323c358b [2.x] fix: Restore cross-suffixed artifactIds in sbt 1 plugin POMs (#9804)
**Problem**

sbt 1 plugin variants published by sbt 2 used cross-suffixed Maven paths and files, but their generated POMs retained uncrossed module and plugin-dependency artifact IDs.

**Solution**

Restore the former Ivy cross-version transformation for the module and plugin dependencies before generic POM generation. Re-enable and modernize the scripted publication test.

Fixes #9803

Generated-by: OpenAI Codex
2026-09-21 13:27:40 -04:00
Eugene Yokota e7018fe642 refactor: Avoid default parameter 2026-09-21 00:32:04 -04:00
Stas Shevchenko 3c53033cf8 [2.x] Deploy remote Maven snapshots with one timestamp (#9756)
Every artifact went up under the plain -SNAPSHOT name with no maven-metadata.xml, so a repo with unique snapshot naming stamped each upload on its own. Remote Maven snapshot deploys now pick one timestamp and build number for the whole publication and send the metadata.
2026-09-21 00:10:49 -04:00
Mai Huy HoàngandClaude Opus 5 983e6a14c0 [2.x] fix: Make sbtn's result line consistent with sbt --server (#9783)
**Problem**
sbt compile through the thin client prints only elapsed time: 2 s, where the
same command in the shell or under sbt --server prints
elapsed time: 2 s, cache 94%, 13 disk cache hits, 24 remote cache hits. The
summary is computed server-side and thrown away: ManagedLogger.success is gated
on Terminal.isSuccessEnabled, and a NetworkChannel's terminal answered
interactive.get || isInWatch, which is false whenever a command is passed on
the command line. The line the user sees is the client's own, built from
wall-clock alone.

**Solution**
Report the line from the server, and have the client print only when the server
will not.

NetworkChannel's terminal reports isSuccessEnabled = true, so the server
writes the line on every channel, and it advertises successLog in its
capabilities. A server from before this sends no such key, which reads as false,
so an older client-server pair behaves as it does today; an unattached client
also always prints, since it renders build/logMessage rather than the proxied
systemOut bytes. Older sbtn keeps printing its own line and so reports
success twice until it updates.

Generated-by: Claude Opus 5

Claude-Session: https://claude.ai/code/session_015BqrfmHbJUph6Kx7gJn3G8

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-21 00:06:51 -04:00
eugene yokota 2ef94e086c [2.x] Custom user agent (#9786)
**Problem**
We want to track the network request created by sbt.

**Solution**
This sets both sbt version and Coursier version into the user agent.
2026-09-17 23:10:52 -04:00
Albert MeltzerandClaude Opus 5 37b3cc59b1 [2.x] ProjectMatrix: validate axes against autoScalaLibrary (#9771)
The flag and the axes both say whether a row is built for Scala, and
where they disagree the flag wins: a row given versions and
autoScalaLibrary = false is built for none of them, and the versions
are dropped. Nothing said so.

ProjectMatrix: validate axes against autoScalaLibrary

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-16 12:52:48 -04:00
eugene yokota 31779bf38d [2.x] fix: Update to Gigahorse 0.9.6 for preauth (#9775)
**Problem**
With HTTP/2, Apache HttpClient can begin the authenticated replay while the rejected stream is still consuming the same repeatable file producer.
The overlapping consumption can send corrupted artifacts, according to mkurz.

**Solution**
This hopefully fixes the issue by updateing to Gigahorse 0.9.6, which fixes the preauth support.
2026-09-16 12:16:10 -04:00
Albert MeltzerandClaude Opus 5 7563b7790b [2.x] Allow adding rows and configuring them separately, and through any method (#9765)
* [2.x] test: Pin what a platform axis alone does

**Problem**
`jsPlatform` enables the Scala.js plugin; the axis does not. A row
built by `customRow` with `VirtualAxis.js` is a Scala.js row by every
name it carries and a JVM row by what runs.

**Solution**
Assert what such a row reports as its platform.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>

* [2.x] feat: Enable JS/Native plugins if the axis is used

Only jsPlatform and nativePlatform enabled the plugin their platform
needs, so using customRow directly would skip it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* [2.x] feat: Configure the rows a matrix builds

A build could reach every row with configure, or one row with the call
that made it, and nothing in between, so settings for the rows of one
platform travelled with every call that creates them. Now
configureRows takes a function of a row's axes and answers with what
to apply, and a row is given it as it is built, so a row declared
after the call is covered too.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-16 21:53:11 +09:00
Albert Meltzer 3460089ec7 [2.x] fix: Do not duplicate platform axes on a row (#9757)
* test: Pin the axes of a row that carries no Scala version

`jvmPlatform(autoScalaLibrary = false)` passes `VirtualAxis.jvm` to
`customRow`, which appends it again, so the row holds the platform axis
twice and its generated directories are named `scalajvm-jvm` and
`javajvm-jvm`. Nothing covered that path.

* fix: Keep one platform axis on a row that names its own

`jvmPlatform(autoScalaLibrary = false)` hands `customRow` the platform
axis, and `customRow` appended a second one, so the row's generated
directories were named `scalajvm-jvm` and `javajvm-jvm` and a cell
whose sources sat in the usual places compiled nothing. Now the axis is
appended only when the caller named no platform.
2026-09-15 14:10:22 +09:00
eugene yokota 801280dc61 [2.x] fix: clean task (#9752)
**Problem**
The clean task no longer works as intended on sbt 2.x due to the disk cache.

**Solution**
This implements an in-memory state of invalidation for subproject and
configuration axes. So clean task would mark subprojects to be
invalidated regardless of the disk cache state.
The invalidation state would be lifted once any cached task executes,
so it's not technically same as sbt 1.x, but the UX should be similar.
2026-09-12 23:18:11 -04:00
eugene yokota 7d1878bd1f [2.x] fix: Fixes test setup/cleanup interleaving (#9727)
**Problem**
Tags are enforced per task node.
This means that a chain like setup-test-cleanup
would release the tags midway, and allow interleaving
executions even for exclusive tests.

**Solution**
This implements a special Span tag, which lets us
keep the tags across the task chains.
Since this requires the flatMapped tasks to not carry their
own tags to prevent a deadlock, the feature needs to be opt-in /
internal implementation.
2026-09-12 17:42:54 -04:00
Stas Shevchenko ea673bf06f [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.
2026-09-12 02:20:06 -04:00
eugene yokotaandkenji yoshida ae0898fb4b Revert "[2.x] Delete bootDirectory in cleanFull (#9060)" (#9747)
This reverts commit 7408fc93c7.

Co-authored-by: kenji yoshida <[email protected]>
2026-09-11 14:52:15 -04:00
Eugene Yokota f9688c1464 Apply Scalafmt format (Scala 3 syntax) 2026-09-10 14:16:27 -04:00
Jozef Koval 2626c40c82 [2.x] fix: Resolve the project axis to the current project in runAggregated (#9722)
**Problem**
When a key does not say which project it belongs to, Extracted.runAggregated filled in the global scope instead of the current project.

**Solution**
Fill in the current project instead, the way runInputTask always has. The only difference between the two scopes is the project, so a key that already names a project behaves exactly as before.
2026-09-10 12:58:39 -04:00
Albert MeltzerandClaude Opus 5 dbeeb199aa [2.x] fix: Stop a displaced server (#9713)
**Problem**
If a client cannot reach the server, it deletes the portfile. Then it
starts a second server. The first server is displaced: its socket path
now belongs to the second server.

A displaced server keeps running. A dropIfIdle notification cannot
reach it, because the proc file it registered names the socket that
the second server now owns.

**Solution**
The portfile holds the serverId of whichever server wrote it. Watch
that file, and exit when the id is not this server's. Leave the
portfile to the server that owns it.

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-10 12:55:11 -04:00
Stas Shevchenko ce7bb28f05 [2.x] fix: Fixes cross command parsing (#9726)
+cleanFull failed with Not a valid key: Full. The cross command re-parses its argument with the key parser, and clean is an accepting prefix, so the rest was taken as task args. Args now have to be preceded by whitespace.
2026-09-10 12:54:21 -04:00
eugene yokota 2238e405b8 [2.x] fix: Fail the build on bad resource generator (#9735)
**Problem**
Currently bad resources are silently dropped.

**Solution**
1. Fix a bad resource generator in the build.
2. Fail the build when bad resources are found.
2026-09-10 01:22:34 -04:00
Albert Meltzer f6033270e5 [2.x] fix: Add a row when customRow gets no versions (#9717)
The overload that takes axisValues and settings passes an empty
scalaVersions into the fold that builds the rows, so a call with
autoScalaLibrary = true returns the matrix unchanged. The assertion
records that, so the fix can move it.

Now the call adds one row from the axes it was given, so a build can name a partial or a full version instead.
2026-09-09 15:48:12 -04:00
eugene yokota 01198f5407 [2.x] feat: workerMaxInstances + testTopology (#9665)
* [2.x] feat: testForkedWorker setting

**Problem**
A major bottleneck of the default setting is that concurrentRestriction
allows exactly one forked test in flight at a time,
and partly due to the restriction all test suites from a subproject runs
within the forked process.

**Solution**
This adds a new setting called testForkedWorker, which lets the build users
tune the number of concurrent worker process in flight.
I've set the default to CPU count / 3.
Within a single worker, the default parallelism is reduced to 2.

The default test grouping now splits the test suites into
testForkedWorker count.

* Use Global scope for overall worker count

Subproject scoping can be used for single vs split

* Adds math.max(..., 1)

* Avoid running setup/cleanup on an empty selection

* Fix the tag application order

* Rename key to workerMaxInstances

* Implement TestTopology

* fix: Fixes exclusive test

Note due to the limitation of the tag system, setup-clean/cleanup
may overlap.

* Check that workerMaxInstances >= 1
2026-09-09 14:13:13 +09:00
Albert MeltzerandClaude Opus 5 db4d22cc18 [2.x] fix: Keep accepting after a client fails
**Problem**
The accept loop did not catch an exception from onIncomingSocket, so
its thread ended. Nothing closed the server socket, so the path stayed
bound: the server took no further client, and the process kept running.
The socket of the client that failed stayed open too.

**Solution**
Log that client, close its socket, and take the next one. An exception
from accept itself keeps the handling it had, so a socket that is
really broken still ends the loop.

The callback now takes a holder rather than the socket, and calls
AtomicCloseable.release to keep it. The loop closes whatever the
callback left behind.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-08 10:14:23 -07:00
Albert MeltzerandClaude Opus 5 40e8ebf917 [2.x] refactor: Name the expressions that repeat (#9712)
CommandExchange asked twice whether an exec came from the closing
channel, and cancelled an exec in two places. Each has a name now, as
does the read of shuttingDown and the Try whose failure is ignored.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-07 20:33:53 -04:00
Stas Shevchenko 976d7f3765 [2.x] fix: keep macro subprojects off the pipelined classpath (#9719) 2026-09-07 20:32:53 -04:00
Christian Harrington 8c62e437fb [2.x] fix: virtualize semanticdbTargetRoot in the compile cache key (#9711)
Problem
-------
SemanticdbPlugin.compileIncAndCacheSemanticdbTargetRootTask is a cached task
that reads semanticdbTargetRoot as a bare File, so its absolute path is hashed
into the action cache key:

  ((true,${OUT}/.../classes,${OUT}/.../classes.sbtdir.zip),/tmp/repro/target/out/.../meta)

Every other component of that key is virtualized. This one names one checkout
on one machine, so the entry can never be served to a second checkout, to a
colleague, or to CI. A monorepo we measured had 118 such keys, none of them
reachable across machines.

Fixes #9709

Solution
--------
Read the target root through semanticdbTargetRootVF, following the convention
sourcesVF and resourcesVF already set: an uncached task holding the virtualized
form of a File-typed key, so that a cached task hashes ${OUT}/.../meta rather
than the path behind it. A cached helper would key on the same bare File and
reintroduce the problem one level up.

The scripted test asserts the property the bug breaks: relocating
rootOutputDirectory must leave every key alone, so the second compile is a pure
cache hit. It pins Compile / semanticdbOptions, because -semanticdb-target
carries an absolute path into scalacOptions as well, which is a separate issue
and would otherwise mask this one.

Generated-by: Claude Opus 5
2026-09-07 20:30:45 -04:00
Mai Huy HoàngandClaude Opus 5 bbcae17f90 [2.x] perf: Optimize UpdateReport disk format (#9515)
The cache now writes each value-distinct ModuleReport once into a "modules"
table and gives each configuration's details a list of indices into it. That is
~5x smaller and hands the reader instance sharing structurally, with nothing to
probe to rediscover it.

CacheStoreFactory.makeCompressed writes gzip-framed JSON and reads either
framing, sniffing the magic bytes so a cache written before a store was
switched to compression still loads. It defaults to make, so existing
CacheStoreFactory implementations are unaffected.

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-01 00:49:49 -04:00
Albert MeltzerandClaude Opus 5 952b82e461 [2.x] fix: Share a holder for a closeable (#9692)
**Problem**
Four fields hold a closeable that a later caller replaces. Each one
reads the field, closes what it finds and writes the new value in its
own way.

**Solution**
AtomicCloseable holds such a value. It closes the value it replaces,
and closes the value that loses a race to fill an empty field.

Two things change for a caller. The client replaced its session
without closing the one it dropped, and now closes it. A close that
throws no longer escapes: each of these sites is discarding the value
it closes, and whatever led there matters more than the close.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-29 23:42:06 -05:00
Anatolii Kmetiukandeugene yokota 0da3f6b478 [2.x] Add test result cache opt-out (#9675)
* [2.x] Add test result cache opt-out

* Update main/src/main/scala/sbt/internal/SysProp.scala

Co-authored-by: eugene yokota <[email protected]>

* Use Boolean values for test cache opt-out

---------

Co-authored-by: eugene yokota <[email protected]>
2026-08-26 11:27:05 +09:00
eugene yokota 108623f848 [2.x] fix: Fixes ThisBuild-scoped bare settings (#9674)
**Problem**
ThisBuild scoped baresettings are treated as a common setting,
which results in duplicate appends etc.

**Solution**
Only treat This-project and ThisProject scoped setting as a common setting.
2026-08-24 21:32:34 -04:00
eugene yokota a91cf079db [2.x] Remove Ivy dependency (#9615)
**Problem**
sbt still has some code that's depending on Ivy.

**Solution**
This removes it.
2026-08-24 12:02:28 -04:00
Mai Huy Hoàng 94acc76830 [2.x] fix: Populate the in-memory cache on a read (#9657)
**Problem**
InMemoryCacheStore.CacheStoreImpl.read returns cacheStore.read[T]() on a miss
without putting the value in the cache, so the only thing that ever fills the
cache is write. A task whose stored output is already up to date never writes,
so it re-reads and re-deserialises that output on every invocation for the life of
the server, and the cache can never warm up for it.

update is the costly instance: transitiveUpdate runs it once per project in
the dependency closure, and every call goes through
UpdateReportPersistence.readFrom.

**Solution**
Put the value in the cache after a successful disk read. The keying is unchanged
-- an entry is still (path, lastModified), read re-stats the file on every
call, and write still invalidates before rewriting -- so a populated read is
sound for the same reason a populated write is.

Measured on an 81-module workspace, no-op build, real output files (no
cache-restored symlinks), exportJars=true, alternating the two builds over 8
runs each:

    update task    398ms across 82 projects -> 30ms across 29
    task total     4797ms -> 4623ms
    wall (median)  5.15s -> 4.97s

This makes maximumWeight bind where it could not before: reads now admit
entries, so a build whose working set exceeds sbt.file.cache.size will evict
rather than never cache at all. That is the intended behaviour of a bounded cache.

Generated-by: Claude Opus 5
2026-08-21 14:24:05 -04:00
Jozef Koval ec99275000 [2.x] fix: Resolve Seq[Initialize[Task[T]]].join to Initialize[Task[Seq[T]]] (#9347)
Fixes #899

Add the task join as an extension method on Seq[Def.Initialize[Task[A]]] in
Def. Member resolution tries extension methods before implicit
conversions, so it is selected ahead of the generic conversion regardless of
whether sbt.Scoped is in scope.
2026-08-21 13:40:28 -04:00
Stas Shevchenko 08cc82ac85 [2.x] perf: avoid re-sorting watch inputs on every file event (#9650)
Watch mode copied and sorted the whole dynamic-input set on every file event, once per config (Continuous.inputs()). The sort is irrelevant to the glob match, so match against the set directly. Biggest relative gain on macOS, where FSEvents coalescing turns a git checkout into a burst of thousands of events.
2026-08-21 01:39:41 -04:00
eugene yokota 4700d305cc Merge commit from fork
fix: disable BSP over TCP and gate requests before auth
2026-08-20 23:13:00 -04:00
Christian Harrington 82705f1cd5 [2.x] fix: Fixes filesystem traversal order affecting cache stability (#9646)
**Problem**
CompileInputs2.sources and packageBin / mappings are hashed positionally but arrive in
filesystem traversal order, which differs between APFS, ext4 and overlayfs. Two machines
hash an identical tree into different cache keys and cannot use each other's entries.

**Solution**
Sort sourcesVF by virtualized id, and mappings where packageConfigurationTask reads
it. Both are where the keys are built, so nothing appended later escapes the sort.

Generated-by: Claude Opus 5
2026-08-20 15:52:50 -04:00
stasimus 56f38a19a4 fix: disable BSP over TCP and gate requests before auth 2026-08-20 10:45:19 +02:00
cdf6b25106 [2.x] fix: Avoid rewriting unchanged plugin descriptors (#9612) (#9624) (#9628)
Only rewrite generated plugin descriptors when their normalized lines change, preserving the descriptor timestamp and downstream cache inputs for unchanged plugin discovery.

Add unit coverage plus direct packageBin and assembly Scripted scenarios. The descriptor regressions fail with the former unconditional write and pass with this change; the packageBin fixture also preserves SBT 2’s existing cache-hit behavior.

Co-authored-by: Dmitrii Naumenko <[email protected]>
Co-authored-by: Codex <[email protected]>
2026-08-19 13:05:17 -04:00
azdrojowa123andClaude Opus 4.8 3045cd0c46 [2.x] Add a resolvedScalacOptions task that resolves cache placeholders (#9610)
Add a resolvedScalacOptions task that resolves cache placeholders in scalacOptions to absolute machine paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-19 05:36:38 -04:00
eugene yokota 6b3d7c6301 [2.x] fix: Fixes cache invalidation on version change (#9471)
**Problem**
packageBin includes version into the file name, which ends up
invalidating the cache.

**Solution**
Define packageInternal, which does not include version in the file name, and used during Compile or Test/compile. Note that publishing and Runtime classpath would continue to use packageBin.
2026-08-19 00:13:59 -04:00
Mai Huy HoàngandClaude Opus 5 a1114188b4 [2.x] perf: Stop re-converting the classpath in compileOptions (#9622)
Both compileOptions sites mapped the whole classpath through
converter.toPath -> converter.toVirtualFile. Going through toPath
defeats FileConverter.toVirtualFile(VirtualFileRef), which already
returns the ref unchanged when it is a VirtualFile, so every entry was
rebuilt from scratch. For a class directory that means walking the
entire output tree, once per dependent.

backendOutput is converted explicitly because it is a settingKey
evaluated once at project load, so reusing it would pin the listing
taken before anything compiled.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-08-18 11:40:54 -04:00