| // Copyright 2025 The Bazel Authors. All rights reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package com.google.devtools.build.lib.starlark; | |
| import static com.google.common.collect.ImmutableList.toImmutableList; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static com.google.devtools.build.lib.packages.Attribute.attr; | |
| import static com.google.devtools.build.lib.packages.BuildType.LABEL; | |
| import static java.util.stream.Collectors.joining; | |
| import static org.junit.Assert.assertThrows; | |
| import com.google.common.base.Splitter; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.devtools.build.lib.analysis.ConfiguredAspect; | |
| import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; | |
| import com.google.devtools.build.lib.analysis.RuleDefinition; | |
| import com.google.devtools.build.lib.analysis.ViewCreationFailedException; | |
| import com.google.devtools.build.lib.analysis.config.BuildOptions; | |
| import com.google.devtools.build.lib.analysis.config.Fragment; | |
| import com.google.devtools.build.lib.analysis.config.FragmentOptions; | |
| import com.google.devtools.build.lib.analysis.config.RequiresOptions; | |
| import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; | |
| import com.google.devtools.build.lib.analysis.util.DummyTestFragment; | |
| import com.google.devtools.build.lib.analysis.util.DummyTestFragment.DummyTestOptions; | |
| import com.google.devtools.build.lib.analysis.util.MockRule; | |
| import com.google.devtools.build.lib.cmdline.Label; | |
| import com.google.devtools.build.lib.packages.AspectClass; | |
| import com.google.devtools.build.lib.packages.Attribute.LabelLateBoundDefault; | |
| import com.google.devtools.build.lib.packages.StarlarkAspectClass; | |
| import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey; | |
| import com.google.devtools.build.lib.testutil.TestRuleClassProvider; | |
| import com.google.devtools.common.options.OptionsClass; | |
| import java.util.Map; | |
| import net.starlark.java.eval.Sequence; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.JUnit4; | |
| /** Tests for Starlark aspects {@code attr_aspects} function. */ | |
| @RunWith(JUnit4.class) | |
| public final class StarlarkAspectAttrAspectsFunctionTest extends AnalysisTestCase { | |
| private void createTestDefs(String propagationAttrsFunction, String propagationPredicateFunction) | |
| throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| String.format( | |
| """ | |
| AspectInfo = provider() | |
| def _rule_impl(ctx): | |
| pass | |
| simple_rule = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| 'deps_1': attr.label_list(), | |
| 'deps_2': attr.label_list(), | |
| '_tool': attr.label(default = Label('//pkg1:rule_tool'))}, | |
| ) | |
| tool_rule = rule( | |
| implementation = _rule_impl, | |
| ) | |
| %s | |
| %s | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on ' + str(target.label)] | |
| rule_attr = ctx.rule.attr | |
| for dep in (getattr(rule_attr, 'deps_1', []) + getattr(rule_attr, 'deps_2', [])): | |
| if AspectInfo in dep: | |
| res.extend(dep[AspectInfo].res) | |
| if hasattr(rule_attr, '_tool') and AspectInfo in rule_attr._tool: | |
| res.extend(rule_attr._tool[AspectInfo].res) | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| propagation_predicate = _propagation_predicate, | |
| ) | |
| """, | |
| propagationAttrsFunction, propagationPredicateFunction)); | |
| } | |
| private void createTestDefs(String propagationAttrsFunction) throws Exception { | |
| createTestDefs( | |
| propagationAttrsFunction, | |
| """ | |
| def _propagation_predicate(ctx): | |
| return True | |
| """); | |
| } | |
| private void createTestPackages() throws Exception { | |
| scratch.file( | |
| "config_setting/BUILD", "config_setting(name='defines', values={'define': 'foo=1'})"); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'simple_rule', 'tool_rule') | |
| simple_rule(name = 't1', deps_1 = [':d1'], deps_2 = [':d2']) | |
| simple_rule(name = 'd1', deps_1 = [':d11'], deps_2 = [':d12']) | |
| simple_rule(name = 'd2', deps_2 = [':d22']) | |
| simple_rule(name = 'd11') | |
| simple_rule(name = 'd12') | |
| simple_rule(name = 'd22') | |
| tool_rule(name = 'rule_tool') | |
| simple_rule( | |
| name = 'with_selects', | |
| deps_1 = select({ | |
| '//config_setting:defines': [':d1'], | |
| '//conditions:default': ['d2'], | |
| }) | |
| ) | |
| simple_rule(name = 't2', deps_1 = [':d1', ':d11'], deps_2 = [':d2']) | |
| """); | |
| } | |
| @Test | |
| public void selectedAttrsReturned_aspectPropagatesAlongReturnedAttrs() throws Exception { | |
| createTestDefs( | |
| """ | |
| def _propagation_attrs(ctx): | |
| if ctx.rule.label == Label('//pkg1:t1'): | |
| attr_aspects = [] | |
| for attr_name in dir(ctx.rule.attr): | |
| attr_value = getattr(ctx.rule.attr, attr_name).value | |
| if type(attr_value) == type(Label("//foo")): | |
| attr_aspects.append(attr_name) | |
| if type(attr_value) == type([]): | |
| if len(attr_value) > 0 and type(attr_value[0]) == type(Label("//foo")): | |
| attr_aspects.append(attr_name) | |
| return attr_aspects | |
| else: | |
| return [] | |
| """); | |
| createTestPackages(); | |
| var analysisResult = update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:t1"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:t1", | |
| "cmdline_aspect on //pkg1:d1", | |
| "cmdline_aspect on //pkg1:d2", | |
| "cmdline_aspect on //pkg1:rule_tool"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:t1", | |
| "cmdline_aspect on @@//pkg1:d1", | |
| "cmdline_aspect on @@//pkg1:d2", | |
| "cmdline_aspect on @@//pkg1:rule_tool"); | |
| } | |
| @Test | |
| public void wildCardAttrReturned_buildFails() throws Exception { | |
| createTestDefs( | |
| """ | |
| def _propagation_attrs(ctx): | |
| return ['*'] | |
| """); | |
| createTestPackages(); | |
| reporter.removeHandler(failFastHandler); | |
| assertThrows( | |
| ViewCreationFailedException.class, | |
| () -> update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:t1")); | |
| assertContainsEvent("'*' is not allowed in 'attr_aspects' list"); | |
| } | |
| @Test | |
| public void invalidReturnValue_buildFails() throws Exception { | |
| createTestDefs( | |
| """ | |
| def _propagation_attrs(ctx): | |
| return [44, 'foo'] | |
| """); | |
| createTestPackages(); | |
| reporter.removeHandler(failFastHandler); | |
| assertThrows( | |
| ViewCreationFailedException.class, | |
| () -> update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:t1")); | |
| assertContainsEvent("at index 0 of attr_aspects, got element of type int, want string"); | |
| } | |
| @Test | |
| public void withPropagationPredicate_aspectPropagatedToSatisfyingTargets() throws Exception { | |
| createTestDefs( | |
| """ | |
| def _propagation_attrs(ctx): | |
| return ['deps_1'] | |
| """, | |
| """ | |
| def _propagation_predicate(ctx): | |
| if ctx.rule.label == Label('//pkg1:d1'): | |
| return False | |
| return True | |
| """); | |
| createTestPackages(); | |
| var analysisResult = update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:t2"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly("cmdline_aspect on //pkg1:t2", "cmdline_aspect on //pkg1:d11"); | |
| var aspectAResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectAResult) | |
| .containsExactly("cmdline_aspect on @@//pkg1:t2", "cmdline_aspect on @@//pkg1:d11"); | |
| } | |
| @Test | |
| public void aspectApplyToGeneratingRule_attrAspectsFuncRunOnGeneratingRule() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| if ctx.rule.label == Label('//pkg1:target_with_output'): | |
| if ctx.rule.attr.out.value == Label('//pkg1:my_out.txt'): | |
| return ['deps'] | |
| return [] | |
| def _aspect_impl(target, ctx): | |
| res = ['generating_rule_aspect on ' + str(target.label)] | |
| rule_attr = ctx.rule.attr | |
| for dep in getattr(rule_attr, 'deps', []): | |
| if AspectInfo in dep: | |
| res.extend(dep[AspectInfo].res) | |
| return [AspectInfo(res = res)] | |
| generating_rule_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| apply_to_generating_rules = True, | |
| ) | |
| def _out_rule_impl(ctx): | |
| if ctx.outputs.out: | |
| ctx.actions.write(ctx.outputs.out, 'hi') | |
| return [] | |
| out_rule = rule( | |
| implementation = _out_rule_impl, | |
| attrs = {'deps': attr.label_list(), 'out': attr.output()}, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'out_rule') | |
| out_rule(name = 'target_with_output', out = 'my_out.txt', deps = [':d1']) | |
| out_rule(name = 'd1') | |
| """); | |
| var analysisResult = | |
| update(ImmutableList.of("//test:defs.bzl%generating_rule_aspect"), "//pkg1:my_out.txt"); | |
| assertThat(getFormattedAspectKeys("generating_rule_aspect")) | |
| .containsExactly( | |
| "generating_rule_aspect on //pkg1:my_out.txt", | |
| "generating_rule_aspect on //pkg1:target_with_output", | |
| "generating_rule_aspect on //pkg1:d1"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "generating_rule_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "generating_rule_aspect on @@//pkg1:target_with_output", | |
| "generating_rule_aspect on @@//pkg1:d1"); | |
| } | |
| @Test | |
| public void attrWithSelect_availableToAttrAspectsFunc() throws Exception { | |
| createTestDefs( | |
| """ | |
| def _propagation_attrs(ctx): | |
| deps_1 = ctx.rule.attr.deps_1.value | |
| if len(deps_1) == 1 and deps_1[0] == Label('//pkg1:d1'): | |
| return ['deps_1'] | |
| return [] | |
| """); | |
| createTestPackages(); | |
| useConfiguration("--define=foo=1"); | |
| var analysisResult = | |
| update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:with_selects"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly("cmdline_aspect on //pkg1:with_selects", "cmdline_aspect on //pkg1:d1"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:with_selects", "cmdline_aspect on @@//pkg1:d1"); | |
| } | |
| @Test | |
| public void computedDefaultAttr_availableToAttrAspectsFunc() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| if hasattr(ctx.rule.attr, '_computed'): | |
| cmp = ctx.rule.attr._computed.value | |
| if Label('//pkg1:my_prefix01') in cmp and Label('//pkg1:my_prefix02') in cmp: | |
| return ['_computed'] | |
| return [] | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on ' + str(target.label)] | |
| rule_attr = ctx.rule.attr | |
| for dep in getattr(rule_attr, '_computed', []): | |
| if AspectInfo in dep: | |
| res.extend(dep[AspectInfo].res) | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| ) | |
| def _compute_attr(prefix): | |
| return [ | |
| Label("//pkg1:" + prefix + "01"), | |
| Label("//pkg1:" + prefix + "02"), | |
| ] | |
| def _rule_impl(ctx): | |
| pass | |
| computed_default_rule = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| "prefix": attr.string(default = "default_prefix"), | |
| "_computed": attr.label_list(default = _compute_attr), | |
| }, | |
| ) | |
| simple_rule = rule( | |
| implementation = _rule_impl, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'computed_default_rule', 'simple_rule') | |
| computed_default_rule(name = 'computed_default_target', prefix = 'my_prefix') | |
| simple_rule(name = 'my_prefix01') | |
| simple_rule(name = 'my_prefix02') | |
| """); | |
| var analysisResult = | |
| update( | |
| ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:computed_default_target"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:computed_default_target", | |
| "cmdline_aspect on //pkg1:my_prefix01", | |
| "cmdline_aspect on //pkg1:my_prefix02"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:computed_default_target", | |
| "cmdline_aspect on @@//pkg1:my_prefix01", | |
| "cmdline_aspect on @@//pkg1:my_prefix02"); | |
| } | |
| /** A custom {@link FragmentOptions} for the latebound attribute test. */ | |
| @OptionsClass | |
| public abstract static class TestOptions extends FragmentOptions {} | |
| /** The {@link Fragment} that contains the options. */ | |
| @RequiresOptions(options = {TestOptions.class}) | |
| public static final class TestFragment extends Fragment { | |
| private final BuildOptions buildOptions; | |
| public TestFragment(BuildOptions buildOptions) { | |
| this.buildOptions = buildOptions; | |
| } | |
| // Getter required to satisfy AutoCodec. | |
| public BuildOptions getBuildOptions() { | |
| return buildOptions; | |
| } | |
| public Label getDep() { | |
| return Label.parseCanonicalUnchecked("//pkg1:latebound_dep"); | |
| } | |
| } | |
| @Test | |
| public void lateBoundAttributes_availableToAttrAspectsFunc() throws Exception { | |
| RuleDefinition lateBoundDepRule = | |
| (MockRule) | |
| () -> | |
| MockRule.define( | |
| "rule_with_latebound_attr", | |
| (builder, env) -> | |
| builder | |
| .add( | |
| attr(":latebound_attr", LABEL) | |
| .value( | |
| LabelLateBoundDefault.fromTargetConfiguration( | |
| TestFragment.class, | |
| null, | |
| (rule, attributes, testConfig) -> testConfig.getDep()))) | |
| .requiresConfigurationFragments(TestFragment.class)); | |
| ConfiguredRuleClassProvider.Builder builder = new ConfiguredRuleClassProvider.Builder(); | |
| TestRuleClassProvider.addStandardRules(builder); | |
| builder.addRuleDefinition(lateBoundDepRule); | |
| builder.addConfigurationFragment(TestFragment.class); | |
| useRuleClassProvider(builder.build()); | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| if hasattr(ctx.rule.attr, '_latebound_attr'): | |
| if ctx.rule.attr._latebound_attr.value == Label('//pkg1:latebound_dep'): | |
| return ['_latebound_attr'] | |
| return [] | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on ' + str(target.label)] | |
| rule_attr = ctx.rule.attr | |
| if hasattr(rule_attr, '_latebound_attr'): | |
| if AspectInfo in rule_attr._latebound_attr: | |
| res.extend(rule_attr._latebound_attr[AspectInfo].res) | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs | |
| ) | |
| def _rule_impl(ctx): | |
| pass | |
| simple_rule = rule( | |
| implementation = _rule_impl, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'simple_rule') | |
| rule_with_latebound_attr(name = 'latebound_target') | |
| simple_rule(name = 'latebound_dep') | |
| """); | |
| var analysisResult = | |
| update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:latebound_target"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:latebound_target", "cmdline_aspect on //pkg1:latebound_dep"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:latebound_target", | |
| "cmdline_aspect on @@//pkg1:latebound_dep"); | |
| } | |
| @Test | |
| public void toolAttr_correctlyIdentified() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| attr_aspects = [] | |
| for attr_name in dir(ctx.rule.attr): | |
| if getattr(ctx.rule.attr, attr_name).is_tool: | |
| attr_aspects.append(attr_name) | |
| return attr_aspects | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on ' + str(target.label)] | |
| rule_attr = ctx.rule.attr | |
| if hasattr(rule_attr, '_tool_1') and AspectInfo in rule_attr._tool_1: | |
| res.extend(rule_attr._tool_1[AspectInfo].res) | |
| if hasattr(rule_attr, '_tool_2') and AspectInfo in rule_attr._tool_2: | |
| res.extend(rule_attr._tool_2[AspectInfo].res) | |
| if hasattr(rule_attr, '_non_tool') and AspectInfo in rule_attr._non_tool: | |
| res.extend(rule_attr._non_tool[AspectInfo].res) | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs | |
| ) | |
| def _rule_impl(ctx): | |
| pass | |
| rule_with_tool = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| '_tool_1': attr.label( | |
| default = Label('//pkg1:tool_1'), flags = ['IS_TOOL_DEPENDENCY']), | |
| '_tool_2': attr.label(default = Label('//pkg1:tool_2'), cfg = 'exec'), | |
| '_non_tool': attr.label(default = Label('//pkg1:non_tool')), | |
| }, | |
| ) | |
| simple_rule = rule( | |
| implementation = _rule_impl, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'rule_with_tool', 'simple_rule') | |
| rule_with_tool(name = 'main_target') | |
| simple_rule(name = 'tool_1') | |
| simple_rule(name = 'tool_2') | |
| simple_rule(name = 'non_tool') | |
| """); | |
| var analysisResult = | |
| update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:main_target"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:main_target", | |
| "cmdline_aspect on //pkg1:tool_1", | |
| "cmdline_aspect on //pkg1:tool_2"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:main_target", | |
| "cmdline_aspect on @@//pkg1:tool_1", | |
| "cmdline_aspect on @@//pkg1:tool_2"); | |
| } | |
| @Test | |
| public void attrInitializer_availableToAttrAspectsFunc() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| if hasattr(ctx.rule.attr, 'deps'): | |
| deps = ctx.rule.attr.deps.value | |
| if Label('//pkg1:added') in deps and Label('//pkg1:initial') in deps: | |
| return ['deps'] | |
| return [] | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on ' + str(target.label)] | |
| rule_attr = ctx.rule.attr | |
| for dep in getattr(rule_attr, 'deps', []): | |
| if AspectInfo in dep: | |
| res.extend(dep[AspectInfo].res) | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs | |
| ) | |
| def _rule_impl(ctx): | |
| pass | |
| def _initializer(name, deps = []): | |
| return {"deps": deps + ["//pkg1:added"]} | |
| rule_with_initializer = rule( | |
| implementation = _rule_impl, | |
| initializer = _initializer, | |
| attrs = { | |
| "deps": attr.label_list(), | |
| }, | |
| ) | |
| simple_rule = rule( | |
| implementation = _rule_impl, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'rule_with_initializer', 'simple_rule') | |
| rule_with_initializer(name = 'main_target', deps = [":initial"]) | |
| simple_rule(name = 'initial') | |
| simple_rule(name = 'added') | |
| """); | |
| useConfiguration("--experimental_rule_extension_api"); | |
| var analysisResult = | |
| update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:main_target"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:main_target", | |
| "cmdline_aspect on //pkg1:added", | |
| "cmdline_aspect on //pkg1:initial"); | |
| var aspectResult = getAspectResult(analysisResult.getAspectsMap(), "cmdline_aspect"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:main_target", | |
| "cmdline_aspect on @@//pkg1:added", | |
| "cmdline_aspect on @@//pkg1:initial"); | |
| } | |
| @Test | |
| public void aspectOnAspect_eachAspectPropagatesSeparately() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AProv = provider() | |
| BProv = provider() | |
| CProv = provider() | |
| def _a_propagation_attrs(ctx): | |
| return ['dep_1', 'dep_2'] | |
| def b_propagation_attrs(ctx): | |
| return ['dep_1'] | |
| def _c_propagation_attrs(ctx): | |
| return ['dep_2'] | |
| def _aspect_a_impl(target, ctx): | |
| current_res = 'aspect_a on %s' % target.label | |
| if BProv in target: | |
| current_res += ' with BProv' | |
| if CProv in target: | |
| current_res += ' with CProv' | |
| res = [current_res] | |
| if ctx.rule.attr.dep_1 and AProv in ctx.rule.attr.dep_1: | |
| res.extend(ctx.rule.attr.dep_1[AProv].res) | |
| if ctx.rule.attr.dep_2 and AProv in ctx.rule.attr.dep_2: | |
| res.extend(ctx.rule.attr.dep_2[AProv].res) | |
| return [AProv(res = res)] | |
| def _aspect_b_impl(target, ctx): | |
| return [BProv(res = 'aspect_b on %s' % target.label)] | |
| def _aspect_c_impl(target, ctx): | |
| return [CProv(res = 'aspect_c on %s' % target.label)] | |
| aspect_a = aspect( | |
| implementation = _aspect_a_impl, | |
| attr_aspects = _a_propagation_attrs, | |
| required_aspect_providers = [[BProv], [CProv]], | |
| ) | |
| aspect_b = aspect( | |
| implementation = _aspect_b_impl, | |
| attr_aspects = b_propagation_attrs, | |
| provides = [BProv], | |
| ) | |
| aspect_c = aspect( | |
| implementation = _aspect_c_impl, | |
| attr_aspects = _c_propagation_attrs, | |
| provides = [CProv], | |
| ) | |
| def _rule_impl(ctx): | |
| return [] | |
| my_rule = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| "dep_1": attr.label(), | |
| "dep_2": attr.label(), | |
| }, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'my_rule') | |
| my_rule(name = 'main_target', dep_1 = ':dep_1', dep_2 = ':dep_2') | |
| my_rule(name = 'dep_1') | |
| my_rule(name = 'dep_2') | |
| """); | |
| var analysisResult = | |
| update( | |
| ImmutableList.of( | |
| "//test:defs.bzl%aspect_c", "//test:defs.bzl%aspect_b", "//test:defs.bzl%aspect_a"), | |
| "//pkg1:main_target"); | |
| assertThat(getFormattedAspectKeys("aspect_a")) | |
| .containsExactly( | |
| "aspect_a on //pkg1:main_target with base aspects: aspect_b,aspect_c", | |
| "aspect_a on //pkg1:dep_1 with base aspects: aspect_b", | |
| "aspect_a on //pkg1:dep_2 with base aspects: aspect_c"); | |
| assertThat(getFormattedAspectKeys("aspect_b")) | |
| .containsExactly("aspect_b on //pkg1:main_target", "aspect_b on //pkg1:dep_1"); | |
| assertThat(getFormattedAspectKeys("aspect_c")) | |
| .containsExactly("aspect_c on //pkg1:main_target", "aspect_c on //pkg1:dep_2"); | |
| var aspectAResult = | |
| getAspectResult(analysisResult.getAspectsMap(), "aspect_a", "//pkg1:main_target", "AProv"); | |
| assertThat(aspectAResult) | |
| .containsExactly( | |
| "aspect_a on @@//pkg1:main_target with BProv with CProv", | |
| "aspect_a on @@//pkg1:dep_1 with BProv", | |
| "aspect_a on @@//pkg1:dep_2 with CProv"); | |
| } | |
| @Test | |
| public void requiredAspect_propagatesWithMainAspect() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| AProv = provider() | |
| BProv = provider() | |
| def _a_propagation_attrs(ctx): | |
| return ['dep_1', 'dep_2'] | |
| def _aspect_a_impl(target, ctx): | |
| current_res = 'aspect_a on %s' % target.label | |
| if BProv in target: | |
| current_res += ' with BProv' | |
| res = [current_res] | |
| if ctx.rule.attr.dep_1 and AProv in ctx.rule.attr.dep_1: | |
| res.extend(ctx.rule.attr.dep_1[AProv].res) | |
| if ctx.rule.attr.dep_2 and AProv in ctx.rule.attr.dep_2: | |
| res.extend(ctx.rule.attr.dep_2[AProv].res) | |
| return [AProv(res = res)] | |
| def _aspect_b_impl(target, ctx): | |
| return [BProv(res = 'aspect_b on %s' % target.label)] | |
| aspect_b = aspect( | |
| implementation = _aspect_b_impl, | |
| attr_aspects = [], | |
| provides = [BProv], | |
| ) | |
| aspect_a = aspect( | |
| implementation = _aspect_a_impl, | |
| attr_aspects = _a_propagation_attrs, | |
| requires = [aspect_b], | |
| ) | |
| def _rule_impl(ctx): | |
| return [] | |
| my_rule = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| "dep_1": attr.label(), | |
| "dep_2": attr.label(), | |
| }, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load('//test:defs.bzl', 'my_rule') | |
| my_rule(name = 'main_target', dep_1 = ':dep_1', dep_2 = ':dep_2') | |
| my_rule(name = 'dep_1') | |
| my_rule(name = 'dep_2') | |
| """); | |
| var analysisResult = update(ImmutableList.of("//test:defs.bzl%aspect_a"), "//pkg1:main_target"); | |
| assertThat(getFormattedAspectKeys("aspect_a")) | |
| .containsExactly( | |
| "aspect_a on //pkg1:main_target with base aspects: aspect_b", | |
| "aspect_a on //pkg1:dep_1 with base aspects: aspect_b", | |
| "aspect_a on //pkg1:dep_2 with base aspects: aspect_b"); | |
| assertThat(getFormattedAspectKeys("aspect_b")) | |
| .containsExactly( | |
| "aspect_b on //pkg1:main_target", | |
| "aspect_b on //pkg1:dep_1", | |
| "aspect_b on //pkg1:dep_2"); | |
| var aspectAResult = | |
| getAspectResult(analysisResult.getAspectsMap(), "aspect_a", "//pkg1:main_target", "AProv"); | |
| assertThat(aspectAResult) | |
| .containsExactly( | |
| "aspect_a on @@//pkg1:main_target with BProv", | |
| "aspect_a on @@//pkg1:dep_1 with BProv", | |
| "aspect_a on @@//pkg1:dep_2 with BProv"); | |
| } | |
| private void createDormantDepsTest(String aspectDef) throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| String.format( | |
| """ | |
| ComponentInfo = provider(fields = ["components"]) | |
| def _component_impl(ctx): | |
| current = struct(label=ctx.label, impl = ctx.attr.impl) | |
| transitive = [d[ComponentInfo].components for d in ctx.attr.deps] | |
| return [ | |
| ComponentInfo(components = depset(direct = [current], transitive = transitive)), | |
| ] | |
| component = rule( | |
| implementation = _component_impl, | |
| attrs = { | |
| "deps": attr.label_list(providers = [ComponentInfo]), | |
| "impl": attr.dormant_label(), | |
| }, | |
| provides = [ComponentInfo], | |
| dependency_resolution_rule = True, | |
| ) | |
| def _binary_impl(ctx): | |
| return [DefaultInfo(files=depset(ctx.files._impls))] | |
| def _materializer(ctx): | |
| all = depset(transitive = [d[ComponentInfo].components for d in ctx.attr.components]) | |
| selected = [c.impl for c in all.to_list() if "yes" in str(c.label)] | |
| return selected | |
| binary = rule( | |
| implementation = _binary_impl, | |
| attrs = { | |
| "components": attr.label_list(providers = [ComponentInfo], for_dependency_resolution = True), | |
| "_impls": attr.label_list(materializer = _materializer), | |
| "regular_deps": attr.label_list(), | |
| }) | |
| def _rule_impl(ctx): | |
| pass | |
| simple_rule = rule( | |
| implementation = _rule_impl, | |
| ) | |
| %s | |
| """, | |
| aspectDef)); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load("//test:defs.bzl", "component", "binary", "simple_rule") | |
| component(name="a_yes", impl=":a_impl") | |
| component(name="b_no", deps = [":c_yes", ":d_no"], impl=":b_impl") | |
| component(name="c_yes", impl=":c_impl") | |
| component(name="d_no", impl=":d_impl") | |
| binary(name="bin", components=[":a_yes", ":b_no"], regular_deps = [":dep_1"]) | |
| [filegroup(name=x + "_impl", srcs=[x]) for x in ["a", "b", "c", "d"]] | |
| simple_rule(name = 'dep_1') | |
| """); | |
| } | |
| @Test | |
| public void aspectOnMaterializingTarget_attrAspectsFuncUsed() throws Exception { | |
| createDormantDepsTest( | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| if ctx.rule.qualified_kind.rule_name == 'binary': | |
| # the value of _impls should be None as it is not materialized yet | |
| if ctx.rule.attr._impls.value != None: | |
| fail("'_impls' should be None") | |
| # the value of regular_deps should be available | |
| if Label('//pkg1:dep_1') not in ctx.rule.attr.regular_deps.value: | |
| fail("regular_deps should be available") | |
| # the value of components should be available | |
| components = ctx.rule.attr.components.value | |
| if len(components) != 2 or Label('//pkg1:a_yes') not in components or Label('//pkg1:b_no') not in components: | |
| fail("components should be available") | |
| return ['_impls', 'components', 'regular_deps'] | |
| return [] | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on %s' % target.label] | |
| deps = [] | |
| deps.extend(getattr(ctx.rule.attr, '_impls', [])) | |
| deps.extend(getattr(ctx.rule.attr, 'components', [])) | |
| deps.extend(getattr(ctx.rule.attr, 'regular_deps', [])) | |
| for dep in deps: | |
| if AspectInfo in dep: | |
| res += dep[AspectInfo].res | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| ) | |
| """); | |
| useConfiguration("--experimental_dormant_deps"); | |
| var analysisResult = update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:bin"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:bin", | |
| "cmdline_aspect on //pkg1:dep_1", | |
| "cmdline_aspect on //pkg1:a_yes", | |
| "cmdline_aspect on //pkg1:b_no", | |
| "cmdline_aspect on //pkg1:a_impl", | |
| "cmdline_aspect on //pkg1:c_impl"); | |
| var aspectAResult = | |
| getAspectResult( | |
| analysisResult.getAspectsMap(), "cmdline_aspect", "//pkg1:bin", "AspectInfo"); | |
| assertThat(aspectAResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:bin", | |
| "cmdline_aspect on @@//pkg1:dep_1", | |
| "cmdline_aspect on @@//pkg1:a_yes", | |
| "cmdline_aspect on @@//pkg1:b_no", | |
| "cmdline_aspect on @@//pkg1:a_impl", | |
| "cmdline_aspect on @@//pkg1:c_impl"); | |
| } | |
| @Test | |
| public void aspectOnDependencyResolutionTargets_attrAspectsFuncUsed() throws Exception { | |
| createDormantDepsTest( | |
| """ | |
| AspectInfo = provider() | |
| def _propagation_attrs(ctx): | |
| if ctx.rule.qualified_kind.rule_name == 'component': | |
| # the value of impl should be available | |
| impl_name = ctx.rule.label.name.split('_')[0] + '_impl' | |
| impl_val = ctx.rule.attr.impl.value | |
| if type(impl_val) != 'DormantDependency' or impl_val.label.name != impl_name: | |
| fail("'impl' should be available") | |
| # the value of deps should be available | |
| if ctx.rule.label == Label('//pkg1:b_no'): | |
| deps = ctx.rule.attr.deps.value | |
| if Label('//pkg1:c_yes') not in deps or Label('//pkg1:d_no') not in deps: | |
| fail("deps should be available") | |
| elif len(ctx.rule.attr.deps.value) != 0: | |
| fail("deps should be empty") | |
| return ['deps', 'impl'] | |
| return ['components'] | |
| def _aspect_impl(target, ctx): | |
| res = ['cmdline_aspect on %s' % target.label] | |
| if hasattr(ctx.rule.attr, 'impl') and type(ctx.rule.attr.impl) != 'DormantDependency': | |
| fail("impl should be a dormant dependency") | |
| deps = [] | |
| deps.extend(getattr(ctx.rule.attr, 'deps', [])) | |
| deps.extend(getattr(ctx.rule.attr, 'components', [])) | |
| for dep in deps: | |
| if AspectInfo in dep: | |
| res += dep[AspectInfo].res | |
| return [AspectInfo(res = res)] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| ) | |
| """); | |
| useConfiguration("--experimental_dormant_deps"); | |
| var analysisResult = update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:bin"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly( | |
| "cmdline_aspect on //pkg1:bin", | |
| "cmdline_aspect on //pkg1:a_yes", | |
| "cmdline_aspect on //pkg1:b_no", | |
| "cmdline_aspect on //pkg1:c_yes", | |
| "cmdline_aspect on //pkg1:d_no"); | |
| var aspectResult = | |
| getAspectResult( | |
| analysisResult.getAspectsMap(), "cmdline_aspect", "//pkg1:bin", "AspectInfo"); | |
| assertThat(aspectResult) | |
| .containsExactly( | |
| "cmdline_aspect on @@//pkg1:bin", | |
| "cmdline_aspect on @@//pkg1:a_yes", | |
| "cmdline_aspect on @@//pkg1:b_no", | |
| "cmdline_aspect on @@//pkg1:c_yes", | |
| "cmdline_aspect on @@//pkg1:d_no"); | |
| } | |
| @Test | |
| public void allRuleAttributesAreAvailableInAttrAspectsFunc() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| attr_map = { | |
| 'bool': True, | |
| 'int': 100, | |
| 'int_list': [1, 2, 3], | |
| 'label': Label('//pkg1:dep_1'), | |
| 'label_keyed_string_dict': {Label('//pkg1:dep_1'): 'key1', Label('//pkg1:dep_2'): 'key2'}, | |
| 'label_list': [Label('//pkg1:dep_1'), Label('//pkg1:dep_2')], | |
| 'output': Label('//pkg1:output.txt'), | |
| 'output_list': [Label('//pkg1:output_2.txt'), Label('//pkg1:output_3.txt')], | |
| 'string': 'string_value', | |
| 'string_dict': {'key1': 'value1', 'key2': 'value2'}, | |
| 'string_keyed_label_dict': {'key1': Label('//pkg1:dep_1'), 'key2': Label('//pkg1:dep_2')}, | |
| 'string_list': ['string_value_1', 'string_value_2'], | |
| 'string_list_dict': {'key1': ['string_value_1', 'string_value_2'], 'key2': ['string_value_3', 'string_value_4']}, | |
| 'label_list_dict': {'key1': [Label('//pkg1:dep_1')], 'key2': [Label('//pkg1:dep_2')]}, | |
| } | |
| def _propagation_attrs(ctx): | |
| for attr_name, expected_val in attr_map.items(): | |
| if not hasattr(ctx.rule.attr, attr_name): | |
| fail("'%s' is not an attribute of the rule" % attr_name) | |
| actual_val = getattr(ctx.rule.attr, attr_name).value | |
| if expected_val != actual_val: | |
| fail("'%s' has wrong value: expected %s, got %s" % (attr_name, expected_val, actual_val)) | |
| return [] | |
| def _aspect_impl(target, ctx): | |
| return [] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| ) | |
| def _rule_impl(ctx): | |
| if ctx.outputs.output: | |
| ctx.actions.write(ctx.outputs.output, 'hi') | |
| if ctx.outputs.output_list: | |
| ctx.actions.write(ctx.outputs.output_list[0], 'hi') | |
| ctx.actions.write(ctx.outputs.output_list[1], 'hi') | |
| return [] | |
| my_rule = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| "bool": attr.bool(), | |
| "int": attr.int(), | |
| "int_list": attr.int_list(), | |
| "label": attr.label(), | |
| "label_keyed_string_dict": attr.label_keyed_string_dict(), | |
| "label_list": attr.label_list(), | |
| "output": attr.output(), | |
| "output_list": attr.output_list(), | |
| "string": attr.string(), | |
| "string_dict": attr.string_dict(), | |
| "string_keyed_label_dict": attr.string_keyed_label_dict(), | |
| "string_list": attr.string_list(), | |
| "string_list_dict": attr.string_list_dict(), | |
| "label_list_dict": attr.label_list_dict(), | |
| }) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load("//test:defs.bzl", "my_rule") | |
| my_rule( | |
| name = 'main_target', | |
| bool = True, | |
| int = 100, | |
| int_list = [1, 2, 3], | |
| label = ':dep_1', | |
| label_keyed_string_dict = {'//pkg1:dep_1': 'key1', '//pkg1:dep_2': 'key2'}, | |
| label_list = [':dep_1', ':dep_2'], | |
| output = 'output.txt', | |
| output_list = ['output_2.txt', 'output_3.txt'], | |
| string = 'string_value', | |
| string_dict = {'key1': 'value1', 'key2': 'value2'}, | |
| string_keyed_label_dict = {'key1': ':dep_1', 'key2': ':dep_2'}, | |
| string_list = ['string_value_1', 'string_value_2'], | |
| string_list_dict = {'key1': ['string_value_1', 'string_value_2'], 'key2': ['string_value_3', 'string_value_4']}, | |
| label_list_dict = {'key1': [':dep_1'], 'key2': [':dep_2']}, | |
| ) | |
| my_rule(name = 'dep_1') | |
| my_rule(name = 'dep_2') | |
| """); | |
| var unused = update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:main_target"); | |
| assertThat(getFormattedAspectKeys("cmdline_aspect")) | |
| .containsExactly("cmdline_aspect on //pkg1:main_target"); | |
| } | |
| @Test | |
| public void attributeWithTransition_availableInAttrAspectsFunc() throws Exception { | |
| scratch.file("test/BUILD"); | |
| scratch.file( | |
| "test/defs.bzl", | |
| """ | |
| def _propagation_attrs(ctx): | |
| if ctx.rule.label.name != 'main_target': | |
| return [] | |
| dep = ctx.rule.attr.dep.value | |
| if not dep or type(dep) != type([]) or dep[0] != Label('//pkg1:dep_1'): | |
| fail("dep is not available") | |
| return ['dep'] | |
| def _aspect_impl(target, ctx): | |
| return [] | |
| cmdline_aspect = aspect( | |
| implementation = _aspect_impl, | |
| attr_aspects = _propagation_attrs, | |
| ) | |
| def _transition_impl(settings, attr): | |
| return { | |
| "t1": {"//command_line_option:foo" : "v1"}, | |
| "t2": {"//command_line_option:foo" : "v2"} | |
| } | |
| simple_transition = transition( | |
| implementation = _transition_impl, | |
| inputs = [], | |
| outputs = ["//command_line_option:foo"] | |
| ) | |
| def _rule_impl(ctx): | |
| pass | |
| my_rule = rule( | |
| implementation = _rule_impl, | |
| attrs = { | |
| "dep": attr.label(cfg = simple_transition), | |
| }, | |
| ) | |
| """); | |
| scratch.file( | |
| "pkg1/BUILD", | |
| """ | |
| load("//test:defs.bzl", "my_rule") | |
| my_rule(name = 'main_target', dep = ':dep_1') | |
| my_rule(name = 'dep_1') | |
| """); | |
| ConfiguredRuleClassProvider.Builder builder = new ConfiguredRuleClassProvider.Builder(); | |
| TestRuleClassProvider.addStandardRules(builder); | |
| builder.addConfigurationFragment(DummyTestFragment.class); | |
| useRuleClassProvider(builder.build()); | |
| useConfiguration("--foo=default"); | |
| var unused = update(ImmutableList.of("//test:defs.bzl%cmdline_aspect"), "//pkg1:main_target"); | |
| var aspectKeys = | |
| getAspectKeys("cmdline_aspect").stream() | |
| .map( | |
| k -> | |
| k.getLabel() | |
| + " with foo = " | |
| + k.getConfigurationKey() | |
| .getOptions() | |
| .get(DummyTestOptions.class) | |
| .getFoo()); | |
| assertThat(aspectKeys) | |
| .containsExactly( | |
| "//pkg1:main_target with foo = default", | |
| "//pkg1:dep_1 with foo = v1", | |
| "//pkg1:dep_1 with foo = v2"); | |
| } | |
| private ImmutableList<AspectKey> getAspectKeys(String aspectName) { | |
| return skyframeExecutor.getEvaluator().getDoneValues().entrySet().stream() | |
| .filter( | |
| entry -> | |
| entry.getKey() instanceof AspectKey | |
| && ((AspectKey) entry.getKey()) | |
| .getAspectClass() | |
| .toString() | |
| .equals("//test:defs.bzl%" + aspectName)) | |
| .map(e -> (AspectKey) e.getKey()) | |
| .collect(toImmutableList()); | |
| } | |
| private String formatAspectKey(AspectKey aspectKey) { | |
| if (aspectKey.getBaseKeys().isEmpty()) { | |
| return Splitter.on("%").splitToList(aspectKey.getAspectClass().toString()).get(1) | |
| + " on " | |
| + aspectKey.getLabel(); | |
| } | |
| String baseAspects = | |
| aspectKey.getBaseKeys().stream() | |
| .map(k -> Splitter.on("%").splitToList(k.getAspectClass().toString()).get(1)) | |
| .collect(joining(",")); | |
| return Splitter.on("%").splitToList(aspectKey.getAspectClass().toString()).get(1) | |
| + " on " | |
| + aspectKey.getLabel() | |
| + " with base aspects: " | |
| + baseAspects; | |
| } | |
| private ImmutableList<String> getFormattedAspectKeys(String aspectName) { | |
| return skyframeExecutor.getEvaluator().getDoneValues().entrySet().stream() | |
| .filter( | |
| entry -> | |
| entry.getKey() instanceof AspectKey | |
| && ((AspectKey) entry.getKey()) | |
| .getAspectClass() | |
| .toString() | |
| .equals("//test:defs.bzl%" + aspectName)) | |
| .map(e -> formatAspectKey((AspectKey) e.getKey())) | |
| .collect(toImmutableList()); | |
| } | |
| private Sequence<?> getAspectResult( | |
| Map<AspectKey, ConfiguredAspect> aspectsMap, String aspectName) throws Exception { | |
| return getAspectResult(aspectsMap, aspectName, null, "AspectInfo"); | |
| } | |
| private Sequence<?> getAspectResult( | |
| Map<AspectKey, ConfiguredAspect> aspectsMap, | |
| String aspectName, | |
| String targetLabel, | |
| String providerName) | |
| throws Exception { | |
| for (Map.Entry<AspectKey, ConfiguredAspect> entry : aspectsMap.entrySet()) { | |
| AspectClass aspectClass = entry.getKey().getAspectClass(); | |
| if (aspectClass instanceof StarlarkAspectClass starlarkAspectClass) { | |
| String aspectExportedName = starlarkAspectClass.getExportedName(); | |
| if (aspectExportedName.equals(aspectName) | |
| && (targetLabel == null || entry.getKey().getLabel().toString().equals(targetLabel))) { | |
| return getStarlarkProvider(entry.getValue(), "//test:defs.bzl", providerName) | |
| .getValue("res", Sequence.class); | |
| } | |
| } | |
| } | |
| throw new AssertionError("Aspect result not found for aspect: " + aspectName); | |
| } | |
| } |