Skip to content

Commit 7b5829e

Browse files
fmeumiancha1992
authored andcommitted
Record repo mapping entries for labels in module extension tags
The mapping of an apparent name in a module extension tag's `attr.label` attribute to the corresponding canonical name has to be recorded in the lockfile so that instantiated repo rules don't reference the stale repos. Fixes bazelbuild#25063 Closes bazelbuild#25067. PiperOrigin-RevId: 720592796 Change-Id: Ia202ca4a8482a81da8085ee18ecaca5fe233bddb
1 parent c6aaa3e commit 7b5829e

File tree

8 files changed

+150
-11
lines changed

8 files changed

+150
-11
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public abstract class BazelLockFileValue implements SkyValue {
3636

3737
// NOTE: See "HACK" note in BazelLockFileModule. While this hack exists, normal increments of the
3838
// lockfile version need to be done by 2 at a time (i.e. keep LOCK_FILE_VERSION an odd number).
39-
public static final int LOCK_FILE_VERSION = 11;
39+
public static final int LOCK_FILE_VERSION = 18;
4040

4141
@SerializationConstant public static final SkyKey KEY = () -> SkyFunctions.BAZEL_LOCK_FILE;
4242

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ private RunModuleExtensionResult runInternal(
272272
try (Mutability mu =
273273
Mutability.create("module extension", usagesValue.getExtensionUniqueName());
274274
ModuleExtensionContext moduleContext =
275-
createContext(env, usagesValue, starlarkSemantics, extensionId)) {
275+
createContext(env, usagesValue, starlarkSemantics, extensionId, repoMappingRecorder)) {
276276
StarlarkThread thread = new StarlarkThread(mu, starlarkSemantics);
277277
thread.setPrintHandler(Event.makeDebugPrintHandler(env.getListener()));
278278
threadContext.storeInThread(thread);
@@ -339,7 +339,8 @@ private ModuleExtensionContext createContext(
339339
Environment env,
340340
SingleExtensionUsagesValue usagesValue,
341341
StarlarkSemantics starlarkSemantics,
342-
ModuleExtensionId extensionId)
342+
ModuleExtensionId extensionId,
343+
Label.RepoMappingRecorder repoMappingRecorder)
343344
throws ExternalDepsException {
344345
Path workingDirectory =
345346
directories
@@ -354,7 +355,8 @@ private ModuleExtensionContext createContext(
354355
abridgedModule,
355356
extension,
356357
usagesValue.getRepoMappings().get(moduleKey),
357-
usagesValue.getExtensionUsages().get(moduleKey)));
358+
usagesValue.getExtensionUsages().get(moduleKey),
359+
repoMappingRecorder));
358360
}
359361
ModuleExtensionUsage rootUsage = usagesValue.getExtensionUsages().get(ModuleKey.ROOT);
360362
boolean rootModuleHasNonDevDependency =

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.common.collect.ImmutableMap;
2020
import com.google.common.collect.Maps;
2121
import com.google.devtools.build.docgen.annot.DocCategory;
22+
import com.google.devtools.build.lib.cmdline.Label;
2223
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
2324
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
2425
import com.google.devtools.build.lib.packages.LabelConverter;
@@ -107,12 +108,14 @@ public static StarlarkBazelModule create(
107108
AbridgedModule module,
108109
ModuleExtension extension,
109110
RepositoryMapping repoMapping,
110-
@Nullable ModuleExtensionUsage usage)
111+
@Nullable ModuleExtensionUsage usage,
112+
Label.RepoMappingRecorder repoMappingRecorder)
111113
throws ExternalDepsException {
112114
LabelConverter labelConverter =
113115
new LabelConverter(
114116
PackageIdentifier.create(repoMapping.ownerRepo(), PathFragment.EMPTY_FRAGMENT),
115-
repoMapping);
117+
repoMapping,
118+
repoMappingRecorder);
116119
ImmutableList<Tag> tags = usage == null ? ImmutableList.of() : usage.getTags();
117120
HashMap<String, ArrayList<TypeCheckedTag>> typeCheckedTags = new HashMap<>();
118121
for (String tagClassName : extension.getTagClasses().keySet()) {

src/main/java/com/google/devtools/build/lib/packages/LabelConverter.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
2222
import java.util.HashMap;
2323
import java.util.Map;
24+
import javax.annotation.Nullable;
2425
import net.starlark.java.eval.StarlarkThread;
2526

2627
/**
@@ -42,16 +43,35 @@ public static LabelConverter forBzlEvaluatingThread(StarlarkThread thread) {
4243

4344
private final Label.PackageContext packageContext;
4445
private final Map<String, Label> labelCache = new HashMap<>();
46+
@Nullable private final Label.RepoMappingRecorder repoMappingRecorder;
4547

46-
public LabelConverter(Label.PackageContext packageContext) {
48+
private LabelConverter(
49+
Label.PackageContext packageContext,
50+
@Nullable Label.RepoMappingRecorder repoMappingRecorder) {
4751
this.packageContext = packageContext;
52+
this.repoMappingRecorder = repoMappingRecorder;
53+
}
54+
55+
public LabelConverter(Label.PackageContext packageContext) {
56+
this(packageContext, null);
4857
}
4958

5059
/** Creates a label converter using the given base package and repo mapping. */
5160
public LabelConverter(PackageIdentifier base, RepositoryMapping repositoryMapping) {
5261
this(Label.PackageContext.of(base, repositoryMapping));
5362
}
5463

64+
/**
65+
* Creates a label converter using the given base package and repo mapping, recording all repo
66+
* mapping lookups in the given recorder.
67+
*/
68+
public LabelConverter(
69+
PackageIdentifier base,
70+
RepositoryMapping repositoryMapping,
71+
Label.RepoMappingRecorder repoMappingRecorder) {
72+
this(Label.PackageContext.of(base, repositoryMapping), repoMappingRecorder);
73+
}
74+
5575
/** Returns the base package identifier that relative labels will be resolved against. */
5676
PackageIdentifier getBasePackage() {
5777
return packageContext.packageIdentifier();
@@ -65,7 +85,7 @@ public Label convert(String input) throws LabelSyntaxException {
6585
// label-strings across all their attribute values.
6686
Label converted = labelCache.get(input);
6787
if (converted == null) {
68-
converted = Label.parseWithPackageContext(input, packageContext);
88+
converted = Label.parseWithPackageContext(input, packageContext, repoMappingRecorder);
6989
labelCache.put(input, converted);
7090
}
7191
return converted;

src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,24 @@ public void labels_passedOnToRepoRule() throws Exception {
894894
}
895895
assertThat(result.get(skyKey).getModule().getGlobal("data"))
896896
.isEqualTo("get up at 6am. go to bed at 11pm.");
897+
898+
SkyKey extensionSkyKey =
899+
SingleExtensionValue.key(
900+
ModuleExtensionId.create(
901+
Label.parseCanonicalUnchecked("@@ext+//:defs.bzl"), "ext", Optional.empty()));
902+
EvaluationResult<SingleExtensionValue> extensionResult =
903+
evaluator.evaluate(ImmutableList.of(extensionSkyKey), evaluationContext);
904+
if (extensionResult.hasError()) {
905+
throw extensionResult.getError().getException();
906+
}
907+
assertThat(
908+
extensionResult
909+
.get(extensionSkyKey)
910+
.lockFileInfo()
911+
.get()
912+
.moduleExtension()
913+
.getRecordedRepoMappingEntries())
914+
.containsCell(RepositoryName.create("foo+"), "bar", RepositoryName.create("bar+"));
897915
}
898916

899917
@Test

src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.common.collect.ImmutableList;
2727
import com.google.common.collect.ImmutableMap;
2828
import com.google.devtools.build.lib.cmdline.Label;
29+
import com.google.devtools.build.lib.cmdline.RepositoryName;
2930
import com.google.devtools.build.lib.packages.BuildType;
3031
import com.google.devtools.build.lib.packages.Type;
3132
import com.google.devtools.build.lib.util.FileTypeSet;
@@ -89,6 +90,7 @@ public void basic() throws Exception {
8990
Module module = buildModule("foo", "1.0").setKey(fooKey).addDep("bar", barKey).build();
9091
AbridgedModule abridgedModule = AbridgedModule.from(module);
9192

93+
Label.RepoMappingRecorder repoMappingRecorder = new Label.RepoMappingRecorder();
9294
StarlarkBazelModule moduleProxy =
9395
StarlarkBazelModule.create(
9496
abridgedModule,
@@ -97,7 +99,8 @@ public void basic() throws Exception {
9799
ImmutableMap.of(
98100
fooKey, fooKey.getCanonicalRepoNameWithoutVersionForTesting(),
99101
barKey, barKey.getCanonicalRepoNameWithoutVersionForTesting())),
100-
usage);
102+
usage,
103+
repoMappingRecorder);
101104

102105
assertThat(moduleProxy.getName()).isEqualTo("foo");
103106
assertThat(moduleProxy.getVersion()).isEqualTo("1.0");
@@ -124,6 +127,9 @@ public void basic() throws Exception {
124127
StarlarkList.immutableOf(
125128
Label.parseCanonical("@@foo~//:pom.xml"),
126129
Label.parseCanonical("@@bar~//:pom.xml")));
130+
131+
assertThat(repoMappingRecorder.recordedEntries())
132+
.containsCell(RepositoryName.create("foo+"), "bar", RepositoryName.create("bar+"));
127133
}
128134

129135
@Test
@@ -145,7 +151,8 @@ public void unknownTagClass() throws Exception {
145151
module.getRepoMappingWithBazelDepsOnly(
146152
ImmutableMap.of(
147153
fooKey, fooKey.getCanonicalRepoNameWithoutVersionForTesting())),
148-
usage));
154+
usage,
155+
new Label.RepoMappingRecorder()));
149156
assertThat(e).hasMessageThat().contains("does not have a tag class named blep");
150157
}
151158
}

src/test/py/bazel/bzlmod/bazel_lockfile_test.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,95 @@ def testExtensionRepoMappingChange_BzlInit(self):
18831883
self.assertNotIn('ran the extension!', stderr)
18841884
self.assertIn('STR=@@bar~//:lib_foo', stderr)
18851885

1886+
def testExtensionRepoMappingChange_tag(self):
1887+
# Regression test for #20721
1888+
self.main_registry.createCcModule('foo', '1.0')
1889+
self.main_registry.createCcModule('bar', '1.0')
1890+
self.ScratchFile(
1891+
'MODULE.bazel',
1892+
[
1893+
'bazel_dep(name="foo",version="1.0",repo_name="repo_name")',
1894+
'bazel_dep(name="bar",version="1.0")',
1895+
'ext = use_extension(":ext.bzl", "ext")',
1896+
'ext.tag(label = "@repo_name//:lib_foo")',
1897+
'use_repo(ext, "repo")',
1898+
],
1899+
)
1900+
self.ScratchFile(
1901+
'BUILD.bazel',
1902+
[
1903+
'load("@repo//:defs.bzl", "STR")',
1904+
'print("STR="+STR)',
1905+
'filegroup(name="lol")',
1906+
],
1907+
)
1908+
self.ScratchFile(
1909+
'ext.bzl',
1910+
[
1911+
'def _repo_impl(rctx):',
1912+
' rctx.file("BUILD")',
1913+
' rctx.file("defs.bzl", "STR = " + repr(str(rctx.attr.value)))',
1914+
'repo = repository_rule(_repo_impl,attrs={"value":attr.label()})',
1915+
'def _ext_impl(mctx):',
1916+
' print("ran the extension!")',
1917+
' repo(name = "repo", value = mctx.modules[0].tags.tag[0].label)',
1918+
'tag = tag_class(',
1919+
' attrs = {',
1920+
' "label": attr.label(),',
1921+
' },',
1922+
')',
1923+
'ext = module_extension(_ext_impl, tag_classes={"tag": tag})',
1924+
],
1925+
)
1926+
1927+
_, _, stderr = self.RunBazel(['build', ':lol'])
1928+
self.assertIn('STR=@@foo+//:lib_foo', '\n'.join(stderr))
1929+
1930+
# Shutdown bazel to make sure we rely on the lockfile and not skyframe
1931+
self.RunBazel(['shutdown'])
1932+
_, _, stderr = self.RunBazel(['build', ':lol'])
1933+
self.assertNotIn('ran the extension!', '\n'.join(stderr))
1934+
1935+
# Shutdown bazel to make sure we rely on the lockfile and not skyframe
1936+
self.RunBazel(['shutdown'])
1937+
# Now, for something spicy: let repo_name point to bar and change nothing
1938+
# else. The extension should rerun despite the lockfile being present, and
1939+
# no usages or .bzl files having changed.
1940+
self.ScratchFile(
1941+
'MODULE.bazel',
1942+
[
1943+
'bazel_dep(name="foo",version="1.0")',
1944+
'bazel_dep(name="bar",version="1.0",repo_name="repo_name")',
1945+
'ext = use_extension(":ext.bzl", "ext")',
1946+
'ext.tag(label = "@repo_name//:lib_foo")',
1947+
'use_repo(ext, "repo")',
1948+
],
1949+
)
1950+
_, _, stderr = self.RunBazel(['build', ':lol'])
1951+
stderr = '\n'.join(stderr)
1952+
self.assertIn('ran the extension!', stderr)
1953+
self.assertIn('STR=@@bar+//:lib_foo', stderr)
1954+
1955+
# Shutdown bazel to make sure we rely on the lockfile and not skyframe
1956+
self.RunBazel(['shutdown'])
1957+
# More spicy! change the repo_name of foo, but nothing else.
1958+
# The extension should NOT rerun, since it never used the @other_name repo
1959+
# mapping.
1960+
self.ScratchFile(
1961+
'MODULE.bazel',
1962+
[
1963+
'bazel_dep(name="foo",version="1.0",repo_name="other_name")',
1964+
'bazel_dep(name="bar",version="1.0",repo_name="repo_name")',
1965+
'ext = use_extension(":ext.bzl", "ext")',
1966+
'ext.tag(label = "@repo_name//:lib_foo")',
1967+
'use_repo(ext, "repo")',
1968+
],
1969+
)
1970+
_, _, stderr = self.RunBazel(['build', ':lol'])
1971+
stderr = '\n'.join(stderr)
1972+
self.assertNotIn('ran the extension!', stderr)
1973+
self.assertIn('STR=@@bar+//:lib_foo', stderr)
1974+
18861975
def testExtensionRepoMappingChange_loadsAndRepoRelativeLabels(self):
18871976
# Regression test for #20721; same test as above, except that the call to
18881977
# Label() in ext.bzl is now moved to @{foo,bar}//:defs.bzl and doesn't

src/test/tools/bzlmod/MODULE.bazel.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)