diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java b/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java index 82ea54975275ab..da4b7ae74e2720 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java @@ -177,6 +177,53 @@ public String getCanonicalForm() { return repository.getCanonicalForm() + "//" + getPackageFragment(); } + /** + * Returns an absolutely unambiguous canonical form for this package in label form. Parsing this + * string in any environment, even when subject to repository mapping, should identify the same + * package. + */ + public String getUnambiguousCanonicalForm() { + return String.format("@@%s//%s", getRepository().getName(), getPackageFragment()); + } + + /** + * Returns a label representation for this package that is suitable for display. The returned + * string is as simple as possible while referencing the current package when parsed in the + * context of the main repository. + * + * @param mainRepositoryMapping the {@link RepositoryMapping} of the main repository + * @return + *
+ *
//some/pkg + *
if this package lives in the main repository + *
@protobuf//some/pkg + *
if this package lives in a repository with "protobuf" as name of a + * repository in WORKSPACE or as apparent name of a Bzlmod dependency of the main module + *
@@protobuf~3.19.2//some/pkg + *
only with Bzlmod if the current package belongs to a repository that is not visible + * from the main module + */ + public String getDisplayForm(RepositoryMapping mainRepositoryMapping) { + Preconditions.checkArgument( + mainRepositoryMapping.ownerRepo() == null || mainRepositoryMapping.ownerRepo().isMain()); + if (repository.isMain()) { + // Packages in the main repository can always use repo-relative form. + return "//" + getPackageFragment(); + } + if (!mainRepositoryMapping.usesStrictDeps()) { + // If the main repository mapping is not using strict visibility, then Bzlmod is certainly + // disabled, which means that canonical and apparent names can be used interchangeably from + // the context of the main repository. + return repository.getNameWithAt() + "//" + getPackageFragment(); + } + // If possible, represent the repository with a non-canonical label using the apparent name the + // main repository has for it, otherwise fall back to a canonical label. + return mainRepositoryMapping + .getInverse(repository) + .map(apparentName -> "@" + apparentName + "//" + getPackageFragment()) + .orElseGet(this::getUnambiguousCanonicalForm); + } + /** * Returns the package path, possibly qualified with a repository name. * diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java index e504ff95f39d8c..3a2889c324236a 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java @@ -19,6 +19,8 @@ import com.google.common.collect.ImmutableMap; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; import javax.annotation.Nullable; /** @@ -93,4 +95,22 @@ public RepositoryName get(String preMappingName) { return RepositoryName.createUnvalidated(preMappingName).toNonVisible(ownerRepo()); } } + + /** + * Whether the repo with this mapping is subject to strict deps; when strict deps is off, unknown + * apparent names are silently treated as canonical names. + */ + public boolean usesStrictDeps() { + return ownerRepo() != null; + } + + /** + * Returns the first apparent name in this mapping that maps to the given canonical name, if any. + */ + public Optional getInverse(RepositoryName postMappingName) { + return repositoryMapping().entrySet().stream() + .filter(e -> e.getValue().equals(postMappingName)) + .map(Entry::getKey) + .findFirst(); + } } diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java index a73a3d38f20d15..ac0caafce97ab3 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/Package.java +++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java @@ -248,6 +248,13 @@ public enum ConfigSettingVisibilityPolicy { */ private RepositoryMapping repositoryMapping; + /** + * The repository mapping of the main repository. This is only used internally to obtain + * user-friendly apparent names from canonical repository names in error message arising from this + * package. + */ + private RepositoryMapping mainRepositoryMapping; + private Set