Skip to content

Change-detect and quiet the automatic sbt meta-build export#2958

Merged
tgodzik merged 3 commits into
scalacenter:mainfrom
jozanek:issue-1357-quiet-meta-build-export
Jun 15, 2026
Merged

Change-detect and quiet the automatic sbt meta-build export#2958
tgodzik merged 3 commits into
scalacenter:mainfrom
jozanek:issue-1357-quiet-meta-build-export

Conversation

@jozanek

@jozanek jozanek commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Closes #1357.

Problem

The sbt-bloop plugin exports the sbt meta-build (the build definition under project/) to bloop on every load, so Metals can compile and navigate project/*.scala / *.sbt. This makes sbt startup slower and prints confusing (and duplicated) [success] Generated …json lines on every load.

Fully reverting the auto-export isn't an option (Metals depends on it) so this keeps it on by default but removes the cost and the noise.

What changed

  • Change detection. The on-load export is skipped while a fingerprint of the files under project/ (path + mtime + size, with target/.bloop subtrees pruned) is unchanged. The fingerprint is stamped in .bloop whenever bloopInstall exports the meta-build, so a steady-state sbt startup is fast and silent, while edits / additions / deletions regenerate. Change detection fails safe: any IO error falls back to exporting, so it can never break load.
  • Quieter logging. The automatic export now logs at debug; a manual bloopInstall keeps its usual [success] output. Quietness is keyed on the on-load path rather than on "is this a meta-build", so manual runs are unaffected.
  • Opt-out. New bloopExportMetaBuild. Disable globally with -Dbloop.export-meta-build=false or BLOOP_EXPORT_META_BUILD=false (read at every meta-build layer, so it also covers nested project/project builds), or per layer with Global / bloopExportMetaBuild := false. Documented in docs/build-tools/sbt.md.

Scope / caveat

The fingerprint tracks files under project/ only. Inputs read from elsewhere — system properties, environment variables, or files outside project/ — are not detected; a bloopInstall (or any edit under project/) forces a refresh. This is documented in the new docs section.

Sorry for long PR, wanted to split/stack it, but wasn't very successful.

The sbt-bloop plugin exports the sbt meta-build (the build definition
under project/) on every load so Metals can compile it. This made sbt
startup slower and noisier than without the plugin.

- Skip the on-load export when a fingerprint of the files under project/
  is unchanged. The fingerprint is stamped in .bloop whenever bloopInstall
  exports the meta-build, so startup is fast and silent once the build
  definition is stable, while edits/additions/deletions still regenerate.
- Log the automatic export at debug level; a manual bloopInstall still
  reports as before.
- Add a bloopExportMetaBuild opt-out via the BLOOP_EXPORT_META_BUILD
  environment variable / bloop.export-meta-build system property (global,
  covers nested meta-builds) or the per-layer setting.

Adds scripted tests for change detection (edit/add/delete) and the
opt-out across nested meta-build layers.
* are still invalidated. Inputs that are not files under `project/` (system
* properties, environment variables, …) are out of scope.
*/
private def metaBuildFingerprint(buildBase: File): String = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't calculate the fingerprints ourselves, this something that sbt is doing and we should delegate to it if needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meta-build export is now opt-in via the bloop.export-meta-build system property (default off), so there's nothing to change-detect: a plain sbt never exports the meta-build, and when the property is set it always regenerates fresh.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thanks!

} else if (isMetaBuild) {
// Stamp the change-detection fingerprint so the next load can skip,
// regardless of whether this `bloopInstall` was automatic or manual.
writeMetaBuildFingerprint(metaBuildBase)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of writting we could use a java property? -Dexport-meta=true or something along those lines? We could add it by default in Metals when running bloopInstall.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added -Dbloop.export-meta-build=true (default off), so Metals can set it when running bloopInstall. I namespaced the property to match the existing bloop.export-jar-classifiers. Happy to rename to export-meta or whatever you'd prefer. Heads-up for the changelog: any non-Metals consumer that relied on the old default auto-export will now need to set this property.

@tgodzik tgodzik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks!

@tgodzik tgodzik merged commit 190bebe into scalacenter:main Jun 15, 2026
12 of 13 checks passed
@tgodzik

tgodzik commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Added the property to metals scalameta/metals#8538

@jozanek jozanek deleted the issue-1357-quiet-meta-build-export branch June 15, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bloop generate is automatically called during sbt project loading

2 participants