Cleanup in StarlarkRuleClassFunctions
- Removed the TODO about labelCache being copied from ConfiguredRuleClassProvider. The latter no longer has such a cache, so the TODO is outdated anyways. Replaced with a more descriptive comment.
- labelCache now uses the new Label#parseCanonical method.
- Removed an unused constructor.
- The `label` function now uses the new Label#parseWithRepoContext method and is no longer "surprisingly complex". Note that we don't actually need to cache these labels since calls to `Label(...)` are fairly rare.
PiperOrigin-RevId: 447445194
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
index c691632..115f500 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
@@ -27,7 +27,6 @@
import static com.google.devtools.build.lib.packages.Type.STRING;
import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
-import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.base.Preconditions;
@@ -54,7 +53,6 @@
import com.google.devtools.build.lib.cmdline.BazelModuleContext;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
-import com.google.devtools.build.lib.cmdline.LabelValidator;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.events.Event;
@@ -93,7 +91,6 @@
import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.packages.Type;
-import com.google.devtools.build.lib.packages.Type.ConversionException;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
import com.google.devtools.build.lib.starlarkbuildapi.StarlarkRuleFunctionsApi;
import com.google.devtools.build.lib.util.FileType;
@@ -121,23 +118,9 @@
/** A helper class to provide an easier API for Starlark rule definitions. */
public class StarlarkRuleClassFunctions implements StarlarkRuleFunctionsApi<Artifact> {
- // TODO(bazel-team): Copied from ConfiguredRuleClassProvider for the transition from built-in
- // rules to Starlark extensions. Using the same instance would require a large refactoring.
- // If we don't want to support old built-in rules and Starlark simultaneously
- // (except for transition phase) it's probably OK.
+ // A cache for base rule classes (especially tests).
private static final LoadingCache<String, Label> labelCache =
- Caffeine.newBuilder()
- .build(
- new CacheLoader<String, Label>() {
- @Override
- public Label load(String from) throws Exception {
- try {
- return Label.parseAbsolute(from, /* repositoryMapping= */ ImmutableMap.of());
- } catch (LabelSyntaxException e) {
- throw new Exception(from, e);
- }
- }
- });
+ Caffeine.newBuilder().build(Label::parseCanonical);
// TODO(bazel-team): Remove the code duplication (BaseRuleClasses and this class).
/** Parent rule class for non-executable non-test Starlark rules. */
@@ -718,21 +701,6 @@
this.definitionLocation = definitionLocation;
}
- /** This is for post-export reconstruction for serialization. */
- private StarlarkRuleFunction(
- RuleClass ruleClass, RuleClassType type, Location definitionLocation, Label starlarkLabel) {
- Preconditions.checkNotNull(
- ruleClass,
- "RuleClass must be non-null as this StarlarkRuleFunction should have been exported.");
- Preconditions.checkNotNull(
- starlarkLabel,
- "Label must be non-null as this StarlarkRuleFunction should have been exported.");
- this.ruleClass = ruleClass;
- this.type = type;
- this.definitionLocation = definitionLocation;
- this.starlarkLabel = starlarkLabel;
- }
-
@Override
public String getName() {
return ruleClass != null ? ruleClass.getName() : "unexported rule";
@@ -740,7 +708,7 @@
@Override
public Object call(StarlarkThread thread, Tuple args, Dict<String, Object> kwargs)
- throws EvalException, InterruptedException, ConversionException {
+ throws EvalException, InterruptedException {
if (!args.isEmpty()) {
throw new EvalException("unexpected positional arguments");
}
@@ -965,42 +933,13 @@
@Override
public Label label(String labelString, StarlarkThread thread) throws EvalException {
- // This function is surprisingly complex.
- //
- // - The logic to find the "current repo" is rather magical, using dynamic scope:
- // introspection on the call stack. This is an obstacle to removing GlobalFrame.
- //
- // An alternative way to implement that would be to say that each BUILD/.bzl file
- // has its own function value called Label that is a closure over the current
- // file label. (That would mean that if you export the Label function from a.bzl
- // file and load it into b.bzl, it would behave differently from the Label function
- // predeclared in b.bzl, so the choice of implementation strategy is observable.
- // However this case is not important in practice.)
- // TODO(adonovan): use this alternative implementation.
- //
- // - Logically all we really need from this process is a RepoID, not a Label
- // or PackageID, but the Label class doesn't yet have the necessary primitives.
- // TODO(adonovan): augment the Label class.
- //
- // - When repository mapping does occur, the result is converted back to a string
- // "unambiguous" canonical form and then parsed again by the cache, with
- // no repo mapping.
- // TODO(adonovan): augment the Label class so that we can validate, remap,
- // and cache without needing four allocations (parseAbsoluteLabel,
- // getRelativeWithRemapping, getUnambiguousCanonicalForm, parseAbsoluteLabel
- // in labelCache)
BazelModuleContext moduleContext =
BazelModuleContext.of(Module.ofInnermostEnclosingStarlarkFunction(thread));
try {
- LabelValidator.parseAbsoluteLabel(labelString);
- labelString =
- moduleContext
- .label()
- .getRelativeWithRemapping(labelString, moduleContext.repoMapping())
- .getUnambiguousCanonicalForm();
- return labelCache.get(labelString);
- } catch (LabelValidator.BadLabelException | LabelSyntaxException e) {
- throw Starlark.errorf("Illegal absolute label syntax: %s", labelString);
+ return Label.parseWithRepoContext(
+ labelString, moduleContext.label().getRepository(), moduleContext.repoMapping());
+ } catch (LabelSyntaxException e) {
+ throw Starlark.errorf("Illegal absolute label syntax: %s", e.getMessage());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
index 1a7e72b..210c618 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
@@ -80,13 +80,12 @@
private static final Interner<Label> LABEL_INTERNER = BlazeInterners.newWeakInterner();
- // TODO(b/200024947): Make this public.
/**
* Parses a raw label string that contains the canonical form of a label. It must be of the form
* {@code [@repo]//foo/bar[:quux]}. If the {@code @repo} part is present, it must be a canonical
* repo name, otherwise the label will be assumed to be in the main repo.
*/
- static Label parseCanonical(String raw) throws LabelSyntaxException {
+ public static Label parseCanonical(String raw) throws LabelSyntaxException {
Parts parts = Parts.parse(raw);
parts.checkPkgIsAbsolute();
RepositoryName repoName =
@@ -107,13 +106,12 @@
return repoMapping.get(RepositoryName.createUnvalidated(parts.repo));
}
- // TODO(b/200024947): Make this public.
/**
* Parses a raw label string within the context of a current repo. It must be of the form {@code
* [@repo]//foo/bar[:quux]}. If the {@code @repo} part is present, it will undergo {@code
* repoMapping}, otherwise the label will be assumed to be in {@code currentRepo}.
*/
- static Label parseWithRepoContext(
+ public static Label parseWithRepoContext(
String raw, RepositoryName currentRepo, RepositoryMapping repoMapping)
throws LabelSyntaxException {
Parts parts = Parts.parse(raw);
@@ -123,7 +121,6 @@
PackageIdentifier.create(repoName, PathFragment.create(parts.pkg)), parts.target);
}
- // TODO(b/200024947): Make this public.
/**
* Parses a raw label string within the context of a current package. It can be of a
* package-relative form ({@code :quux}). Otherwise, it must be of the form {@code
@@ -131,7 +128,7 @@
* repoMapping}, otherwise the label will be assumed to be in the repo of {@code
* packageIdentifier}.
*/
- static Label parseWithPackageContext(
+ public static Label parseWithPackageContext(
String raw, PackageIdentifier packageIdentifier, RepositoryMapping repoMapping)
throws LabelSyntaxException {
Parts parts = Parts.parse(raw);