Skip to content

Commit 71787cf

Browse files
fmeumcopybara-github
authored andcommitted
Cover missing cases during module extension label normalization
The previous logic missed to normalize cases such as `"extension.bzl"` and `"//extension.bzl"`, thus resulting in crashes if these styles are mixed as well as invalid buildozer commands for `use_repo` fixing. Instead of enumerating cases, parse the label and emit it in unambiguous canonical form with a leading `@` stripped. Closes #20482. PiperOrigin-RevId: 592666970 Change-Id: Ieea34b27a187545a11107a334bbae14fef974ae8
1 parent 605a05a commit 71787cf

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@
2929
import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileGlobals.ModuleExtensionUsageBuilder.ModuleExtensionProxy;
3030
import com.google.devtools.build.lib.bazel.bzlmod.Version.ParseException;
3131
import com.google.devtools.build.lib.cmdline.Label;
32+
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
33+
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
34+
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
3235
import com.google.devtools.build.lib.cmdline.RepositoryName;
3336
import com.google.devtools.build.lib.events.EventHandler;
3437
import com.google.devtools.build.lib.packages.StarlarkExportable;
38+
import com.google.devtools.build.lib.vfs.PathFragment;
3539
import java.util.ArrayList;
3640
import java.util.HashMap;
3741
import java.util.LinkedHashMap;
@@ -480,17 +484,31 @@ public ModuleExtensionProxy useExtension(
480484
}
481485

482486
private String normalizeLabelString(String rawExtensionBzlFile) {
483-
// Normalize the label by adding the current module's repo_name if the label doesn't specify a
484-
// repository name. This is necessary as ModuleExtensionUsages are grouped by the string value
485-
// of this label, but later mapped to their Label representation. If multiple strings map to the
486-
// same Label, this would result in a crash.
487+
// Normalize the label by parsing and stringifying it with a repo mapping that preserves the
488+
// apparent repository name, except that a reference to the main repository via the empty
489+
// repo name is translated to using the module repo name. This is necessary as
490+
// ModuleExtensionUsages are grouped by the string value of this label, but later mapped to
491+
// their Label representation. If multiple strings map to the same Label, this would result in a
492+
// crash.
487493
// ownName can't change anymore as calling module() after this results in an error.
488494
String ownName = module.getRepoName().orElse(module.getName());
489-
if (module.getKey().equals(ModuleKey.ROOT) && rawExtensionBzlFile.startsWith("@//")) {
490-
return "@" + ownName + rawExtensionBzlFile.substring(1);
491-
} else if (rawExtensionBzlFile.startsWith("//")) {
492-
return "@" + ownName + rawExtensionBzlFile;
493-
} else {
495+
RepositoryName ownRepoName = RepositoryName.createUnvalidated(ownName);
496+
try {
497+
ImmutableMap<String, RepositoryName> repoMapping = ImmutableMap.of();
498+
if (module.getKey().equals(ModuleKey.ROOT)) {
499+
repoMapping = ImmutableMap.of("", ownRepoName);
500+
}
501+
Label label =
502+
Label.parseWithPackageContext(
503+
rawExtensionBzlFile,
504+
Label.PackageContext.of(
505+
PackageIdentifier.create(ownRepoName, PathFragment.EMPTY_FRAGMENT),
506+
RepositoryMapping.createAllowingFallback(repoMapping)));
507+
// Skip over the leading "@" of the unambiguous form.
508+
return label.getUnambiguousCanonicalForm().substring(1);
509+
} catch (LabelSyntaxException ignored) {
510+
// Preserve backwards compatibility by not failing eagerly, rather keep the invalid label and
511+
// let the extension fail when evaluated.
494512
return rawExtensionBzlFile;
495513
}
496514
}

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,10 @@ public void simpleExtension_nonCanonicalLabel() throws Exception {
363363
"use_repo(ext2, 'bar')",
364364
"ext3 = use_extension('@//:defs.bzl', 'ext')",
365365
"ext3.tag(name='quz', data='qu')",
366-
"use_repo(ext3, 'quz')");
366+
"use_repo(ext3, 'quz')",
367+
"ext4 = use_extension('defs.bzl', 'ext')",
368+
"ext4.tag(name='qor', data='qo')",
369+
"use_repo(ext4, 'qor')");
367370
scratch.file(
368371
workspaceRoot.getRelative("defs.bzl").getPathString(),
369372
"load('@data_repo//:defs.bzl','data_repo')",
@@ -379,15 +382,17 @@ public void simpleExtension_nonCanonicalLabel() throws Exception {
379382
"load('@foo//:data.bzl', foo_data='data')",
380383
"load('@bar//:data.bzl', bar_data='data')",
381384
"load('@quz//:data.bzl', quz_data='data')",
382-
"data = 'foo:'+foo_data+' bar:'+bar_data+' quz:'+quz_data");
385+
"load('@qor//:data.bzl', qor_data='data')",
386+
"data = 'foo:'+foo_data+' bar:'+bar_data+' quz:'+quz_data+' qor:'+qor_data");
383387

384388
SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
385389
EvaluationResult<BzlLoadValue> result =
386390
evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
387391
if (result.hasError()) {
388392
throw result.getError().getException();
389393
}
390-
assertThat(result.get(skyKey).getModule().getGlobal("data")).isEqualTo("foo:fu bar:ba quz:qu");
394+
assertThat(result.get(skyKey).getModule().getGlobal("data"))
395+
.isEqualTo("foo:fu bar:ba quz:qu qor:qo");
391396
}
392397

393398
@Test

0 commit comments

Comments
 (0)