Skip to content

Commit 99b3f38

Browse files
WyveraldSalmaSamyShreeM01
authored
[6.2.0] Add native.module_{name,version} (bazelbuild#17893)
* Remove BzlmodRepoRuleHelper The helper logic is only used in the BzlmodRepoRuleFunction so no need to have it in a separate place. - Remove BzlmodRepoRuleHelper Interface & its implementations - Refactor BzlmodRepoRuleFunction to use the helper logic - Update tests and Build files accordingly PiperOrigin-RevId: 486712547 Change-Id: I9a274a6a0afcc77be56bbe20e0c4d17c41c31c58 * Separate selection from bazel dependency graph * Created new K/F/V for Bazel dependency graph named "BazelDepGraph" * Refactored "BazelModuleResolution" to only run resolution (discovery, selection and checks) to create pruned and unpruned graph and not create any dependency value * BazelDepGraphResolution calls BazelModuleResolution and extracts the dependency graph from it * Updated tests PiperOrigin-RevId: 499026445 Change-Id: Id1237f9d09015ffe8987d933431fccfcfa0c0963 * Add native.module_{name,version} Extension authors often want to write some macro and change its behavior depending on which module is using it. For example, for rules_go, they want to look at the `go_deps` tags in a certain module and only allow access to repos generated from those tags. We do this by introducing two new methods on `native`, callable only during the loading phase. They return the name and version of the module associated with the current repo. If the repo is from WORKSPACE, they return `None`. If the repo is generated by an extension, they return info about the module hosting the extension. The implementation works by storing the "associated module" information in `RepositoryMappingValue`. I had attempted to store them in `BzlmodRepoRuleValue` or even `RepositoryDirectoryValue`, but those are not the right places since they might happen before we even evaluate the MODULE.bazel file (i.e. for non-registry overrides). Fixes bazelbuild#17652. RELNOTES: Added `native.module_name()` and `native.module_version()` to allow BUILD macro authors to acquire information about which Bazel module the current repo is associated with. PiperOrigin-RevId: 518849334 Change-Id: I06b4bc95b5a57de2412ee02544240b054c708165 * fix BUILD * remove test case that was accidentally cherry-picked --------- Co-authored-by: salma-samy <[email protected]> Co-authored-by: kshyanashree <[email protected]>
1 parent 10792ce commit 99b3f38

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1353
-1391
lines changed

src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
2626
import com.google.devtools.build.lib.analysis.RuleDefinition;
2727
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
28+
import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction;
2829
import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorFunction;
2930
import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorValue.AugmentedModule.ResolutionReason;
3031
import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction;
@@ -248,8 +249,9 @@ public ResolutionReason getResolutionReason() {
248249
.addSkyFunction(
249250
SkyFunctions.MODULE_FILE,
250251
new ModuleFileFunction(registryFactory, directories.getWorkspace(), builtinModules))
251-
.addSkyFunction(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction())
252+
.addSkyFunction(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction())
252253
.addSkyFunction(SkyFunctions.BAZEL_MODULE_INSPECTION, new BazelModuleInspectorFunction())
254+
.addSkyFunction(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction())
253255
.addSkyFunction(SkyFunctions.SINGLE_EXTENSION_EVAL, singleExtensionEvalFunction)
254256
.addSkyFunction(SkyFunctions.SINGLE_EXTENSION_USAGES, new SingleExtensionUsagesFunction());
255257
filesystem = runtime.getFileSystem();

src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD

+2-18
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ java_library(
8585
srcs = [
8686
"AbridgedModule.java",
8787
"ArchiveOverride.java",
88+
"BazelDepGraphValue.java",
8889
"BazelModuleResolutionValue.java",
8990
"GitOverride.java",
9091
"LocalPathOverride.java",
@@ -125,6 +126,7 @@ java_library(
125126
java_library(
126127
name = "resolution_impl",
127128
srcs = [
129+
"BazelDepGraphFunction.java",
128130
"BazelModuleResolutionFunction.java",
129131
"Discovery.java",
130132
"ModuleExtensionContext.java",
@@ -191,24 +193,6 @@ java_library(
191193
],
192194
)
193195

194-
java_library(
195-
name = "repo_rule_helper",
196-
srcs = [
197-
"BzlmodRepoRuleHelper.java",
198-
"BzlmodRepoRuleHelperImpl.java",
199-
],
200-
deps = [
201-
":common",
202-
":registry",
203-
":resolution",
204-
"//src/main/java/com/google/devtools/build/lib/cmdline",
205-
"//src/main/java/com/google/devtools/build/lib/events",
206-
"//src/main/java/com/google/devtools/build/skyframe",
207-
"//third_party:guava",
208-
"//third_party:jsr305",
209-
],
210-
)
211-
212196
java_library(
213197
name = "repo_rule_creator",
214198
srcs = ["BzlmodRepoRuleCreator.java"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2022 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
package com.google.devtools.build.lib.bazel.bzlmod;
17+
18+
import static com.google.common.collect.ImmutableList.toImmutableList;
19+
import static com.google.common.collect.ImmutableMap.toImmutableMap;
20+
21+
import com.google.common.collect.BiMap;
22+
import com.google.common.collect.HashBiMap;
23+
import com.google.common.collect.ImmutableMap;
24+
import com.google.common.collect.ImmutableTable;
25+
import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction.BazelModuleResolutionFunctionException;
26+
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
27+
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
28+
import com.google.devtools.build.lib.cmdline.RepositoryName;
29+
import com.google.devtools.build.lib.packages.LabelConverter;
30+
import com.google.devtools.build.lib.server.FailureDetails.ExternalDeps.Code;
31+
import com.google.devtools.build.lib.vfs.PathFragment;
32+
import com.google.devtools.build.skyframe.SkyFunction;
33+
import com.google.devtools.build.skyframe.SkyFunctionException;
34+
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
35+
import com.google.devtools.build.skyframe.SkyKey;
36+
import com.google.devtools.build.skyframe.SkyValue;
37+
import javax.annotation.Nullable;
38+
39+
/**
40+
* This function runs Bazel module resolution, extracts the dependency graph from it and creates a
41+
* value containing all Bazel modules, along with a few lookup maps that help with further usage. By
42+
* this stage, module extensions are not evaluated yet.
43+
*/
44+
public class BazelDepGraphFunction implements SkyFunction {
45+
46+
@Override
47+
@Nullable
48+
public SkyValue compute(SkyKey skyKey, Environment env)
49+
throws SkyFunctionException, InterruptedException {
50+
51+
BazelModuleResolutionValue selectionResult =
52+
(BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY);
53+
if (env.valuesMissing()) {
54+
return null;
55+
}
56+
57+
ImmutableMap<ModuleKey, Module> depGraph = selectionResult.getResolvedDepGraph();
58+
ImmutableMap<RepositoryName, ModuleKey> canonicalRepoNameLookup =
59+
depGraph.keySet().stream()
60+
.collect(toImmutableMap(ModuleKey::getCanonicalRepoName, key -> key));
61+
62+
// For each extension usage, we resolve (i.e. canonicalize) its bzl file label. Then we can
63+
// group all usages by the label + name (the ModuleExtensionId).
64+
ImmutableTable.Builder<ModuleExtensionId, ModuleKey, ModuleExtensionUsage>
65+
extensionUsagesTableBuilder = ImmutableTable.builder();
66+
for (Module module : depGraph.values()) {
67+
LabelConverter labelConverter =
68+
new LabelConverter(
69+
PackageIdentifier.create(module.getCanonicalRepoName(), PathFragment.EMPTY_FRAGMENT),
70+
module.getRepoMappingWithBazelDepsOnly());
71+
for (ModuleExtensionUsage usage : module.getExtensionUsages()) {
72+
try {
73+
ModuleExtensionId moduleExtensionId =
74+
ModuleExtensionId.create(
75+
labelConverter.convert(usage.getExtensionBzlFile()), usage.getExtensionName());
76+
extensionUsagesTableBuilder.put(moduleExtensionId, module.getKey(), usage);
77+
} catch (LabelSyntaxException e) {
78+
throw new BazelModuleResolutionFunctionException(
79+
ExternalDepsException.withCauseAndMessage(
80+
Code.BAD_MODULE,
81+
e,
82+
"invalid label for module extension found at %s",
83+
usage.getLocation()),
84+
Transience.PERSISTENT);
85+
}
86+
}
87+
}
88+
ImmutableTable<ModuleExtensionId, ModuleKey, ModuleExtensionUsage> extensionUsagesById =
89+
extensionUsagesTableBuilder.buildOrThrow();
90+
91+
// Calculate a unique name for each used extension id.
92+
BiMap<String, ModuleExtensionId> extensionUniqueNames = HashBiMap.create();
93+
for (ModuleExtensionId id : extensionUsagesById.rowKeySet()) {
94+
// Ensure that the resulting extension name (and thus the repository names derived from it) do
95+
// not start with a tilde.
96+
RepositoryName repository = id.getBzlFileLabel().getRepository();
97+
String nonEmptyRepoPart;
98+
if (repository.isMain()) {
99+
nonEmptyRepoPart = "_main";
100+
} else {
101+
nonEmptyRepoPart = repository.getName();
102+
}
103+
String bestName = nonEmptyRepoPart + "~" + id.getExtensionName();
104+
if (extensionUniqueNames.putIfAbsent(bestName, id) == null) {
105+
continue;
106+
}
107+
int suffix = 2;
108+
while (extensionUniqueNames.putIfAbsent(bestName + suffix, id) != null) {
109+
suffix++;
110+
}
111+
}
112+
113+
return BazelDepGraphValue.create(
114+
depGraph,
115+
canonicalRepoNameLookup,
116+
depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList()),
117+
extensionUsagesById,
118+
ImmutableMap.copyOf(extensionUniqueNames.inverse()));
119+
}
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2022 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
package com.google.devtools.build.lib.bazel.bzlmod;
17+
18+
import com.google.auto.value.AutoValue;
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.common.collect.ImmutableMap;
21+
import com.google.common.collect.ImmutableTable;
22+
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
23+
import com.google.devtools.build.lib.cmdline.RepositoryName;
24+
import com.google.devtools.build.lib.skyframe.SkyFunctions;
25+
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
26+
import com.google.devtools.build.skyframe.SkyKey;
27+
import com.google.devtools.build.skyframe.SkyValue;
28+
import java.util.Map;
29+
30+
/**
31+
* The result of running Bazel module resolution, containing the Bazel module dependency graph
32+
* post-version-resolution.
33+
*/
34+
@AutoValue
35+
public abstract class BazelDepGraphValue implements SkyValue {
36+
@SerializationConstant public static final SkyKey KEY = () -> SkyFunctions.BAZEL_DEP_GRAPH;
37+
38+
public static BazelDepGraphValue create(
39+
ImmutableMap<ModuleKey, Module> depGraph,
40+
ImmutableMap<RepositoryName, ModuleKey> canonicalRepoNameLookup,
41+
ImmutableList<AbridgedModule> abridgedModules,
42+
ImmutableTable<ModuleExtensionId, ModuleKey, ModuleExtensionUsage> extensionUsagesTable,
43+
ImmutableMap<ModuleExtensionId, String> extensionUniqueNames) {
44+
return new AutoValue_BazelDepGraphValue(
45+
depGraph,
46+
canonicalRepoNameLookup,
47+
abridgedModules,
48+
extensionUsagesTable,
49+
extensionUniqueNames);
50+
}
51+
52+
/**
53+
* The post-selection dep graph. Must have BFS iteration order, starting from the root module. For
54+
* any KEY in the returned map, it's guaranteed that {@code depGraph[KEY].getKey() == KEY}.
55+
*/
56+
public abstract ImmutableMap<ModuleKey, Module> getDepGraph();
57+
58+
/** A mapping from a canonical repo name to the key of the module backing it. */
59+
public abstract ImmutableMap<RepositoryName, ModuleKey> getCanonicalRepoNameLookup();
60+
61+
/** All modules in the same order as {@link #getDepGraph}, but with limited information. */
62+
public abstract ImmutableList<AbridgedModule> getAbridgedModules();
63+
64+
/**
65+
* All module extension usages grouped by the extension's ID and the key of the module where this
66+
* usage occurs. For each extension identifier ID, extensionUsagesTable[ID][moduleKey] is the
67+
* ModuleExtensionUsage of ID in the module keyed by moduleKey.
68+
*/
69+
public abstract ImmutableTable<ModuleExtensionId, ModuleKey, ModuleExtensionUsage>
70+
getExtensionUsagesTable();
71+
72+
/**
73+
* A mapping from the ID of a module extension to a unique string that serves as its "name". This
74+
* is not the same as the extension's declared name, as the declared name is only unique within
75+
* the .bzl file, whereas this unique name is guaranteed to be unique across the workspace.
76+
*/
77+
public abstract ImmutableMap<ModuleExtensionId, String> getExtensionUniqueNames();
78+
79+
/**
80+
* Returns the full {@link RepositoryMapping} for the given module, including repos from Bazel
81+
* module deps and module extensions.
82+
*/
83+
public final RepositoryMapping getFullRepoMapping(ModuleKey key) {
84+
ImmutableMap.Builder<String, RepositoryName> mapping = ImmutableMap.builder();
85+
for (Map.Entry<ModuleExtensionId, ModuleExtensionUsage> e :
86+
getExtensionUsagesTable().column(key).entrySet()) {
87+
ModuleExtensionId extensionId = e.getKey();
88+
ModuleExtensionUsage usage = e.getValue();
89+
for (Map.Entry<String, String> entry : usage.getImports().entrySet()) {
90+
String canonicalRepoName =
91+
getExtensionUniqueNames().get(extensionId) + "~" + entry.getValue();
92+
mapping.put(entry.getKey(), RepositoryName.createUnvalidated(canonicalRepoName));
93+
}
94+
}
95+
return getDepGraph()
96+
.get(key)
97+
.getRepoMappingWithBazelDepsOnly()
98+
.withAdditionalMappings(mapping.buildOrThrow());
99+
}
100+
}

src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public SkyValue compute(SkyKey skyKey, Environment env)
5656
}
5757
ImmutableMap<String, ModuleOverride> overrides = root.getOverrides();
5858
ImmutableMap<ModuleKey, Module> unprunedDepGraph = resolutionValue.getUnprunedDepGraph();
59-
ImmutableMap<ModuleKey, Module> resolvedDepGraph = resolutionValue.getDepGraph();
59+
ImmutableMap<ModuleKey, Module> resolvedDepGraph = resolutionValue.getResolvedDepGraph();
6060

6161
ImmutableMap<ModuleKey, AugmentedModule> depGraph =
6262
computeAugmentedGraph(unprunedDepGraph, resolvedDepGraph.keySet(), overrides);

0 commit comments

Comments
 (0)