// Copyright 2015 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.analysis.util; import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL; import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST; import static com.google.devtools.build.lib.syntax.Type.BOOLEAN; import static com.google.devtools.build.lib.syntax.Type.STRING; import static com.google.devtools.build.lib.syntax.Type.STRING_LIST; import com.google.common.base.Function; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.ConfiguredAspect; import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.AspectDefinition; import com.google.devtools.build.lib.packages.AspectParameters; import com.google.devtools.build.lib.packages.Attribute.LateBoundDefault; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.NativeAspectClass; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder; import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier; import com.google.devtools.build.lib.rules.java.JavaConfiguration; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.util.FileTypeSet; import java.util.List; /** * Various rule and aspect classes that aid in testing the aspect machinery. * *

These are mostly used in {@link com.google.devtools.build.lib.analysis.DependencyResolverTest} * and {@link com.google.devtools.build.lib.analysis.AspectTest}. */ public class TestAspects { /** * A transitive info provider for collecting aspects in the transitive closure. Created by * aspects. */ @Immutable public static final class AspectInfo implements TransitiveInfoProvider { private final NestedSet data; public AspectInfo(NestedSet data) { this.data = data; } public NestedSet getData() { return data; } } /** * A transitive info provider used as sentinel. Created by aspects. */ @Immutable public static final class FooProvider implements TransitiveInfoProvider { } /** * A transitive info provider used as sentinel. Created by aspects. */ @Immutable public static final class BarProvider implements TransitiveInfoProvider { } /** * A transitive info provider for collecting aspects in the transitive closure. Created by * rules. */ @Immutable public static final class RuleInfo implements TransitiveInfoProvider { private final NestedSet data; public RuleInfo(NestedSet data) { this.data = data; } public NestedSet getData() { return data; } } /** * A very simple provider used in tests that check whether the logic that attaches aspects * depending on whether a configured target has a provider works or not. */ @Immutable public static final class RequiredProvider implements TransitiveInfoProvider { } /** * Another very simple provider used in tests that check whether the logic that attaches aspects * depending on whether a configured target has a provider works or not. */ @Immutable public static final class RequiredProvider2 implements TransitiveInfoProvider { } private static NestedSet collectAspectData(String me, RuleContext ruleContext) { NestedSetBuilder result = new NestedSetBuilder<>(Order.STABLE_ORDER); result.add(me); Iterable attributeNames = ruleContext.attributes().getAttributeNames(); for (String attributeName : attributeNames) { Type attributeType = ruleContext.attributes().getAttributeType(attributeName); if (!LABEL.equals(attributeType) && !LABEL_LIST.equals(attributeType)) { continue; } Iterable prerequisites = ruleContext .getPrerequisites(attributeName, Mode.DONT_CHECK, AspectInfo.class); for (AspectInfo prerequisite : prerequisites) { result.addTransitive(prerequisite.getData()); } } return result.build(); } /** * A simple rule configured target factory that is used in all the mock rules in this class. */ public static class DummyRuleFactory implements RuleConfiguredTargetFactory { @Override public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) .addProvider( new RuleInfo(collectAspectData("rule " + ruleContext.getLabel(), ruleContext))) .setFilesToBuild(NestedSetBuilder.create(Order.STABLE_ORDER)) .setRunfilesSupport(null, null) .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)); if (ruleContext.getRule().getRuleClassObject().getName().equals("honest")) { builder.addProvider(new RequiredProvider()); } return builder.build(); } } /** * A simple rule configured target factory that exports provider {@link RequiredProvider2}. */ public static class DummyRuleFactory2 implements RuleConfiguredTargetFactory { @Override public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { return new RuleConfiguredTargetBuilder(ruleContext) .addProvider( new RuleInfo(collectAspectData("rule " + ruleContext.getLabel(), ruleContext))) .setFilesToBuild(NestedSetBuilder.create(Order.STABLE_ORDER)) .setRunfilesSupport(null, null) .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)) .addProvider(new RequiredProvider()) .addProvider(new RequiredProvider2()) .build(); } } /** * A simple rule configured target factory that expects different providers added through * different aspects. */ public static class MultiAspectRuleFactory implements RuleConfiguredTargetFactory { @Override public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { TransitiveInfoCollection fooAttribute = ruleContext.getPrerequisite("foo", Mode.DONT_CHECK); TransitiveInfoCollection barAttribute = ruleContext.getPrerequisite("bar", Mode.DONT_CHECK); NestedSetBuilder infoBuilder = NestedSetBuilder.stableOrder(); if (fooAttribute.getProvider(FooProvider.class) != null) { infoBuilder.add("foo"); } if (barAttribute.getProvider(BarProvider.class) != null) { infoBuilder.add("bar"); } RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) .addProvider( new RuleInfo(infoBuilder.build())) .setFilesToBuild(NestedSetBuilder.create(Order.STABLE_ORDER)) .setRunfilesSupport(null, null) .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)); return builder.build(); } } /** * A base class for mock aspects to reduce boilerplate. */ public abstract static class BaseAspect extends NativeAspectClass implements ConfiguredAspectFactory { @Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { String information = parameters.isEmpty() ? "" : " data " + Iterables.getFirst(parameters.getAttribute("baz"), null); return new ConfiguredAspect.Builder(this, parameters, ruleContext) .addProvider( new AspectInfo( collectAspectData("aspect " + ruleContext.getLabel() + information, ruleContext))) .build(); } } public static final SimpleAspect SIMPLE_ASPECT = new SimpleAspect(); public static final FooProviderAspect FOO_PROVIDER_ASPECT = new FooProviderAspect(); public static final BarProviderAspect BAR_PROVIDER_ASPECT = new BarProviderAspect(); private static final AspectDefinition SIMPLE_ASPECT_DEFINITION = new AspectDefinition.Builder(SIMPLE_ASPECT).build(); private static final AspectDefinition FOO_PROVIDER_ASPECT_DEFINITION = new AspectDefinition.Builder(FOO_PROVIDER_ASPECT).build(); private static final AspectDefinition BAR_PROVIDER_ASPECT_DEFINITION = new AspectDefinition.Builder(BAR_PROVIDER_ASPECT).build(); /** * A very simple aspect. */ public static class SimpleAspect extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return SIMPLE_ASPECT_DEFINITION; } } /** * A simple aspect that propagates a FooProvider provider. */ public static class FooProviderAspect extends NativeAspectClass implements ConfiguredAspectFactory { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return FOO_PROVIDER_ASPECT_DEFINITION; } @Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { return new ConfiguredAspect.Builder(this, parameters, ruleContext) .addProvider(new FooProvider()) .build(); } } /** * A simple aspect that propagates a BarProvider provider. */ public static class BarProviderAspect extends NativeAspectClass implements ConfiguredAspectFactory{ @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return BAR_PROVIDER_ASPECT_DEFINITION; } @Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { return new ConfiguredAspect.Builder(this, parameters, ruleContext) .addProvider(new BarProvider()) .build(); } } public static final ExtraAttributeAspect EXTRA_ATTRIBUTE_ASPECT = new ExtraAttributeAspect(); private static final AspectDefinition EXTRA_ATTRIBUTE_ASPECT_DEFINITION = new AspectDefinition.Builder(EXTRA_ATTRIBUTE_ASPECT) .add(attr("$dep", LABEL).value(Label.parseAbsoluteUnchecked("//extra:extra"))) .build(); private static final ExtraAttributeAspectRequiringProvider EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER = new ExtraAttributeAspectRequiringProvider(); private static final AspectDefinition EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER_DEFINITION = new AspectDefinition.Builder(EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER) .add(attr("$dep", LABEL).value(Label.parseAbsoluteUnchecked("//extra:extra"))) .requireProviders(RequiredProvider.class) .build(); /** * An aspect that defines its own implicit attribute. */ public static class ExtraAttributeAspect extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return EXTRA_ATTRIBUTE_ASPECT_DEFINITION; } } public static final AttributeAspect ATTRIBUTE_ASPECT = new AttributeAspect(); private static final AspectDefinition ATTRIBUTE_ASPECT_DEFINITION = new AspectDefinition.Builder(ATTRIBUTE_ASPECT) .propagateAlongAttribute("foo") .build(); /** * An aspect that propagates along all attributes. */ public static class AllAttributesAspect extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return ALL_ATTRIBUTES_ASPECT_DEFINITION; } } public static final NativeAspectClass ALL_ATTRIBUTES_ASPECT = new AllAttributesAspect(); private static final AspectDefinition ALL_ATTRIBUTES_ASPECT_DEFINITION = new AspectDefinition.Builder(ALL_ATTRIBUTES_ASPECT) .propagateAlongAllAttributes() .build(); /** An aspect that propagates along all attributes and has a tool dependency. */ public static class AllAttributesWithToolAspect extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return ALL_ATTRIBUTES_WITH_TOOL_ASPECT_DEFINITION; } } public static final NativeAspectClass ALL_ATTRIBUTES_WITH_TOOL_ASPECT = new AllAttributesWithToolAspect(); private static final AspectDefinition ALL_ATTRIBUTES_WITH_TOOL_ASPECT_DEFINITION = new AspectDefinition.Builder(ALL_ATTRIBUTES_WITH_TOOL_ASPECT) .propagateAlongAllAttributes() .add( attr("$tool", BuildType.LABEL) .allowedFileTypes(FileTypeSet.ANY_FILE) .value(Label.parseAbsoluteUnchecked("//a:tool"))) .build(); /** * An aspect that requires aspects on the attributes of rules it attaches to. */ public static class AttributeAspect extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return ATTRIBUTE_ASPECT_DEFINITION; } } /** * An aspect that defines its own implicit attribute and requires provider. */ public static class ExtraAttributeAspectRequiringProvider extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER_DEFINITION; } } public static class AspectRequiringProvider extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return ASPECT_REQUIRING_PROVIDER_DEFINITION; } } /** * An aspect that requires provider sets {{@link RequiredProvider}} and * {{@link RequiredProvider2}}. */ public static class AspectRequiringProviderSets extends BaseAspect { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return ASPECT_REQUIRING_PROVIDER_SETS_DEFINITION; } } /** * An aspect that has a definition depending on parameters provided by originating rule. */ public static class ParametrizedDefinitionAspect extends NativeAspectClass implements ConfiguredAspectFactory { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { AspectDefinition.Builder builder = new AspectDefinition.Builder(PARAMETRIZED_DEFINITION_ASPECT) .propagateAlongAttribute("foo"); ImmutableCollection baz = aspectParameters.getAttribute("baz"); if (baz != null) { try { builder.add(attr("$dep", LABEL).value(Label.parseAbsolute(baz.iterator().next()))); } catch (LabelSyntaxException e) { throw new IllegalStateException(); } } return builder.build(); } @Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { StringBuilder information = new StringBuilder("aspect " + ruleContext.getLabel()); if (!parameters.isEmpty()) { information.append(" data " + Iterables.getFirst(parameters.getAttribute("baz"), null)); information.append(" "); } List deps = ruleContext.getPrerequisites("$dep", Mode.TARGET); information.append("$dep:["); for (TransitiveInfoCollection dep : deps) { information.append(" "); information.append(dep.getLabel()); } information.append("]"); return new ConfiguredAspect.Builder(this, parameters, ruleContext) .addProvider(new AspectInfo(collectAspectData(information.toString(), ruleContext))) .build(); } } private static final ParametrizedDefinitionAspect PARAMETRIZED_DEFINITION_ASPECT = new ParametrizedDefinitionAspect(); private static final AspectRequiringProvider ASPECT_REQUIRING_PROVIDER = new AspectRequiringProvider(); private static final AspectRequiringProviderSets ASPECT_REQUIRING_PROVIDER_SETS = new AspectRequiringProviderSets(); private static final AspectDefinition ASPECT_REQUIRING_PROVIDER_DEFINITION = new AspectDefinition.Builder(ASPECT_REQUIRING_PROVIDER) .requireProviders(RequiredProvider.class) .propagateAlongAttribute("foo") .build(); private static final AspectDefinition ASPECT_REQUIRING_PROVIDER_SETS_DEFINITION = new AspectDefinition.Builder(ASPECT_REQUIRING_PROVIDER_SETS) .requireProviderSets( ImmutableList.of( ImmutableSet.>of(RequiredProvider.class), ImmutableSet.>of(RequiredProvider2.class))) .build(); /** * An aspect that prints a warning. */ public static class WarningAspect extends NativeAspectClass implements ConfiguredAspectFactory { @Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { ruleContext.ruleWarning("Aspect warning on " + base.getTarget().getLabel()); return new ConfiguredAspect.Builder(this, parameters, ruleContext).build(); } @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return WARNING_ASPECT_DEFINITION; } } public static final WarningAspect WARNING_ASPECT = new WarningAspect(); private static final AspectDefinition WARNING_ASPECT_DEFINITION = new AspectDefinition.Builder(WARNING_ASPECT) .propagateAlongAttribute("bar") .build(); /** * An aspect that raises an error. */ public static class ErrorAspect extends NativeAspectClass implements ConfiguredAspectFactory { @Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { ruleContext.ruleError("Aspect error"); return null; } @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return ERROR_ASPECT_DEFINITION; } } public static final ErrorAspect ERROR_ASPECT = new ErrorAspect(); private static final AspectDefinition ERROR_ASPECT_DEFINITION = new AspectDefinition.Builder(ERROR_ASPECT) .propagateAlongAttribute("bar") .build(); /** * An aspect that advertises but fails to provide providers. */ public static class FalseAdvertisementAspect extends NativeAspectClass implements ConfiguredAspectFactory { @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return FALSE_ADVERTISEMENT_DEFINITION; } @Override public ConfiguredAspect create(ConfiguredTarget base, RuleContext context, AspectParameters parameters) throws InterruptedException { return new ConfiguredAspect.Builder(this, parameters, context).build(); } } public static final FalseAdvertisementAspect FALSE_ADVERTISEMENT_ASPECT = new FalseAdvertisementAspect(); private static final AspectDefinition FALSE_ADVERTISEMENT_DEFINITION = new AspectDefinition.Builder(FALSE_ADVERTISEMENT_ASPECT) .advertiseProvider(RequiredProvider.class) .advertiseProvider( ImmutableList.of(SkylarkProviderIdentifier.forLegacy("advertised_provider"))) .build(); /** * A common base rule for mock rules in this class to reduce boilerplate. * *

It has a few common attributes because internal Blaze machinery assumes the presence of * these. */ public static class BaseRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("testonly", BOOLEAN).nonconfigurable("test").value(false)) .add(attr("deprecation", STRING).nonconfigurable("test").value((String) null)) .add(attr("tags", STRING_LIST)) .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST) .nonconfigurable("test")) .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST) .allowedFileTypes(FileTypeSet.NO_FILE)) .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST) .allowedFileTypes(FileTypeSet.NO_FILE)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("base") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRuleClasses.RootRule.class) .build(); } } /** * A rule that defines an aspect on one of its attributes. */ public static class AspectRequiringRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(SIMPLE_ASPECT)) .add(attr("bar", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(SIMPLE_ASPECT)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines different aspects on different attributes. */ public static class MultiAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL).allowedFileTypes(FileTypeSet.ANY_FILE) .mandatory() .aspect(FOO_PROVIDER_ASPECT)) .add(attr("bar", LABEL).allowedFileTypes(FileTypeSet.ANY_FILE) .mandatory() .aspect(BAR_PROVIDER_ASPECT)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("multi_aspect") .factoryClass(MultiAspectRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link AspectRequiringProvider} on one of its attributes. */ public static class AspectRequiringProviderRule implements RuleDefinition { private static final class TestAspectParametersExtractor implements Function { @Override public AspectParameters apply(Rule rule) { if (rule.isAttrDefined("baz", STRING)) { String value = rule.getAttributeContainer().getAttr("baz").toString(); if (!value.equals("")) { return new AspectParameters.Builder().addAttribute("baz", value).build(); } } return AspectParameters.EMPTY; } } @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(ASPECT_REQUIRING_PROVIDER, new TestAspectParametersExtractor())) .add(attr("baz", STRING)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("aspect_requiring_provider") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link AspectRequiringProviderSets} on one of its attributes. */ public static class AspectRequiringProviderSetsRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(ASPECT_REQUIRING_PROVIDER_SETS)) .add(attr("baz", STRING)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("aspect_requiring_provider_sets") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link ExtraAttributeAspect} on one of its attributes. */ public static class ExtraAttributeAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(EXTRA_ATTRIBUTE_ASPECT)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("rule_with_extra_deps_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link ParametrizedDefinitionAspect} on one of its attributes. */ public static class ParametrizedDefinitionAspectRule implements RuleDefinition { private static final class TestAspectParametersExtractor implements Function { @Override public AspectParameters apply(Rule rule) { if (rule.isAttrDefined("baz", STRING)) { String value = rule.getAttributeContainer().getAttr("baz").toString(); if (!value.equals("")) { return new AspectParameters.Builder().addAttribute("baz", value).build(); } } return AspectParameters.EMPTY; } } @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add( attr("foo", LABEL_LIST) .allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(PARAMETRIZED_DEFINITION_ASPECT, new TestAspectParametersExtractor())) .add(attr("baz", STRING)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("parametrized_definition_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link ExtraAttributeAspectRequiringProvider} on one of its attributes. */ public static class ExtraAttributeAspectRequiringProviderRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("extra_attribute_aspect_requiring_provider") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link AllAttributesAspect} on one of its attributes. */ public static class AllAttributesAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(ALL_ATTRIBUTES_ASPECT)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("all_attributes_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** A rule that defines an {@link AllAttributesWithToolAspect} on one of its attributes. */ public static class AllAttributesWithToolAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add( attr("foo", LABEL_LIST) .allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(ALL_ATTRIBUTES_WITH_TOOL_ASPECT)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("all_attributes_with_tool_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines a {@link WarningAspect} on one of its attributes. */ public static class WarningAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(WARNING_ASPECT)) .add(attr("bar", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("warning_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that defines an {@link ErrorAspect} on one of its attributes. */ public static class ErrorAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) .aspect(ERROR_ASPECT)) .add(attr("bar", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("error_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A simple rule that has an attribute. */ public static class SimpleRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .add(attr("foo1", LABEL).allowedFileTypes(FileTypeSet.ANY_FILE)) .add(attr("txt", STRING)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("simple") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that advertises a provider but doesn't implement it. */ public static class LiarRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .advertiseProvider(RequiredProvider.class) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("liar") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that advertises a provider and implements it. */ public static class HonestRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .advertiseProvider(RequiredProvider.class) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("honest") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * A rule that advertises another, different provider and implements it. */ public static class HonestRule2 implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .advertiseProvider(RequiredProvider2.class) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("honest2") .factoryClass(DummyRuleFactory2.class) .ancestors(BaseRule.class) .build(); } } /** * Rule with an implcit dependency. */ public static class ImplicitDepRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("$dep", LABEL).value(Label.parseAbsoluteUnchecked("//extra:extra"))) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("implicit_dep") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * Rule with a late-bound dependency. */ public static class LateBoundDepRule implements RuleDefinition { private static final LateBoundDefault> PLUGINS_LABEL_LIST = LateBoundDefault.fromTargetConfiguration( JavaConfiguration.class, ImmutableList.of(), (rule, attributes, javaConfig) -> javaConfig.getPlugins()); @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr(":plugins", LABEL_LIST).value(PLUGINS_LABEL_LIST)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("late_bound_dep") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** * Rule with {@link FalseAdvertisementAspect} */ public static final class FalseAdvertisementAspectRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .add(attr("deps", LABEL_LIST).allowedFileTypes().aspect(FALSE_ADVERTISEMENT_ASPECT)) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("false_advertisement_aspect") .factoryClass(DummyRuleFactory.class) .ancestors(BaseRule.class) .build(); } } /** Aspect that propagates over rule outputs. */ public static class AspectApplyingToFiles extends NativeAspectClass implements ConfiguredAspectFactory { /** Simple provider for testing */ @Immutable public static final class Provider implements TransitiveInfoProvider { private final Label label; private Provider(Label label) { this.label = label; } public Label getLabel() { return label; } } @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { return AspectDefinition.builder(this).applyToFiles(true).build(); } @Override public ConfiguredAspect create(ConfiguredTarget base, RuleContext context, AspectParameters parameters) throws InterruptedException { return ConfiguredAspect.builder(this, parameters, context) .addProvider(Provider.class, new Provider(base.getLabel())) .build(); } } }