From aa55c4df164e9a7be0ee592a10b35f505256b213 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 30 Aug 2023 00:48:57 -0700 Subject: [PATCH] Add private `subrules` param to `rule()` and `aspect()` Rules or aspects that invoke a subrule must declare them in the `subrules` parameter PiperOrigin-RevId: 561258778 Change-Id: Id228c26ba09bf4f0677116ac5b804b927e5c087a --- .../BazelRuleAnalysisThreadContext.java | 4 + .../starlark/StarlarkRuleClassFunctions.java | 22 +++++- .../starlark/StarlarkRuleContext.java | 10 +++ .../analysis/starlark/StarlarkSubrule.java | 23 +++++- .../build/lib/packages/AspectDefinition.java | 21 ++++- .../build/lib/packages/RuleClass.java | 28 ++++++- .../lib/packages/StarlarkDefinedAspect.java | 7 +- .../lib/rules/test/StarlarkTestingModule.java | 3 +- .../StarlarkRuleFunctionsApi.java | 22 +++++- .../FakeStarlarkRuleFunctionsApi.java | 2 + .../starlark/StarlarkSubruleTest.java | 76 ++++++++++++++++++- .../build/lib/packages/RuleClassTest.java | 3 +- 12 files changed, 204 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BazelRuleAnalysisThreadContext.java b/src/main/java/com/google/devtools/build/lib/analysis/BazelRuleAnalysisThreadContext.java index 4e0bcf9cdc0fb0..abf90641c9e00c 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BazelRuleAnalysisThreadContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/BazelRuleAnalysisThreadContext.java @@ -52,6 +52,10 @@ public String getContextForUncheckedException() { return ruleContext.getLabel().toString(); } + public RuleContext getRuleContext() { + return ruleContext; + } + /** * Retrieves this context from a Starlark thread. * 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 f43430a95356bb..2931ff22c5aa49 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 @@ -303,6 +303,7 @@ public StarlarkRuleFunction rule( Object buildSetting, Object cfg, Object execGroups, + Sequence subrules, StarlarkThread thread) throws EvalException { // Ensure we're initializing a .bzl file, which also means we have a RuleDefinitionEnvironment. @@ -314,6 +315,10 @@ public StarlarkRuleFunction rule( LabelConverter labelConverter = LabelConverter.forBzlEvaluatingThread(thread); + if (!subrules.isEmpty()) { + BuiltinRestriction.failIfCalledOutsideAllowlist(thread, ALLOWLIST_SUBRULES); + } + return createRule( // Contextual parameters. bazelContext, @@ -339,7 +344,8 @@ public StarlarkRuleFunction rule( analysisTest, buildSetting, cfg, - execGroups); + execGroups, + subrules); } /** @@ -377,7 +383,8 @@ public static StarlarkRuleFunction createRule( Object analysisTest, Object buildSetting, Object cfg, - Object execGroups) + Object execGroups, + Sequence subrules) throws EvalException { // analysis_test=true implies test=true. @@ -523,6 +530,9 @@ public static StarlarkRuleFunction createRule( parseExecCompatibleWith(execCompatibleWith, labelConverter)); } + builder.setSubrules( + Sequence.cast(subrules, StarlarkSubruleApi.class, "subrules").getImmutableList()); + return new StarlarkRuleFunction( builder, type, @@ -586,6 +596,7 @@ public StarlarkAspect aspect( Boolean applyToGeneratingRules, Sequence rawExecCompatibleWith, Object rawExecGroups, + Sequence subrules, StarlarkThread thread) throws EvalException { LabelConverter labelConverter = LabelConverter.forBzlEvaluatingThread(thread); @@ -705,6 +716,10 @@ public StarlarkAspect aspect( } } + if (!subrules.isEmpty()) { + BuiltinRestriction.failIfCalledOutsideAllowlist(thread, ALLOWLIST_SUBRULES); + } + return new StarlarkDefinedAspect( implementation, Starlark.toJavaOptional(doc, String.class).map(Starlark::trimDocString), @@ -720,7 +735,8 @@ public StarlarkAspect aspect( parseToolchainTypes(toolchains, labelConverter), applyToGeneratingRules, execCompatibleWith, - execGroups); + execGroups, + ImmutableSet.copyOf(Sequence.cast(subrules, StarlarkSubruleApi.class, "subrules"))); } /** diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleContext.java index 50f93b34fdf303..cb02362cce6417 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleContext.java @@ -76,6 +76,7 @@ import com.google.devtools.build.lib.shell.ShellUtils; import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException; import com.google.devtools.build.lib.starlarkbuildapi.StarlarkRuleContextApi; +import com.google.devtools.build.lib.starlarkbuildapi.StarlarkSubruleApi; import com.google.devtools.build.lib.starlarkbuildapi.platform.ToolchainContextApi; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; @@ -298,6 +299,15 @@ public StarlarkRuleContext(RuleContext ruleContext, @Nullable AspectDescriptor a } } + /** Returns the subrules declared by the rule or aspect represented by this context. */ + ImmutableSet getSubrules() { + if (isForAspect()) { + return getRuleContext().getMainAspect().getDefinition().getSubrules(); + } else { + return getRuleContext().getRule().getRuleClassObject().getSubrules(); + } + } + /** * Represents `ctx.outputs`. * diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubrule.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubrule.java index 58f056c84b179e..3055e9f15858d2 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubrule.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubrule.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.analysis.starlark; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.analysis.BazelRuleAnalysisThreadContext; import com.google.devtools.build.lib.starlarkbuildapi.StarlarkSubruleApi; import net.starlark.java.eval.Dict; @@ -43,12 +44,32 @@ public String getName() { @Override public Object call(StarlarkThread thread, Tuple args, Dict kwargs) throws EvalException, InterruptedException { - BazelRuleAnalysisThreadContext.fromOrFail(thread, getName()); + StarlarkRuleContext ruleContext = + BazelRuleAnalysisThreadContext.fromOrFail(thread, getName()) + .getRuleContext() + .getStarlarkRuleContext(); + ImmutableSet declaredSubrules = ruleContext.getSubrules(); + if (!declaredSubrules.contains(this)) { + throw getUndeclaredSubruleError(ruleContext); + } SubruleContext subruleContext = new SubruleContext(); ImmutableList positionals = ImmutableList.builder().add(subruleContext).addAll(args).build(); return Starlark.call(thread, implementation, positionals, kwargs); } + private EvalException getUndeclaredSubruleError(StarlarkRuleContext starlarkRuleContext) { + if (starlarkRuleContext.isForAspect()) { + return Starlark.errorf( + "aspect '%s' must declare '%s' in 'subrules'", + starlarkRuleContext.getRuleContext().getMainAspect().getAspectClass().getName(), + this.getName()); + } else { + return Starlark.errorf( + "rule '%s' must declare '%s' in 'subrules'", + starlarkRuleContext.getRuleContext().getRule().getRuleClass(), this.getName()); + } + } + private static class SubruleContext {} } diff --git a/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java b/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java index 47a91190212ab4..516db17ddfd156 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java +++ b/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java @@ -28,6 +28,7 @@ import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy; import com.google.devtools.build.lib.packages.Type.LabelClass; import com.google.devtools.build.lib.packages.Type.LabelVisitor; +import com.google.devtools.build.lib.starlarkbuildapi.StarlarkSubruleApi; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Collection; import java.util.HashSet; @@ -83,6 +84,7 @@ public final class AspectDefinition { private final ImmutableSet