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..147191af51be6b 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 @@ -21,6 +21,7 @@ import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Objects; +import java.util.Optional; import javax.annotation.concurrent.Immutable; /** @@ -177,6 +178,50 @@ 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 local 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.ownerRepo() == null) { + // If the main repository mapping is not using strict visibility, then Bzlmod is certainly + // disabled, which means that canonical and local 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 local name the + // main repository has for it, otherwise fall back to a canonical label. + return mainRepositoryMapping.getInverse(repository) + .map(localName -> "@" + localName + "//" + 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..0a95cb6b6b8342 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,14 @@ public RepositoryName get(String preMappingName) { return RepositoryName.createUnvalidated(preMappingName).toNonVisible(ownerRepo()); } } + + /** + * 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