From 010ac99ed02882d391c9d7120f6076489f616530 Mon Sep 17 00:00:00 2001 From: "bazel.build machine account" <15028808+bazel-io@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:22:32 +0100 Subject: [PATCH] [7.1.1] Fix two `bazel mod tidy` crashes (#21700) * Fixes a crash when using a non-registry override with a specified version: ``` Caused by: java.lang.NullPointerException: null value in entry: foo=null at com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:33) at com.google.common.collect.ImmutableMapEntry.<init>(ImmutableMapEntry.java:54) at com.google.common.collect.ImmutableMap.entryOf(ImmutableMap.java:345) at com.google.common.collect.ImmutableMap$Builder.put(ImmutableMap.java:454) at com.google.devtools.build.lib.bazel.bzlmod.Module.getRepoMappingWithBazelDepsOnly(Module.java:67) at com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction.getExtensionUsagesById(BazelDepGraphFunction.java:233) at com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction.compute(BazelDepGraphFunction.java:126) at com.google.devtools.build.skyframe.AbstractParallelEvaluator$Evaluate.run(AbstractParallelEvaluator.java:464) ``` * Fixes a crash for root modules with no extension usages: ``` Caused by: java.lang.NullPointerException: Cannot invoke "java.util.Map.keySet()" because the return value of "com.google.common.collect.ImmutableMap.get(Object)" is null at com.google.devtools.build.lib.bazel.bzlmod.BazelModTidyFunction.compute(BazelModTidyFunction.java:85) at com.google.devtools.build.skyframe.AbstractParallelEvaluator$Evaluate.run(AbstractParallelEvaluator.java:464) ``` Fixes #21651 Closes #21686. Commit https://github.com/bazelbuild/bazel/commit/77369dc895597c012794c5ada78705a90a61c2cb PiperOrigin-RevId: 615826860 Change-Id: I22be3fd53d0dc97aec92afe3dc51a9d6b7e60c98 Co-authored-by: Fabian Meumertzheim <fabian@meumertzhe.im> --- .../lib/bazel/bzlmod/BazelLockFileValue.java | 9 ++- .../bazel/bzlmod/BazelModTidyFunction.java | 8 ++- .../build/lib/bazel/bzlmod/Discovery.java | 34 +++------ .../build/lib/bazel/bzlmod/InterimModule.java | 22 ++++++ src/test/py/bazel/bzlmod/mod_command_test.py | 70 +++++++++++++++++++ 5 files changed, 116 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java index 3c85644a59a..17c92325e67 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java @@ -132,7 +132,14 @@ public abstract class BazelLockFileValue implements SkyValue, Postable { newDepGraph.putAll(getModuleDepGraph()); newDepGraph.put( ModuleKey.ROOT, - toModule(value.getModule(), /* override= */ null, /* remoteRepoSpec= */ null)); + toModule( + value + .getModule() + .withDepSpecsTransformed( + InterimModule.applyOverrides( + value.getOverrides(), value.getModule().getName())), + /* override= */ null, + /* remoteRepoSpec= */ null)); return toBuilder() .setModuleFileHash(value.getModuleFileHash()) .setModuleDepGraph(newDepGraph.buildKeepingLast()) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModTidyFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModTidyFunction.java index a1eac4d6473..6cdf50a1374 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModTidyFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModTidyFunction.java @@ -21,6 +21,7 @@ import static com.google.devtools.build.lib.bazel.bzlmod.ModuleFileFunction.IGNO import static com.google.devtools.build.lib.bazel.bzlmod.ModuleFileFunction.MODULE_OVERRIDES; import static com.google.devtools.build.lib.skyframe.PrecomputedValue.STARLARK_SEMANTICS; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; @@ -81,7 +82,12 @@ public class BazelModTidyFunction implements SkyFunction { } ImmutableSet<SkyKey> extensionsUsedByRootModule = - depGraphValue.getExtensionUsagesTable().columnMap().get(ModuleKey.ROOT).keySet().stream() + depGraphValue + .getExtensionUsagesTable() + .columnMap() + .getOrDefault(ModuleKey.ROOT, ImmutableMap.of()) + .keySet() + .stream() .map(SingleExtensionEvalValue::key) .collect(toImmutableSet()); SkyframeLookupResult result = env.getValuesAndExceptions(extensionsUsedByRootModule); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java index 32f7d0a020c..5da2540e923 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java @@ -54,7 +54,10 @@ final class Discovery { String rootModuleName = root.getModule().getName(); ImmutableMap<String, ModuleOverride> overrides = root.getOverrides(); Map<ModuleKey, InterimModule> depGraph = new HashMap<>(); - depGraph.put(ModuleKey.ROOT, rewriteDepSpecs(root.getModule(), overrides, rootModuleName)); + depGraph.put( + ModuleKey.ROOT, + root.getModule() + .withDepSpecsTransformed(InterimModule.applyOverrides(overrides, rootModuleName))); Queue<ModuleKey> unexpanded = new ArrayDeque<>(); Map<ModuleKey, ModuleKey> predecessors = new HashMap<>(); unexpanded.add(ModuleKey.ROOT); @@ -101,7 +104,11 @@ final class Discovery { depGraph.put(depKey, null); } else { depGraph.put( - depKey, rewriteDepSpecs(moduleFileValue.getModule(), overrides, rootModuleName)); + depKey, + moduleFileValue + .getModule() + .withDepSpecsTransformed( + InterimModule.applyOverrides(overrides, rootModuleName))); unexpanded.add(depKey); } } @@ -111,27 +118,4 @@ final class Discovery { } return ImmutableMap.copyOf(depGraph); } - - private static InterimModule rewriteDepSpecs( - InterimModule module, ImmutableMap<String, ModuleOverride> overrides, String rootModuleName) { - return module.withDepSpecsTransformed( - depSpec -> { - if (rootModuleName.equals(depSpec.getName())) { - return DepSpec.fromModuleKey(ModuleKey.ROOT); - } - - Version newVersion = depSpec.getVersion(); - @Nullable ModuleOverride override = overrides.get(depSpec.getName()); - if (override instanceof NonRegistryOverride) { - newVersion = Version.EMPTY; - } else if (override instanceof SingleVersionOverride) { - Version overrideVersion = ((SingleVersionOverride) override).getVersion(); - if (!overrideVersion.isEmpty()) { - newVersion = overrideVersion; - } - } - - return DepSpec.create(depSpec.getName(), newVersion, depSpec.getMaxCompatibilityLevel()); - }); - } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java index cc70b04467e..21aa20ed58b 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java @@ -260,4 +260,26 @@ public abstract class InterimModule extends ModuleBase { .setAttributes(AttributeValues.create(attrBuilder.buildOrThrow())) .build(); } + + static UnaryOperator<DepSpec> applyOverrides( + ImmutableMap<String, ModuleOverride> overrides, String rootModuleName) { + return depSpec -> { + if (rootModuleName.equals(depSpec.getName())) { + return DepSpec.fromModuleKey(ModuleKey.ROOT); + } + + Version newVersion = depSpec.getVersion(); + @Nullable ModuleOverride override = overrides.get(depSpec.getName()); + if (override instanceof NonRegistryOverride) { + newVersion = Version.EMPTY; + } else if (override instanceof SingleVersionOverride) { + Version overrideVersion = ((SingleVersionOverride) override).getVersion(); + if (!overrideVersion.isEmpty()) { + newVersion = overrideVersion; + } + } + + return DepSpec.create(depSpec.getName(), newVersion, depSpec.getMaxCompatibilityLevel()); + }; + } } diff --git a/src/test/py/bazel/bzlmod/mod_command_test.py b/src/test/py/bazel/bzlmod/mod_command_test.py index 3f6853dee97..fa68bee94a0 100644 --- a/src/test/py/bazel/bzlmod/mod_command_test.py +++ b/src/test/py/bazel/bzlmod/mod_command_test.py @@ -800,6 +800,76 @@ class ModCommandTest(test_base.TestBase): module_file.read().split('\n'), ) + def testModTidyWithNonRegistryOverride(self): + self.ScratchFile( + 'MODULE.bazel', + [ + 'bazel_dep(name = "foo", version = "1.2.3")', + 'local_path_override(module_name = "foo", path = "foo")', + 'ext = use_extension("//:extension.bzl", "ext")', + 'use_repo(ext, "dep")', + ], + ) + self.ScratchFile('BUILD.bazel') + self.ScratchFile( + 'extension.bzl', + [ + 'def _ext_impl(ctx):', + ' pass', + '', + 'ext = module_extension(implementation=_ext_impl)', + ], + ) + self.ScratchFile( + 'foo/MODULE.bazel', ['module(name = "foo", version = "1.2.3")'] + ) + + # Verify that bazel mod tidy doesn't fail without the lockfile. + self.RunBazel(['mod', 'tidy']) + + with open('MODULE.bazel', 'r') as module_file: + self.assertEqual( + [ + 'bazel_dep(name = "foo", version = "1.2.3")', + 'local_path_override(', + ' module_name = "foo",', + ' path = "foo",', + ')', + '', + 'ext = use_extension("//:extension.bzl", "ext")', + 'use_repo(ext, "dep")', + # This newline is from ScratchFile. + '', + ], + module_file.read().split('\n'), + ) + + # Verify that bazel mod tidy doesn't fail with the lockfile. + self.RunBazel(['mod', 'tidy']) + + def testModTidyWithoutUsages(self): + self.ScratchFile( + 'MODULE.bazel', + [ + 'module( name = "foo", version = "1.2.3")', + ], + ) + + self.RunBazel(['mod', 'tidy']) + + with open('MODULE.bazel', 'r') as module_file: + self.assertEqual( + [ + 'module(', + ' name = "foo",', + ' version = "1.2.3",', + ')', + # This newline is from ScratchFile. + '', + ], + module_file.read().split('\n'), + ) + def testModTidyFailsOnExtensionFailure(self): self.ScratchFile( 'MODULE.bazel', -- GitLab