diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java index 2a0ace8e215798..cf93fb2933e8de 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java @@ -17,12 +17,14 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; +import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.devtools.build.lib.analysis.BlazeVersionInfo; import com.google.devtools.build.lib.bazel.BazelVersion; import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; @@ -44,6 +46,7 @@ import com.google.devtools.build.skyframe.SkyframeLookupResult; import java.util.Map; import java.util.Objects; +import java.util.Set; import javax.annotation.Nullable; /** @@ -119,6 +122,8 @@ private static Selection.Result discoverAndSelect(Environment env, RootModuleFil return null; } + verifyAllOverridesAreOnExistentModules(initialDepGraph, root.getOverrides()); + Selection.Result selectionResult; try (SilentCloseable c = Profiler.instance().profile(ProfilerTask.BZLMOD, "selection")) { selectionResult = Selection.run(initialDepGraph, root.getOverrides()); @@ -152,6 +157,23 @@ private static Selection.Result discoverAndSelect(Environment env, RootModuleFil return selectionResult; } + private static void verifyAllOverridesAreOnExistentModules( + ImmutableMap initialDepGraph, + ImmutableMap overrides) + throws BazelModuleResolutionFunctionException { + ImmutableSet existentModules = + initialDepGraph.values().stream().map(InterimModule::getName).collect(toImmutableSet()); + Set nonexistentModules = Sets.difference(overrides.keySet(), existentModules); + if (!nonexistentModules.isEmpty()) { + throw new BazelModuleResolutionFunctionException( + ExternalDepsException.withMessage( + Code.BAD_MODULE, + "the root module specifies overrides on nonexistent module(s): %s", + Joiner.on(", ").join(nonexistentModules)), + Transience.PERSISTENT); + } + } + private static void verifyRootModuleDirectDepsAreAccurate( InterimModule discoveredRootModule, InterimModule resolvedRootModule, diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java index 4ee98ed19af66f..a5c5ba6aba5351 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java @@ -440,4 +440,40 @@ public void testYankedVersionSideEffects_differentCompatibilityLevel() throws Ex + " compatibility level 3 which is different"); assertDoesNotContainEvent("hello from yanked version"); } + + @Test + public void overrideOnNonexistentModule() throws Exception { + scratch.file( + rootDirectory.getRelative("MODULE.bazel").getPathString(), + "module(name='mod', version='1.0')", + "bazel_dep(name = 'a', version = '1.0')", + "bazel_dep(name = 'b', version = '1.1')", + "local_path_override(module_name='d', path='whatevs')"); + + FakeRegistry registry = + registryFactory + .newFakeRegistry("/bar") + .addModule( + createModuleKey("a", "1.0"), + "module(name='a', version='1.0')", + "bazel_dep(name='b', version='1.0')") + .addModule(createModuleKey("c", "1.0"), "module(name='c', version='1.0')") + .addModule(createModuleKey("c", "1.1"), "module(name='c', version='1.1')") + .addModule( + createModuleKey("b", "1.0"), + "module(name='b', version='1.0')", + "bazel_dep(name='c', version='1.1')") + .addModule( + createModuleKey("b", "1.1"), + "module(name='b', version='1.1')", + "bazel_dep(name='c', version='1.0')"); + + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + EvaluationResult result = + evaluator.evaluate(ImmutableList.of(BazelModuleResolutionValue.KEY), evaluationContext); + + assertThat(result.hasError()).isTrue(); + assertThat(result.getError().toString()) + .contains("the root module specifies overrides on nonexistent module(s): d"); + } }