Commit Graph

76 Commits

Author SHA1 Message Date
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
Albert Meltzer 8c76375eab
[2.x] fix: Name the platform in CrossVersion(module, scalaModuleInfo) (#9620)
**Problem**
CrossVersion(module, scalaModuleInfo) is handed everything needed to name an
artifact, including ScalaModuleInfo.platform, and the name it returns is what
a caller publishes or resolves under. Nothing covers what it does with the
platform.

**Solution**
Name the artifact in full: platform suffix before cross suffix, matching the
coordinate (sbt/sbt#9117), through addPlatformSuffix, which already knows that
jvm contributes no suffix.

Generated-by: Claude Opus 5
2026-08-18 02:04:57 -04:00
kenji yoshida c5eac14c14
[2.x] refactor: Remove unused code (#9589) 2026-08-13 14:50:30 -04:00
tanaka takaya 1038618246
[2.x] perf: Memoize the artifact content hash in LibraryManagementCodec (#9563)
**Problem**
Serializing an UpdateReport re-reads every artifact through sjson-new's
File iso to recompute its sha256, so every ActionCache key computation
and Tracked write-back re-reads the whole dependency classpath on every
invocation, including no-ops.

**Solution**
Override the iso with a hash memoized by (path, size, lastModified),
with the same invalidation semantics as the digest cache in sbt/sbt#8363,
and mix it into the generated codec via contrabandCodecParents.

Generated-by: Claude Fable 5
2026-08-06 20:46:13 -04:00
Mai Huy Hoàng 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 <noreply@anthropic.com>
2026-07-29 09:43:09 +07:00
Mai Huy Hoàng 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 <noreply@anthropic.com>
2026-07-29 09:35:47 +07:00
Mai Huy Hoàng 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 <noreply@anthropic.com>
2026-07-28 09:34:37 -04:00
Eugene Yokota 74f76e5445 [2.x] Deprecate Resolver.url
This adds Resolver.uri instead.
2026-07-10 11:46:26 -04:00
Jozef Koval 73d164fa84
[2.x] fix: Substitute [organisation] literally by defaulting Patterns.isMavenCompatible to false (#9344)
**Problem**

In an Ivy resolver pattern, the [organisation]/[organization] token has its dots rewritten to slashes (org.example → org/example), behaving like Ivy's [orgPath] token rather than being literal. Per the [Apache Ivy spec](http://ant.apache.org/ivy/history/latest-milestone/concept.html), [organisation] should be substituted literally and [orgPath] is the slash-separated form.

Root cause: Patterns.isMavenCompatible defaulted to true, which sbt forwards to Apache Ivy as setM2compatible(true); with m2-compatibility on, Ivy rewrites the [organisation] token to slash form. A user supplying a custom Ivy pattern (e.g. for an SFTP/SSH resolver) inherited that default and got the wrong paths, with no obvious indication why. The only workaround was the non-obvious withIsMavenCompatible(false).

**Solution**

Flip the default of Patterns.isMavenCompatible from true to false, so a hand-written Patterns keeps [organisation] literal by default — matching the Ivy spec.
2026-06-15 23:54:28 -04:00
Ali Rashid 3b097cc3cc
[2.x] fix: Fixes publishing platform-specific artifacts (like Scala Native)
**Problem**
Platform suffix is absent in published artifacts.
#9118 partially solved this. It didn't touch publish-side naming though, so the published files still drop the suffix in three places.

**Solution**
This fixes
- ivyless publication names - CoursierArtifactsTasks.coursierPublicationsTask
- ivyless POM <artifactId> (the coordinate written inside the .pom) - PomGenerator.crossVersionDep
- Ivy backend (useIvy := true) - CrossVersion.substituteCross via IvyActions
2026-06-03 21:07:02 -04:00
Eugene Yokota c1219702d5 Contraband 0.9.0 2026-06-01 01:52:50 -04:00
eugene yokota 315202181c
[2.x] ci: Scalafmt 3.11.1 (#9279)
Apply Scalafmt
2026-05-31 16:01:15 -04:00
Zainab Ali 3b1dbae74a
[2.x] Add Test configuration to evictionWarningOptions (#9102)
* Add Test configuration to evictionWarningOptions
* Add Test configuration to default evictionWarningOptions
* Deduplicate eviction errors based on callers.
* Update eviction error test for semantic versioning.
* Group evictions by configuration and update test.
2026-04-23 23:06:54 -04:00
Anatolii Kmetiuk 4ebacc6e05
[2.x] fix: Include platform suffix in Artifact.artifactName (#9118) 2026-04-21 22:58:34 -04:00
BrianHotopp 3890cc7086
[2.x] fix: Resolve relative paths from -sbt-dir / sbt.global.base (#9001)
getFileProperty returned relative File objects when system properties
like sbt.global.base were set to relative paths (e.g. via -sbt-dir
../cache in .sbtopts). This caused an assertion failure in
IO.directoryURI: "Not absolute: ../cache/plugins".

Also fixes misleading scaladoc in SemanticSelector that claimed
`<=1.0` is equivalent to `<1.1.0` — they differ for pre-release
versions like 1.1.0-M1 (#4423).

Fixes #3729

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:27:34 -04:00
Dream 8132a392c3
[2.x] feat: Add dependencyMode setting to control classpath transitivity (#8960)
**Problem**
sbt always includes all transitive dependencies on the classpath.
This makes it easy to accidentally depend on transitive dependencies
without declaring them, leading to fragile builds that break when
a library changes its own dependencies.

**Solution**
Add a `dependencyMode` setting with three modes:

- DependencyMode.Transitive (default) — current behavior, all
  transitive dependencies on the classpath
- DependencyMode.Direct — only declared dependencies plus
  scala-library on the classpath
- DependencyMode.PlusOne — declared dependencies plus their
  immediate transitive dependencies plus scala-library

Fixes sbt/sbt#8942
2026-03-23 16:30:16 -04:00
ckstck 33c9bbdbe2
[2.x] fix: libraryDependency didn't work for cross-platform dependencies (#8957)
Problem
libraryDependencySchemes didn't work for platforms like Scala.JS

Solution
Modified EvictionError.scala to extract the suffix.
Changed from _: Binary to b: Binary and added ${b.suffix} to the module name.

---------

Co-authored-by: oolokioo7 <loki021107@gmail.com>
2026-03-21 22:43:17 -04:00
kenji yoshida 6dcb601f73
Add scalafmt newlines.topLevelStatementBlankLines setting (#8949) 2026-03-21 02:58:49 -04:00
xuwei-k 324f863d60 Remove return statements in UpdateReportPersistenceBenchmark 2026-03-20 15:04:34 +09:00
xuwei-k 87d8ae3a6c Use IO.withTemporaryDirectory in UpdateReportPersistenceSpec 2026-03-20 15:04:25 +09:00
kenji yoshida 14606c593d
[2.x] ci: Add scalafix DisableSyntax.noReturns (#8922) 2026-03-19 10:48:10 -04:00
Dream d71fe5b7a3
[2.x] refactor: Extract lm-ivy to separate sbt-ivy plugin module (#8873)
Step 5 of #7640 — removes the compile-time dependency on lm-ivy from main/ by creating a standalone sbt-ivy plugin module.

- Create new sbt-ivy/ subproject with IvyDependencyPlugin AutoPlugin that provides all Ivy-specific functionality (ivySbt, ivyModule, ivyConfiguration, publisher, projectDescriptors, deliver/makeIvyXml)
- Move IvyXml.scala from main/ to sbt-ivy/
2026-03-10 23:30:06 -04:00
eugene yokota 647dbc47f4
[2.x] Move compiler bridge to Update (#8836)
**Problem**
We want to grab tooling artifacts in update.

**Solution**
This adds binary compiler bridge artifacts into the update graph.
2026-03-04 02:35:38 -05:00
bitloi 19ebaaafb6
[2.x] perf: lightweight UpdateReport cache persistence (#8815)
- Add UpdateReportCache case class wrapping UpdateReportLite with stats/stamps
- Implement toCache/fromCache for conversion between UpdateReport and cache
- Add readFrom/writeTo for CacheStore persistence with backward compatibility
- Add fromLiteFull to JsonUtil for full reconstruction from lite format
- Update LibraryManagement to use new persistence API
- Add benchmark comparing full vs lite deserialization
- Add unit tests for persistence correctness
- Add scripted test for cache round-trip verification
2026-02-25 22:36:07 -05:00
Daniil Sivak 12cbd877bc
[2.x] fix: excluding artifacts w/o scala version suffix (#7454) (#8756)
**Problem**

Excluding artifacts using `.exclude(org, name)` requires you to
explicitly set scala version in `name`.

**Solution**

- Deprecating `.exclude(org, name)` in favor of new
  `.exclude(OrganizationArtifactName)`
- Fixing `lmcoursier.FromSbt` ignores `excludeRule.crossVersion`
2026-02-25 15:06:16 -05:00
PandaMan f47afb5b49
[2.x] fix: Fixes evicted warning for version intervals (#8719)
When a dependency declares a version range (e.g. Ivy [1.3.1,2.3] or comma-separated "1.3.1,2.3" as used by Coursier), and the resolver picks a version inside that range, sbt was still reporting an eviction warning. The chosen version satisfies the range, so it should not be reported as an eviction.

Example (from #6244): oauth2-oidc-sdk and nimbus-jose-jwt both depend on net.minidev:json-smart with range [1.3.1,2.3]. Resolution selects 2.3, which is within the range. Before this fix, sbt reported an eviction for json-smart even though 2.3 satisfies [1.3.1,2.3].
2026-02-09 02:27:28 -05:00
eugene yokota 080ce8f00e
[2.x] Extend 2.x universe to BinCompatV (#8667)
**Problem**
Some scripted tests are failing due to the fact that -bin-SNAPSHOT
isn't being recognized.

**Solution**
This fixes sbtApiVersion to recognize BinCompatV.
2026-01-31 23:29:50 -05:00
calm 8a518dfb98
[2.x] fix: Skip eviction warning when winner satisfies version range (#8616)
- Add `versionSatisfiesRange()` function to `VersionRange.scala` supporting Maven-style ranges (`[x,y)`, `(x,y]`, `[x,)`, etc.) and plus ranges (`1.0+`)
- Check if winner version satisfies evicted module's version range in `guessCompatible()`
2026-01-22 15:52:58 -05:00
calm 1b8e3317f9
[2.x] feat: Add "3-latest.candidate" support for Scala 3 release candidates (#8596)
Add support for `"3-latest.candidate"` to automatically resolve to the latest Scala 3 RC from Maven Central.

```scala
scalaVersion := "3-latest.candidate"
```

Ref https://github.com/sbt/sbt/discussions/8590
2026-01-21 03:42:50 -05:00
E.G ba9b5155e1
[2.x] test: Migrate UpdateReportSpec to verify.BasicTestSuite (#8545)
* test: Migrate UpdateReportSpec to verify.BasicTestSuite (#8543)

Migrate UpdateReportSpec.scala from ScalaTest's AnyFlatSpec + Matchers
to verify.BasicTestSuite, following the pattern established by other
test files in the lm-core module.

Changes:
- Replace AnyFlatSpec class with BasicTestSuite object
- Remove ScalaTest Matchers dependency
- Convert 'should ... in' syntax to 'test(...)' syntax
- Use Scala 3 syntax with colon indentation
- Change === to == for assertions (BasicTestSuite style)
- Add explicit types for lazy vals
- Add 'end UpdateReportSpec' marker

Fixes #8543

* Update lm-core/src/test/scala/UpdateReportSpec.scala

---------

Co-authored-by: GlobalStar117 <GlobalStar117@users.noreply.github.com>
2026-01-15 15:07:48 -05:00
calm b4f73c9a7b
[2.x] fix: Invalidate update cache across commands when dependencies change (#8501)
**Problem**
When project A's dependencies changed and A was compiled in one command, project B (depending on A) would not invalidate its update cache in a subsequent command. This caused stale classpaths.

The root cause was that `depsUpdated` only checked `!stats.cached`, which only detected fresh resolves within the same command. When a dependency was served from cache (even if resolved fresh in a previous command), `cached` was marked `true`, causing incorrect cache reuse.

Debug scenario from issue:
sbt:aaa> clean
sbt:aaa> a/compile
sbt:aaa> show itTests/depsUpdated
[info] * false   <-- BUG: should be true

**Solution**
Added `stamp: String` field to `UpdateStats` that records when the update was resolved. This stamp persists across commands and enables accurate cross-command comparison:

- If any dependency's stamp > our cached stamp, we re-resolve
- Falls back to `!cached` check for backwards compatibility with old caches
- Using `String` type allows future transition from timestamps to content hashes
2026-01-12 16:17:51 -05:00
byteforge bd03184cf5
[2.x] Fix ProjectMatrix invalid project ID with CrossVersion.full (#8484)
When using `ProjectMatrix` with `CrossVersion.full` and Scala 2 versions like `2.13.18`, the project ID incorrectly became `$1$2_13_18` instead of `foo2_13_18`.

**Root cause:** The Scala 3 compiler creates synthetic intermediate vals (e.g., `$1`) during macro expansion. The `enclosingTerm` function in the macros was stopping at these synthetic symbols instead of continuing up the symbol tree to find the actual val name.

**Fix:** Added `Flags.Synthetic` check to skip compiler-generated symbols in:
- `main-settings/src/main/scala/sbt/std/KeyMacro.scala`
- `lm-core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala`

---------

Co-authored-by: byteforge38 <joseph.mc0803@gmail.com>
2026-01-11 19:17:26 -05:00
kenji yoshida 113b6eb103
Use SAM-conversion if possible (#8477) 2026-01-11 07:21:28 -05:00
eugene yokota 81d3527913
Merge pull request #8468 from xuwei-k/tailrec-annotation
[2.x] Add `@tailrec` annotation
2026-01-11 03:19:19 -05:00
xuwei-k 3b4b7effc2 Remove redundant String#toString 2026-01-11 16:46:05 +09:00
xuwei-k c0fe4dfb10 Add tailrec annotation 2026-01-11 16:33:45 +09:00
calm 8c20401fb9
[2.x] Report eviction errors for Test dependencies (#8451)
Eviction warnings and errors were not reported for Test dependencies because
`EvictionError` only checked the Compile configuration.

This fix runs the eviction check for both Compile and Test configurations
separately, with distinct error messages:

- Compile: `found version conflict(s) in library dependencies`
- Test: `found version conflict(s) in Test dependencies`
2026-01-08 20:01:18 -05:00
Eugene Yokota a9e38e3a1c [2.x] fix: Resolver.combineDefaultResolvers
**Problem**
combineDefaultResolvers loses information.

**Solution**
This fixes it.
2025-12-25 01:49:57 -05:00
Eugene Yokota 5730383340 Merge branch '1.12.x' into wip/merge-1.12.x 2025-11-24 02:14:17 -05:00
Eugene Yokota d0ae314748 scalaEarlyVersion setting and source directories
**Problem**
During the milestone releases of Scala, e.g. Scala 2.13.0-M1,
scalaBinaryVersion by design points to 2.13.0-M1,
and also the source directory uses scala-2.13.0-M1,
but in most cases we actually want to pretend compatibility
and use scala-2.13 directory.

**Solution**
This introduces a new setting called scalaEarlyVersion,
which is the scalaBinaryVersion of the release version of milestones.
We have been calling this "partial version", but that broke
down for Scala 3, which adopted semantic versioning.
2025-11-16 18:02:17 -05:00
xuwei-k 038fa6c476 remove unnecessary nowarn annotations 2025-10-04 19:25:11 +09:00
Eugene Yokota 645908f597 Apply Contraband 2025-09-28 21:28:21 -04:00
Eugene Yokota 2fa3159f18 Update to Contraband 0.8.0 2025-09-19 00:46:34 -04:00
Hamza Remmal 0b319a16c5 add scala nightly repository resolver 2025-08-25 02:31:51 -04:00
Eugene Yokota 9783cd092b Merge branch '1.11.x' into wip/merge-1.11.x 2025-08-25 02:29:12 -04:00
eugene yokota 9b035c9979
Merge pull request #8209 from eed3si9n/wip/bump-sjson-new
[2.x] Bump to sjson-new 0.14.0-M4
2025-08-15 22:57:06 -04:00
Eugene Yokota be5152dbfb sjson-new 0.14.0-M4 2025-08-15 22:12:06 -04:00
xuwei-k 1a1ddb1373 update ResolverFunctions#reorganizeAppResolvers comment 2025-08-15 19:30:29 +09:00
Eugene Yokota 827efb6ee6 bport: Handle partialVersion("2")
https://github.com/sbt/librarymanagement/pull/528
2025-08-10 19:50:18 -04:00
Eugene Yokota 9e37218dcf refactor: Hide Ivy-related classes
Move Ivy-related classes to internal.
Promote IvyPaths and Credentials to core.
2025-08-09 01:52:45 -04:00