bzlmod: Precompute data structures needed for module extension resolution
(https://github.com/bazelbuild/bazel/issues/13316)
At the end of BazelModuleResolutionFunction, we do some precomputation such as grouping all ModuleExtensionUsages by their "extension ID", and calculating a unique name for each extension.
PiperOrigin-RevId: 395948289
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/AbridgedModule.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/AbridgedModule.java
new file mode 100644
index 0000000..aed3f74
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/AbridgedModule.java
@@ -0,0 +1,48 @@
+// Copyright 2021 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package com.google.devtools.build.lib.bazel.bzlmod;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+
+/**
+ * An abridged version of a {@link Module}, with a reduced set of information available, used for
+ * module extension resolution.
+ */
+@AutoValue
+public abstract class AbridgedModule {
+ public abstract String getName();
+
+ public abstract Version getVersion();
+
+ public abstract ModuleKey getKey();
+
+ public final String getCanonicalRepoName() {
+ return getKey().getCanonicalRepoName();
+ }
+
+ public abstract ImmutableMap<String, ModuleKey> getDeps();
+
+ public final RepositoryMapping getRepoMapping() {
+ return Module.getRepoMappingWithBazelDepsOnly(getKey(), getName(), getDeps());
+ }
+
+ public static AbridgedModule from(Module module) {
+ return new AutoValue_AbridgedModule(
+ module.getName(), module.getVersion(), module.getKey(), module.getDeps());
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD
index fe9853f..749a238 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD
@@ -44,6 +44,7 @@
name = "module_extension",
srcs = [
"ModuleExtension.java",
+ "ModuleExtensionId.java",
"ModuleExtensionUsage.java",
"Tag.java",
"TagClass.java",
@@ -81,6 +82,7 @@
java_library(
name = "resolution",
srcs = [
+ "AbridgedModule.java",
"ArchiveOverride.java",
"BazelModuleResolutionValue.java",
"GitOverride.java",
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 8edde3b..76265cb 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
@@ -15,16 +15,24 @@
package com.google.devtools.build.lib.bazel.bzlmod;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableTable;
import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext;
+import com.google.devtools.build.lib.server.FailureDetails.ExternalDeps.Code;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
+import java.util.HashMap;
/**
* Runs Bazel module resolution. This function produces the dependency graph containing all Bazel
@@ -57,7 +65,9 @@
@VisibleForTesting
static BazelModuleResolutionValue createValue(
- ImmutableMap<ModuleKey, Module> depGraph, ImmutableMap<String, ModuleOverride> overrides) {
+ ImmutableMap<ModuleKey, Module> depGraph, ImmutableMap<String, ModuleOverride> overrides)
+ throws BazelModuleResolutionFunctionException {
+ // Build some reverse lookups for later use.
ImmutableMap<String, ModuleKey> canonicalRepoNameLookup =
depGraph.keySet().stream()
.collect(toImmutableMap(ModuleKey::getCanonicalRepoName, key -> key));
@@ -69,7 +79,58 @@
.filter(key -> !(overrides.get(key.getName()) instanceof MultipleVersionOverride))
.collect(toImmutableMap(ModuleKey::getName, key -> key));
- return BazelModuleResolutionValue.create(depGraph, canonicalRepoNameLookup, moduleNameLookup);
+ // For each extension usage, we resolve (i.e. canonicalize) its bzl file label. Then we can
+ // group all usages by the label + name (the ModuleExtensionId).
+ ImmutableTable.Builder<ModuleExtensionId, ModuleKey, ModuleExtensionUsage>
+ extensionUsagesTableBuilder = ImmutableTable.builder();
+ for (Module module : depGraph.values()) {
+ LabelConversionContext labelConversionContext =
+ new LabelConversionContext(
+ StarlarkBazelModule.createModuleRootLabel(module.getCanonicalRepoName()),
+ module.getRepoMappingWithBazelDepsOnly(),
+ new HashMap<>());
+ for (ModuleExtensionUsage usage : module.getExtensionUsages()) {
+ try {
+ ModuleExtensionId moduleExtensionId =
+ ModuleExtensionId.create(
+ labelConversionContext.convert(usage.getExtensionBzlFile()),
+ usage.getExtensionName());
+ extensionUsagesTableBuilder.put(moduleExtensionId, module.getKey(), usage);
+ } catch (LabelSyntaxException e) {
+ throw new BazelModuleResolutionFunctionException(
+ ExternalDepsException.withCauseAndMessage(
+ Code.BAD_MODULE,
+ e,
+ "invalid label for module extension found at %s",
+ usage.getLocation()),
+ Transience.PERSISTENT);
+ }
+ }
+ }
+ ImmutableTable<ModuleExtensionId, ModuleKey, ModuleExtensionUsage> extensionUsagesById =
+ extensionUsagesTableBuilder.build();
+
+ // Calculate a unique name for each used extension id.
+ BiMap<String, ModuleExtensionId> extensionUniqueNames = HashBiMap.create();
+ for (ModuleExtensionId id : extensionUsagesById.rowKeySet()) {
+ String bestName =
+ id.getBzlFileLabel().getRepository().strippedName() + "." + id.getExtensionName();
+ if (extensionUniqueNames.putIfAbsent(bestName, id) == null) {
+ continue;
+ }
+ int suffix = 2;
+ while (extensionUniqueNames.putIfAbsent(bestName + suffix, id) != null) {
+ suffix++;
+ }
+ }
+
+ return BazelModuleResolutionValue.create(
+ depGraph,
+ canonicalRepoNameLookup,
+ moduleNameLookup,
+ depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList()),
+ extensionUsagesById,
+ ImmutableMap.copyOf(extensionUniqueNames.inverse()));
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java
index 0a5bc1d..e8f39fb 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java
@@ -16,11 +16,16 @@
package com.google.devtools.build.lib.bazel.bzlmod;
import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableTable;
+import com.google.devtools.build.lib.cmdline.RepositoryMapping;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
+import java.util.Map;
/**
* The result of running Bazel module resolution, containing the Bazel module dependency graph
@@ -33,9 +38,17 @@
public static BazelModuleResolutionValue create(
ImmutableMap<ModuleKey, Module> depGraph,
ImmutableMap<String, ModuleKey> canonicalRepoNameLookup,
- ImmutableMap<String, ModuleKey> moduleNameLookup) {
+ ImmutableMap<String, ModuleKey> moduleNameLookup,
+ ImmutableList<AbridgedModule> abridgedModules,
+ ImmutableTable<ModuleExtensionId, ModuleKey, ModuleExtensionUsage> extensionUsagesTable,
+ ImmutableMap<ModuleExtensionId, String> extensionUniqueNames) {
return new AutoValue_BazelModuleResolutionValue(
- depGraph, canonicalRepoNameLookup, moduleNameLookup);
+ depGraph,
+ canonicalRepoNameLookup,
+ moduleNameLookup,
+ abridgedModules,
+ extensionUsagesTable,
+ extensionUniqueNames);
}
/**
@@ -52,4 +65,46 @@
* or modules with multiple-version overrides.
*/
public abstract ImmutableMap<String, ModuleKey> getModuleNameLookup();
+
+ /** All modules in the same order as {@link #getDepGraph}, but with limited information. */
+ public abstract ImmutableList<AbridgedModule> getAbridgedModules();
+
+ /**
+ * All module extension usages grouped by the extension's ID and the key of the module where this
+ * usage occurs. For each extension identifier ID, extensionUsagesTable[ID][moduleKey] is the
+ * ModuleExtensionUsage of ID in the module keyed by moduleKey.
+ */
+ public abstract ImmutableTable<ModuleExtensionId, ModuleKey, ModuleExtensionUsage>
+ getExtensionUsagesTable();
+
+ /**
+ * A mapping from the ID of a module extension to a unique string that serves as its "name". This
+ * is not the same as the extension's declared name, as the declared name is only unique within
+ * the .bzl file, whereas this unique name is guaranteed to be unique across the workspace.
+ */
+ public abstract ImmutableMap<ModuleExtensionId, String> getExtensionUniqueNames();
+
+ /**
+ * Returns the full {@link RepositoryMapping} for the given module, including repos from Bazel
+ * module deps and module extensions.
+ */
+ public final RepositoryMapping getFullRepoMapping(ModuleKey key) {
+ ImmutableMap.Builder<RepositoryName, RepositoryName> mapping = ImmutableMap.builder();
+ for (Map.Entry<ModuleExtensionId, ModuleExtensionUsage> e :
+ getExtensionUsagesTable().column(key).entrySet()) {
+ ModuleExtensionId extensionId = e.getKey();
+ ModuleExtensionUsage usage = e.getValue();
+ for (Map.Entry<String, String> entry : usage.getImports().entrySet()) {
+ String canonicalRepoName =
+ getExtensionUniqueNames().get(extensionId) + "." + entry.getValue();
+ mapping.put(
+ RepositoryName.createFromValidStrippedName(entry.getKey()),
+ RepositoryName.createFromValidStrippedName(canonicalRepoName));
+ }
+ }
+ return getDepGraph()
+ .get(key)
+ .getRepoMappingWithBazelDepsOnly()
+ .withAdditionalMappings(mapping.build());
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java
index d05f348..b9dbf77 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java
@@ -63,6 +63,10 @@
*/
public abstract ModuleKey getKey();
+ public final String getCanonicalRepoName() {
+ return getKey().getCanonicalRepoName();
+ }
+
/**
* The compatibility level of the module, which essentially signifies the "major version" of the
* module in terms of SemVer.
@@ -75,49 +79,36 @@
*/
public abstract ImmutableMap<String, ModuleKey> getDeps();
- /**
- * Used in {@link #getRepoMapping} to denote whether only repos from {@code bazel_dep}s should be
- * returned, or repos from module extensions should also be returned.
- */
- public enum WhichRepoMappings {
- BAZEL_DEPS_ONLY,
- WITH_MODULE_EXTENSIONS_TOO
- }
-
- /** Returns the {@link RepositoryMapping} for the repo corresponding to this module. */
- public final RepositoryMapping getRepoMapping(WhichRepoMappings whichRepoMappings) {
+ static RepositoryMapping getRepoMappingWithBazelDepsOnly(
+ ModuleKey key, String name, ImmutableMap<String, ModuleKey> deps) {
ImmutableMap.Builder<RepositoryName, RepositoryName> mapping = ImmutableMap.builder();
// If this is the root module, then the main repository should be visible as `@`.
- if (getKey().equals(ModuleKey.ROOT)) {
+ if (key.equals(ModuleKey.ROOT)) {
mapping.put(RepositoryName.MAIN, RepositoryName.MAIN);
}
// Every module should be able to reference itself as @<module name>.
// If this is the root module, this perfectly falls into @<module name> => @
- if (!getName().isEmpty()) {
+ if (!name.isEmpty()) {
mapping.put(
- RepositoryName.createFromValidStrippedName(getName()),
- RepositoryName.createFromValidStrippedName(getKey().getCanonicalRepoName()));
+ RepositoryName.createFromValidStrippedName(name),
+ RepositoryName.createFromValidStrippedName(key.getCanonicalRepoName()));
}
- for (Map.Entry<String, ModuleKey> dep : getDeps().entrySet()) {
+ for (Map.Entry<String, ModuleKey> dep : deps.entrySet()) {
// Special note: if `dep` is actually the root module, its ModuleKey would be ROOT whose
// canonicalRepoName is the empty string. This perfectly maps to the main repo ("@").
mapping.put(
RepositoryName.createFromValidStrippedName(dep.getKey()),
RepositoryName.createFromValidStrippedName(dep.getValue().getCanonicalRepoName()));
}
- if (whichRepoMappings.equals(WhichRepoMappings.WITH_MODULE_EXTENSIONS_TOO)) {
- for (ModuleExtensionUsage usage : getExtensionUsages()) {
- for (Map.Entry<String, String> entry : usage.getImports().entrySet()) {
- // TODO(wyv): work out a rigorous canonical repo name format (and potentially a shorter
- // version when ambiguities aren't present).
- String canonicalRepoName = usage.getExtensionName() + "." + entry.getValue();
- mapping.put(
- RepositoryName.createFromValidStrippedName(entry.getKey()),
- RepositoryName.createFromValidStrippedName(canonicalRepoName));
- }
- }
- }
- return RepositoryMapping.create(mapping.build(), getKey().getCanonicalRepoName());
+ return RepositoryMapping.create(mapping.build(), key.getCanonicalRepoName());
+ }
+
+ /**
+ * Returns a {@link RepositoryMapping} with only Bazel module repos and no repos from module
+ * extensions. For the full mapping, see {@link BazelModuleResolutionValue#getFullRepoMappings}.
+ */
+ public final RepositoryMapping getRepoMappingWithBazelDepsOnly() {
+ return getRepoMappingWithBazelDepsOnly(getKey(), getName(), getDeps());
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionId.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionId.java
new file mode 100644
index 0000000..9fef1ef
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionId.java
@@ -0,0 +1,31 @@
+// Copyright 2021 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package com.google.devtools.build.lib.bazel.bzlmod;
+
+import com.google.auto.value.AutoValue;
+import com.google.devtools.build.lib.cmdline.Label;
+
+/** A unique identifier for a {@link ModuleExtension}. */
+@AutoValue
+public abstract class ModuleExtensionId {
+ public abstract Label getBzlFileLabel();
+
+ public abstract String getExtensionName();
+
+ public static ModuleExtensionId create(Label bzlFileLabel, String extensionName) {
+ return new AutoValue_ModuleExtensionId(bzlFileLabel, extensionName);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModule.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModule.java
index 59237ece..dbbb032 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModule.java
@@ -15,8 +15,8 @@
package com.google.devtools.build.lib.bazel.bzlmod;
import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
-import com.google.devtools.build.lib.bazel.bzlmod.Module.WhichRepoMappings;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.RepositoryName;
@@ -84,27 +84,34 @@
}
/**
- * Creates a new {@link StarlarkBazelModule} object representing the given {@link Module}, with
- * its scope limited to the given {@link ModuleExtension}. It'll be populated with the tags
+ * Creates a label pointing to the root package of the repo with the given canonical repo name.
+ * This label can be used to anchor (relativize) labels with no "@foo" part.
+ */
+ static Label createModuleRootLabel(String canonicalRepoName) {
+ return Label.createUnvalidated(
+ PackageIdentifier.create(
+ RepositoryName.createFromValidStrippedName(canonicalRepoName),
+ PathFragment.EMPTY_FRAGMENT),
+ "unused_dummy_target_name");
+ }
+
+ /**
+ * Creates a new {@link StarlarkBazelModule} object representing the given {@link AbridgedModule},
+ * with its scope limited to the given {@link ModuleExtension}. It'll be populated with the tags
* present in the given {@link ModuleExtensionUsage}.
*/
public static StarlarkBazelModule create(
- Module module, ModuleExtension extension, ModuleExtensionUsage usage)
+ AbridgedModule module, ModuleExtension extension, @Nullable ModuleExtensionUsage usage)
throws ExternalDepsException {
- Label moduleRootLabel =
- Label.createUnvalidated(
- PackageIdentifier.create(
- RepositoryName.createFromValidStrippedName(module.getKey().getCanonicalRepoName()),
- PathFragment.EMPTY_FRAGMENT),
- "unused_dummy_target_name");
LabelConversionContext labelConversionContext =
new LabelConversionContext(
- moduleRootLabel,
- module.getRepoMapping(WhichRepoMappings.BAZEL_DEPS_ONLY),
+ createModuleRootLabel(module.getCanonicalRepoName()),
+ module.getRepoMapping(),
/* convertedLabelsInPackage= */ new HashMap<>());
+ ImmutableList<Tag> tags = usage == null ? ImmutableList.of() : usage.getTags();
ImmutableListMultimap.Builder<String, TypeCheckedTag> typeCheckedTags =
ImmutableListMultimap.builder();
- for (Tag tag : usage.getTags()) {
+ for (Tag tag : tags) {
TagClass tagClass = extension.getTagClasses().get(tag.getTagName());
if (tagClass == null) {
throw ExternalDepsException.withMessage(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java
index ed7cc7a..85604f3 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java
@@ -25,7 +25,6 @@
import com.google.common.hash.HashFunction;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue;
-import com.google.devtools.build.lib.bazel.bzlmod.Module.WhichRepoMappings;
import com.google.devtools.build.lib.bazel.bzlmod.ModuleKey;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelConstants;
@@ -866,7 +865,7 @@
return bazelModuleResolutionValue
.getDepGraph()
.get(moduleKey)
- .getRepoMapping(WhichRepoMappings.BAZEL_DEPS_ONLY);
+ .getRepoMappingWithBazelDepsOnly();
}
// We are fully done with workspace evaluation so we should get the mappings from the
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java
index 387f614..c5b391e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java
@@ -18,8 +18,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue;
-import com.google.devtools.build.lib.bazel.bzlmod.Module;
-import com.google.devtools.build.lib.bazel.bzlmod.Module.WhichRepoMappings;
import com.google.devtools.build.lib.bazel.bzlmod.ModuleKey;
import com.google.devtools.build.lib.cmdline.LabelConstants;
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
@@ -108,8 +106,7 @@
if (moduleKey == null) {
return Optional.empty();
}
- Module module = bazelModuleResolutionValue.getDepGraph().get(moduleKey);
- return Optional.of(module.getRepoMapping(WhichRepoMappings.WITH_MODULE_EXTENSIONS_TOO));
+ return Optional.of(bazelModuleResolutionValue.getFullRepoMapping(moduleKey));
}
private SkyValue computeFromWorkspace(
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 d610496..27ad8d7 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
@@ -15,11 +15,16 @@
package com.google.devtools.build.lib.bazel.bzlmod;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey;
+import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createRepositoryMapping;
+import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.cmdline.Label;
+import net.starlark.java.syntax.Location;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -94,5 +99,117 @@
.containsExactly(
"rules_cc", createModuleKey("rules_cc", "1.0"),
"rules_java", createModuleKey("rules_java", ""));
+ assertThat(value.getAbridgedModules())
+ .containsExactlyElementsIn(
+ depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList()));
+ }
+
+ private static ModuleExtensionUsage createModuleExtensionUsage(
+ String bzlFile, String name, String... imports) {
+ ImmutableBiMap.Builder<String, String> importsBuilder = ImmutableBiMap.builder();
+ for (int i = 0; i < imports.length; i += 2) {
+ importsBuilder.put(imports[i], imports[i + 1]);
+ }
+ return ModuleExtensionUsage.builder()
+ .setExtensionBzlFile(bzlFile)
+ .setExtensionName(name)
+ .setImports(importsBuilder.build())
+ .setLocation(Location.BUILTIN)
+ .build();
+ }
+
+ @Test
+ public void createValue_moduleExtensions() throws Exception {
+ Module root =
+ Module.builder()
+ .setName("root")
+ .setVersion(Version.parse("1.0"))
+ .setKey(ModuleKey.ROOT)
+ .addDep("rje", createModuleKey("rules_jvm_external", "1.0"))
+ .addDep("rpy", createModuleKey("rules_python", "2.0"))
+ .addExtensionUsage(
+ createModuleExtensionUsage("@rje//:defs.bzl", "maven", "av", "autovalue"))
+ .addExtensionUsage(
+ createModuleExtensionUsage("@rpy//:defs.bzl", "pip", "numpy", "numpy"))
+ .build();
+ ModuleKey depKey = createModuleKey("dep", "2.0");
+ Module dep =
+ Module.builder()
+ .setName("dep")
+ .setVersion(Version.parse("2.0"))
+ .setKey(depKey)
+ .addDep("rules_python", createModuleKey("rules_python", "2.0"))
+ .addExtensionUsage(
+ createModuleExtensionUsage("@rules_python//:defs.bzl", "pip", "np", "numpy"))
+ .addExtensionUsage(
+ createModuleExtensionUsage("//:defs.bzl", "myext", "oneext", "myext"))
+ .addExtensionUsage(
+ createModuleExtensionUsage("//incredible:conflict.bzl", "myext", "twoext", "myext"))
+ .build();
+ ImmutableMap<ModuleKey, Module> depGraph = ImmutableMap.of(ModuleKey.ROOT, root, depKey, dep);
+
+ ModuleExtensionId maven =
+ ModuleExtensionId.create(
+ Label.parseAbsoluteUnchecked("@rules_jvm_external.1.0//:defs.bzl"), "maven");
+ ModuleExtensionId pip =
+ ModuleExtensionId.create(
+ Label.parseAbsoluteUnchecked("@rules_python.2.0//:defs.bzl"), "pip");
+ ModuleExtensionId myext =
+ ModuleExtensionId.create(Label.parseAbsoluteUnchecked("@dep.2.0//:defs.bzl"), "myext");
+ ModuleExtensionId myext2 =
+ ModuleExtensionId.create(
+ Label.parseAbsoluteUnchecked("@dep.2.0//incredible:conflict.bzl"), "myext");
+
+ BazelModuleResolutionValue value =
+ BazelModuleResolutionFunction.createValue(depGraph, ImmutableMap.of());
+ assertThat(value.getExtensionUsagesTable()).hasSize(5);
+ assertThat(value.getExtensionUsagesTable())
+ .containsCell(maven, ModuleKey.ROOT, root.getExtensionUsages().get(0));
+ assertThat(value.getExtensionUsagesTable())
+ .containsCell(pip, ModuleKey.ROOT, root.getExtensionUsages().get(1));
+ assertThat(value.getExtensionUsagesTable())
+ .containsCell(pip, depKey, dep.getExtensionUsages().get(0));
+ assertThat(value.getExtensionUsagesTable())
+ .containsCell(myext, depKey, dep.getExtensionUsages().get(1));
+ assertThat(value.getExtensionUsagesTable())
+ .containsCell(myext2, depKey, dep.getExtensionUsages().get(2));
+
+ assertThat(value.getExtensionUniqueNames())
+ .containsExactly(
+ maven, "rules_jvm_external.1.0.maven",
+ pip, "rules_python.2.0.pip",
+ myext, "dep.2.0.myext",
+ myext2, "dep.2.0.myext2");
+
+ assertThat(value.getFullRepoMapping(ModuleKey.ROOT))
+ .isEqualTo(
+ createRepositoryMapping(
+ ModuleKey.ROOT,
+ "",
+ "",
+ "root",
+ "",
+ "rje",
+ "rules_jvm_external.1.0",
+ "rpy",
+ "rules_python.2.0",
+ "av",
+ "rules_jvm_external.1.0.maven.autovalue",
+ "numpy",
+ "rules_python.2.0.pip.numpy"));
+ assertThat(value.getFullRepoMapping(depKey))
+ .isEqualTo(
+ createRepositoryMapping(
+ depKey,
+ "dep",
+ "dep.2.0",
+ "rules_python",
+ "rules_python.2.0",
+ "np",
+ "rules_python.2.0.pip.numpy",
+ "oneext",
+ "dep.2.0.myext.myext",
+ "twoext",
+ "dep.2.0.myext2.myext"));
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java
index 3ef4e6b..e13c265 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java
@@ -18,9 +18,6 @@
import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey;
import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createRepositoryMapping;
-import com.google.common.collect.ImmutableBiMap;
-import com.google.devtools.build.lib.bazel.bzlmod.Module.WhichRepoMappings;
-import net.starlark.java.syntax.Location;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -58,15 +55,8 @@
.addDep("my_foo", createModuleKey("foo", "1.0"))
.addDep("my_bar", createModuleKey("bar", "2.0"))
.addDep("my_root", ModuleKey.ROOT)
- .addExtensionUsage(
- ModuleExtensionUsage.builder()
- .setExtensionBzlFile("//:defs.bzl")
- .setExtensionName("maven")
- .setLocation(Location.BUILTIN)
- .setImports(ImmutableBiMap.of("my_guava", "guava"))
- .build())
.build();
- assertThat(module.getRepoMapping(WhichRepoMappings.BAZEL_DEPS_ONLY))
+ assertThat(module.getRepoMappingWithBazelDepsOnly())
.isEqualTo(
createRepositoryMapping(
key,
@@ -78,20 +68,6 @@
"bar.2.0",
"my_root",
""));
- assertThat(module.getRepoMapping(WhichRepoMappings.WITH_MODULE_EXTENSIONS_TOO))
- .isEqualTo(
- createRepositoryMapping(
- key,
- "test_module",
- "test_module.1.0",
- "my_foo",
- "foo.1.0",
- "my_bar",
- "bar.2.0",
- "my_root",
- "",
- "my_guava",
- "maven.guava"));
}
@Test
@@ -104,7 +80,7 @@
.addDep("my_foo", createModuleKey("foo", "1.0"))
.addDep("my_bar", createModuleKey("bar", "2.0"))
.build();
- assertThat(module.getRepoMapping(WhichRepoMappings.BAZEL_DEPS_ONLY))
+ assertThat(module.getRepoMappingWithBazelDepsOnly())
.isEqualTo(
createRepositoryMapping(
ModuleKey.ROOT,
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java
index 224726b..04c9958 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java
@@ -81,14 +81,14 @@
.allowedFileTypes(FileTypeSet.ANY_FILE)
.build())))
.build();
- Module module =
- Module.builder()
- .setName("foo")
- .setVersion(Version.parse("1.0"))
- .setKey(createModuleKey("foo", ""))
- .addDep("bar", createModuleKey("bar", "2.0"))
- .addExtensionUsage(usage)
- .build();
+ AbridgedModule module =
+ AbridgedModule.from(
+ Module.builder()
+ .setName("foo")
+ .setVersion(Version.parse("1.0"))
+ .setKey(createModuleKey("foo", ""))
+ .addDep("bar", createModuleKey("bar", "2.0"))
+ .build());
StarlarkBazelModule moduleProxy = StarlarkBazelModule.create(module, extension, usage);
@@ -124,13 +124,13 @@
ModuleExtensionUsage usage = getBaseUsageBuilder().addTag(buildTag("blep").build()).build();
ModuleExtension extension =
getBaseExtensionBuilder().setTagClasses(ImmutableMap.of("dep", createTagClass())).build();
- Module module =
- Module.builder()
- .setName("foo")
- .setVersion(Version.parse("1.0"))
- .setKey(createModuleKey("foo", ""))
- .addExtensionUsage(usage)
- .build();
+ AbridgedModule module =
+ AbridgedModule.from(
+ Module.builder()
+ .setName("foo")
+ .setVersion(Version.parse("1.0"))
+ .setKey(createModuleKey("foo", ""))
+ .build());
ExternalDepsException e =
assertThrows(