Fix unconditional Skyframe invalidation with `--lockfile_mode=update`
Ensure that `BazelLockFileModule` only updates `MODULE.bazel.lock` if the content of the file needs to change. Every such update changes the file's metadata, which results in Skyframe invalidation of, in particular, all configurations. This broke `bazel config`, which uses `MemoizingEvaluator#getDoneValues()` to directly observe Skyframe state.
Since this type of invalidation can also be caused by users and deviates from the usual "incremental correctness" guarantees provided by Bazel, let `config` show a descriptive error when no configurations are found.
Fixes #19823
Closes #19842.
PiperOrigin-RevId: 574133346
Change-Id: I5886c91fc6b7b938a7dee59ea75aa7b8afb5b161
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java
index a664ae3..4036eb3 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java
@@ -106,8 +106,13 @@
combineModuleExtensions(lockfile.getModuleExtensions(), oldExtensionUsages))
.build();
- // Write the new value to the file
- updateLockfile(lockfilePath, lockfile);
+ // Write the new value to the file, but only if needed. This is not just a performance
+ // optimization: whenever the lockfile is updated, most Skyframe nodes will be marked as dirty
+ // on the next build, which breaks commands such as `bazel config` that rely on
+ // com.google.devtools.build.skyframe.MemoizingEvaluator#getDoneValues.
+ if (!lockfile.equals(oldLockfile)) {
+ updateLockfile(lockfilePath, lockfile);
+ }
this.moduleResolutionEvent = null;
this.extensionResolutionEventsMap.clear();
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java
index 53e43ca..c0ddd7b 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java
@@ -332,6 +332,15 @@
public BlazeCommandResult exec(CommandEnvironment env, OptionsParsingResult options) {
ImmutableSortedMap<BuildConfigurationKey, BuildConfigurationValue> configurations =
findConfigurations(env);
+ if (configurations.isEmpty()) {
+ String message =
+ "No configurations found. This can happen if the 'config' subcommand is used after "
+ + "files, including their metadata, have changed since the last invocation of "
+ + "another subcommand. Try running a 'build' or 'cquery' directly followed by "
+ + "'config'.";
+ env.getReporter().handle(Event.error(message));
+ return createFailureResult(message, Code.CONFIGURATION_NOT_FOUND);
+ }
try (PrintWriter writer =
new PrintWriter(
diff --git a/src/test/shell/integration/configured_query_test.sh b/src/test/shell/integration/configured_query_test.sh
index 8417dc1..9a9cb52 100755
--- a/src/test/shell/integration/configured_query_test.sh
+++ b/src/test/shell/integration/configured_query_test.sh
@@ -60,10 +60,6 @@
add_to_bazelrc "build --package_path=%workspace%"
-# TODO: enable Bzlmod for this Test
-# https://github.com/bazelbuild/bazel/issues/19823
-disable_bzlmod
-
#### TESTS #############################################################
function test_basic_query() {
@@ -897,8 +893,8 @@
--starlark:expr="str(target.label) + '%foo'" > output \
2>"$TEST_log" || fail "Expected success"
- assert_contains "^@//$pkg:pylib%foo$" output
- assert_contains "^@//$pkg:pylibtwo%foo$" output
+ assert_contains "^@@\?//$pkg:pylib%foo$" output
+ assert_contains "^@@\?//$pkg:pylibtwo%foo$" output
bazel cquery "//$pkg:all" --output=starlark \
--noincompatible_unambiguous_label_stringification \
@@ -1294,7 +1290,7 @@
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:srcfile.txt:providers=.*FileProvider.*FilesToRunProvider.*LicensesProvider.*VisibilityProvider" \
output
- assert_contains "VisibilityProvider.label:@//$pkg:srcfile.txt" output
+ assert_contains "VisibilityProvider.label:@@\?//$pkg:srcfile.txt" output
}
function test_starlark_output_providers_starlark_provider() {
@@ -1394,6 +1390,7 @@
EOF
mkdir -p $dir/main
+ write_default_lockfile $dir/main/MODULE.bazel.lock
cat > $dir/main/WORKSPACE <<EOF
local_repository(name = "repo", path = "../repo")
EOF