Skip to content

fix: don't materialize rules_python when reading the artifacts manifest - #4370

Open
sputt wants to merge 2 commits into
bazel-contrib:mainfrom
sputt:fix/artifacts-manifest-bzl
Open

sputt wants to merge 2 commits into
bazel-contrib:mainfrom
sputt:fix/artifacts-manifest-bzl

Conversation

@sputt

@sputt sputt commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

The config extension reads artifacts_manifest.json with mctx.read(Label(...)), so with --experimental_remote_repo_contents_cache every consumer still materializes the whole @rules_python repo. This is the remaining gap after #4294.

Following #4294, the manifest becomes python/private/artifacts_manifest.bzl, whose ARTIFACTS_MANIFEST_JSON string the extension loads. It stays empty in git, so source checkouts build the tools from source. The release generator now writes this .bzl file, and the archive script bundles it in place of the empty one. configure_tool_toolchains no longer needs module_ctx, and tests pass their manifest JSON directly.

The `config` extension read `artifacts_manifest.json` by Label, so with
`--experimental_remote_repo_contents_cache` every consumer still
materialized the whole `@rules_python` repo, the gap left after bazel-contrib#4294.

The manifest is now `artifacts_manifest.bzl` with an
`ARTIFACTS_MANIFEST_JSON` string that the extension loads. The release
generator writes that .bzl, and the archive script bundles it in place
of the empty one in git.
@sputt
sputt force-pushed the fix/artifacts-manifest-bzl branch from 605daa3 to b5b9262 Compare October 27, 2026 21:29
@sputt

sputt commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

AI disclosure: this change was written with an AI coding agent and human-reviewed by me before sending. I'll respond to review comments directly; no agent is monitoring or replying on this PR.

@sputt

sputt commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Verified with Bazel 9.1.1, --experimental_remote_repo_contents_cache and a local bazel-remote cache: bazel cquery //:hello (a py_binary) from a fresh output base after a warm-up run, with rules_python as an archive_override.

Before (main):

DEBUG: Materializing remote repo @@rules_python+

After (this PR): no @@rules_python+ materialization. The same //:hello result in both runs.

@sputt

sputt commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

PTAL

http_file = mocks.repo()
toolchain_repo = mocks.repo()
tools_toolchains_repo = mocks.repo()
mctx = mocks.mctx(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should add a validation or a comment here to ensure that we don't do something similar in the future. Could we in theory add an integration test to test a regression like this?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

With the mocks, it might not be so bad to do that. All the the mctx.read() calls should go through the mock interface, so if that kept track of the paths it saw, you could then compute if the read would have caused a repo to be materialized.

For an integration test, not sure, since it requires the remote repo cache. It sounded like @sputt had a cleaner repro strategy, so maybe they have ideas / know


It's a .bzl file so the `config` extension can load it rather than read it by
Label, which would make Bazel's remote repository contents cache materialize
the entire repository.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

add a reference to the pending PR in bazel to optimize this case. Given that, we can track down when we can remove this hack

the entire repository.
"""

ARTIFACTS_MANIFEST_JSON = ""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

An embedded JSON string is a bit weird, so add a comment about why we do that: to keep the code paths for loading a custom prebuilt tools manifest the same as when using the builtin manifest.

manifest_path = self.rules_python_dir / "python/private/artifacts_manifest.bzl"
manifest_path.write_text(
json.dumps(manifest, indent=2) + "\n",
f'ARTIFACTS_MANIFEST_JSON = """{json.dumps(manifest)}"""\n',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

pretty print the JSON string. Use indent 1. The parsing and storage overhead are minimal, so lets take the win in human inspection of it.

. \
":!MODULE.bazel" \
":!python/private/artifacts_manifest.json" | gzip > "$ARCHIVE"
":!python/private/artifacts_manifest.bzl" | gzip > "$ARCHIVE"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: since we're here, move the | gzip > "$ARCHIVE" to its own line

Comment thread news/4370.fixed.md
@@ -0,0 +1,4 @@
(toolchains) Evaluating the {obj}`config` module extension no longer

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm pretty sure the artifacts.json code path didn't land yet, so this news entry isn't necessary

This branch has not been deployed

No deployments
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.

3 participants