Skip to content

Commit de37930

Browse files
Wyveraldcopybara-github
authored andcommitted
'@'-prefixed canonical repo names for Bzlmod repos
See https://docs.google.com/document/d/1N81qfCa8oskCk5LqTW-LNthy6EBrDot7bdUsjz6JFC4/edit#heading=h.z37pyziy8h33 * RepositoryName syntax is relaxed to allow an extra '@' in the beginning, signifying that the RepositoryName should bypass RepositoryMapping * All repos generated by Bzlmod will have an extra '@' prefixed to their names (except for well-known modules) * TODO: strip the '@' when generating paths under $outputBase/external or $execRoot/external Work towards #15593. RELNOTES: When Bzlmod is enabled, all Bzlmod-generated repos will have an extra '@' prepended to their names. This effectively enables the canonical label literal syntax for Bzlmod-generated repos (`@@canonicalRepoName//pkg:target`; see https://docs.google.com/document/d/1N81qfCa8oskCk5LqTW-LNthy6EBrDot7bdUsjz6JFC4/edit?usp=sharing). PiperOrigin-RevId: 454156392 Change-Id: I2fb08495f066cfd15cc344534925f674a63764f6
1 parent e123eaa commit de37930

19 files changed

+196
-177
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ static BazelModuleResolutionValue createValue(
160160
for (ModuleExtensionId id : extensionUsagesById.rowKeySet()) {
161161
String bestName =
162162
id.getBzlFileLabel().getRepository().getName() + "." + id.getExtensionName();
163+
if (!bestName.startsWith("@")) {
164+
// We have to special-case extensions hosted in well-known modules, because *all* repos
165+
// generated by Bzlmod have to have an '@'-prefixed name, except well-known modules.
166+
bestName = "@" + bestName;
167+
}
163168
if (extensionUniqueNames.putIfAbsent(bestName, id) == null) {
164169
continue;
165170
}

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,16 @@ public abstract class ModuleKey {
3131
* Therefore, we have to keep its canonical repository name the same as its well known repository
3232
* name. Eg. "@com_google_protobuf//:protoc" is used for --proto_compiler flag.
3333
*
34-
* <p>TODO(pcloudy): Remove this hack after figuring out a correct way to deal with the above
35-
* situation.
34+
* <p>NOTE(wyv): We don't prepend an '@' to the repo names of well-known modules. This is because
35+
* we still need the repo name to be 'bazel_tools' (not '@bazel_tools') since the command line
36+
* flags still don't go through repo mapping yet, and they're asking for '@bazel_tools//:thing',
37+
* not '@@bazel_tools//:thing'. We can't switch to the latter syntax because it doesn't work if
38+
* Bzlmod is not enabled. On the other hand, this means we cannot write '@@bazel_tools//:thing' to
39+
* bypass repo mapping at all, which can be awkward.
40+
*
41+
* <p>TODO(wyv): After we get rid of usage of com_google_protobuf in flag defaults, and make all
42+
* flag values go through repo mapping, we can remove the concept of well-known modules
43+
* altogether.
3644
*/
3745
private static final ImmutableMap<String, RepositoryName> WELL_KNOWN_MODULES =
3846
ImmutableMap.of(
@@ -69,9 +77,7 @@ public RepositoryName getCanonicalRepoName() {
6977
if (ROOT.equals(this)) {
7078
return RepositoryName.MAIN;
7179
}
72-
if (getVersion().isEmpty()) {
73-
return RepositoryName.createUnvalidated(getName() + ".override");
74-
}
75-
return RepositoryName.createUnvalidated(getName() + "." + getVersion());
80+
return RepositoryName.createUnvalidated(
81+
String.format("@%s.%s", getName(), getVersion().isEmpty() ? "override" : getVersion()));
7682
}
7783
}

src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,20 @@ public RepositoryMapping withAdditionalMappings(RepositoryMapping additionalMapp
8181
* Returns the canonical repository name associated with the given apparent repo name. The
8282
* provided apparent repo name is assumed to be valid.
8383
*/
84-
public RepositoryName get(String apparentRepoName) {
85-
RepositoryName canonicalRepoName = repositoryMapping().get(apparentRepoName);
84+
public RepositoryName get(String preMappingName) {
85+
if (preMappingName.startsWith("@")) {
86+
// The given name is actually a canonical, post-mapping repo name already.
87+
return RepositoryName.createUnvalidated(preMappingName);
88+
}
89+
RepositoryName canonicalRepoName = repositoryMapping().get(preMappingName);
8690
if (canonicalRepoName != null) {
8791
return canonicalRepoName;
8892
}
8993
// If the owner repo is not present, that means we should fall back to the requested repo name.
9094
if (ownerRepo() == null) {
91-
return RepositoryName.createUnvalidated(apparentRepoName);
95+
return RepositoryName.createUnvalidated(preMappingName);
9296
} else {
93-
return RepositoryName.createUnvalidated(apparentRepoName).toNonVisible(ownerRepo());
97+
return RepositoryName.createUnvalidated(preMappingName).toNonVisible(ownerRepo());
9498
}
9599
}
96100
}

src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public final class RepositoryName {
3737

3838
@SerializationConstant public static final RepositoryName MAIN = new RepositoryName("");
3939

40-
private static final Pattern VALID_REPO_NAME = Pattern.compile("[\\w\\-.]*");
40+
private static final Pattern VALID_REPO_NAME = Pattern.compile("@?[\\w\\-.#]*");
4141

4242
private static final LoadingCache<String, RepositoryName> repositoryNameCache =
4343
Caffeine.newBuilder()
@@ -49,8 +49,7 @@ public final class RepositoryName {
4949
});
5050

5151
/**
52-
* Makes sure that name is a valid repository name and creates a new RepositoryName using it. The
53-
* given string must not begin with a '@'.
52+
* Makes sure that name is a valid repository name and creates a new RepositoryName using it.
5453
*
5554
* @throws LabelSyntaxException if the name is invalid
5655
*/
@@ -66,11 +65,8 @@ public static RepositoryName create(String name) throws LabelSyntaxException {
6665
}
6766
}
6867

69-
/**
70-
* Creates a RepositoryName from a known-valid string. The given string must not begin with a '@'.
71-
*/
68+
/** Creates a RepositoryName from a known-valid string. */
7269
public static RepositoryName createUnvalidated(String name) {
73-
Preconditions.checkArgument(!name.startsWith("@"), "Do not prefix @ to repo names!");
7470
if (name.isEmpty()) {
7571
// NOTE(wyv): Without this `if` clause, a lot of Google-internal integration tests would start
7672
// failing. This suggests to me that something is comparing RepositoryName objects using
@@ -147,8 +143,8 @@ static void validate(String name) throws LabelSyntaxException {
147143

148144
if (!VALID_REPO_NAME.matcher(name).matches()) {
149145
throw LabelParser.syntaxErrorf(
150-
"invalid repository name '@%s': repo names may contain only A-Z, a-z, 0-9, '-', '_' and"
151-
+ " '.'",
146+
"invalid repository name '@%s': repo names may contain only A-Z, a-z, 0-9, '-', '_', '.'"
147+
+ " and '#'",
152148
StringUtilities.sanitizeControlChars(name));
153149
}
154150
}

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

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ public void createValue_basic() throws Exception {
9393
.containsExactly(
9494
RepositoryName.MAIN,
9595
ModuleKey.ROOT,
96-
RepositoryName.create("dep.1.0"),
96+
RepositoryName.create("@dep.1.0"),
9797
createModuleKey("dep", "1.0"),
98-
RepositoryName.create("dep.2.0"),
98+
RepositoryName.create("@dep.2.0"),
9999
createModuleKey("dep", "2.0"),
100-
RepositoryName.create("rules_cc.1.0"),
100+
RepositoryName.create("@rules_cc.1.0"),
101101
createModuleKey("rules_cc", "1.0"),
102-
RepositoryName.create("rules_java.override"),
102+
RepositoryName.create("@rules_java.override"),
103103
createModuleKey("rules_java", ""));
104104
assertThat(value.getModuleNameLookup())
105105
.containsExactly(
@@ -156,15 +156,14 @@ public void createValue_moduleExtensions() throws Exception {
156156

157157
ModuleExtensionId maven =
158158
ModuleExtensionId.create(
159-
Label.parseAbsoluteUnchecked("@rules_jvm_external.1.0//:defs.bzl"), "maven");
159+
Label.parseCanonical("@@rules_jvm_external.1.0//:defs.bzl"), "maven");
160160
ModuleExtensionId pip =
161-
ModuleExtensionId.create(
162-
Label.parseAbsoluteUnchecked("@rules_python.2.0//:defs.bzl"), "pip");
161+
ModuleExtensionId.create(Label.parseCanonical("@@rules_python.2.0//:defs.bzl"), "pip");
163162
ModuleExtensionId myext =
164-
ModuleExtensionId.create(Label.parseAbsoluteUnchecked("@dep.2.0//:defs.bzl"), "myext");
163+
ModuleExtensionId.create(Label.parseCanonical("@@dep.2.0//:defs.bzl"), "myext");
165164
ModuleExtensionId myext2 =
166165
ModuleExtensionId.create(
167-
Label.parseAbsoluteUnchecked("@dep.2.0//incredible:conflict.bzl"), "myext");
166+
Label.parseCanonical("@@dep.2.0//incredible:conflict.bzl"), "myext");
168167

169168
BazelModuleResolutionValue value =
170169
BazelModuleResolutionFunction.createValue(depGraph, depGraph, ImmutableMap.of());
@@ -182,10 +181,10 @@ public void createValue_moduleExtensions() throws Exception {
182181

183182
assertThat(value.getExtensionUniqueNames())
184183
.containsExactly(
185-
maven, "rules_jvm_external.1.0.maven",
186-
pip, "rules_python.2.0.pip",
187-
myext, "dep.2.0.myext",
188-
myext2, "dep.2.0.myext2");
184+
maven, "@rules_jvm_external.1.0.maven",
185+
pip, "@rules_python.2.0.pip",
186+
myext, "@dep.2.0.myext",
187+
myext2, "@dep.2.0.myext2");
189188

190189
assertThat(value.getFullRepoMapping(ModuleKey.ROOT))
191190
.isEqualTo(
@@ -196,26 +195,26 @@ public void createValue_moduleExtensions() throws Exception {
196195
"root",
197196
"",
198197
"rje",
199-
"rules_jvm_external.1.0",
198+
"@rules_jvm_external.1.0",
200199
"rpy",
201-
"rules_python.2.0",
200+
"@rules_python.2.0",
202201
"av",
203-
"rules_jvm_external.1.0.maven.autovalue",
202+
"@rules_jvm_external.1.0.maven.autovalue",
204203
"numpy",
205-
"rules_python.2.0.pip.numpy"));
204+
"@rules_python.2.0.pip.numpy"));
206205
assertThat(value.getFullRepoMapping(depKey))
207206
.isEqualTo(
208207
createRepositoryMapping(
209208
depKey,
210209
"dep",
211-
"dep.2.0",
210+
"@dep.2.0",
212211
"rules_python",
213-
"rules_python.2.0",
212+
"@rules_python.2.0",
214213
"np",
215-
"rules_python.2.0.pip.numpy",
214+
"@rules_python.2.0.pip.numpy",
216215
"oneext",
217-
"dep.2.0.myext.myext",
216+
"@dep.2.0.myext.myext",
218217
"twoext",
219-
"dep.2.0.myext2.myext"));
218+
"@dep.2.0.myext2.myext"));
220219
}
221220
}

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,18 @@ public void getRepoSpec_bazelModule() throws Exception {
147147
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
148148

149149
EvaluationResult<GetRepoSpecByNameValue> result =
150-
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C.2.0")), evaluationContext);
150+
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("@C.2.0")), evaluationContext);
151151
if (result.hasError()) {
152152
fail(result.getError().toString());
153153
}
154154

155-
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("C.2.0")).rule();
155+
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@C.2.0")).rule();
156156
assertThat(repoSpec)
157157
.hasValue(
158158
RepoSpec.builder()
159159
.setRuleClassName("local_repository")
160-
.setAttributes(ImmutableMap.of("name", "C.2.0", "path", "/usr/local/modules/C.2.0"))
160+
.setAttributes(
161+
ImmutableMap.of("name", "@C.2.0", "path", "/usr/local/modules/@C.2.0"))
161162
.build());
162163
}
163164

@@ -178,19 +179,20 @@ public void getRepoSpec_nonRegistryOverride() throws Exception {
178179
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
179180

180181
EvaluationResult<GetRepoSpecByNameValue> result =
181-
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C.override")), evaluationContext);
182+
evaluator.evaluate(
183+
ImmutableList.of(getRepoSpecByNameKey("@C.override")), evaluationContext);
182184
if (result.hasError()) {
183185
fail(result.getError().toString());
184186
}
185187

186-
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("C.override")).rule();
188+
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@C.override")).rule();
187189
assertThat(repoSpec)
188190
.hasValue(
189191
RepoSpec.builder()
190192
.setRuleClassName("local_repository")
191193
.setAttributes(
192194
ImmutableMap.of(
193-
"name", "C.override",
195+
"name", "@C.override",
194196
"path", "/foo/bar/C"))
195197
.build());
196198
}
@@ -214,12 +216,12 @@ public void getRepoSpec_singleVersionOverride() throws Exception {
214216
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
215217

216218
EvaluationResult<GetRepoSpecByNameValue> result =
217-
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C.3.0")), evaluationContext);
219+
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("@C.3.0")), evaluationContext);
218220
if (result.hasError()) {
219221
fail(result.getError().toString());
220222
}
221223

222-
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("C.3.0")).rule();
224+
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@C.3.0")).rule();
223225
assertThat(repoSpec)
224226
.hasValue(
225227
RepoSpec.builder()
@@ -230,9 +232,9 @@ public void getRepoSpec_singleVersionOverride() throws Exception {
230232
.setAttributes(
231233
ImmutableMap.of(
232234
"name",
233-
"C.3.0",
235+
"@C.3.0",
234236
"path",
235-
"/usr/local/modules/C.3.0",
237+
"/usr/local/modules/@C.3.0",
236238
"patches",
237239
ImmutableList.of("//:foo.patch"),
238240
"patch_args",
@@ -262,17 +264,18 @@ public void getRepoSpec_multipleVersionOverride() throws Exception {
262264
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
263265

264266
EvaluationResult<GetRepoSpecByNameValue> result =
265-
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("D.2.0")), evaluationContext);
267+
evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("@D.2.0")), evaluationContext);
266268
if (result.hasError()) {
267269
fail(result.getError().toString());
268270
}
269271

270-
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("D.2.0")).rule();
272+
Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@D.2.0")).rule();
271273
assertThat(repoSpec)
272274
.hasValue(
273275
RepoSpec.builder()
274276
.setRuleClassName("local_repository")
275-
.setAttributes(ImmutableMap.of("name", "D.2.0", "path", "/usr/local/modules/D.2.0"))
277+
.setAttributes(
278+
ImmutableMap.of("name", "@D.2.0", "path", "/usr/local/modules/@D.2.0"))
276279
.build());
277280
}
278281

0 commit comments

Comments
 (0)