// Copyright 2014 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; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.ABSTRACT; import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.TEST; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.devtools.build.lib.actions.ActionEnvironment; import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.BuildOptions.OptionsDiff; import com.google.devtools.build.lib.analysis.config.ComposingRuleTransitionFactory; import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory; import com.google.devtools.build.lib.analysis.config.DefaultsPackage; import com.google.devtools.build.lib.analysis.config.FragmentOptions; import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics; import com.google.devtools.build.lib.analysis.skylark.SkylarkModules; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.graph.Digraph; import com.google.devtools.build.lib.graph.Node; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.NativeAspectClass; import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; import com.google.devtools.build.lib.packages.OutputFile; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.packages.RuleErrorConsumer; import com.google.devtools.build.lib.packages.RuleTransitionFactory; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy; import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; import com.google.devtools.build.lib.skylarkbuildapi.Bootstrap; import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.Environment.Extension; import com.google.devtools.build.lib.syntax.Environment.GlobalFrame; import com.google.devtools.build.lib.syntax.Environment.Phase; import com.google.devtools.build.lib.syntax.Mutability; import com.google.devtools.build.lib.syntax.SkylarkSemantics; import com.google.devtools.build.lib.syntax.SkylarkUtils; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.common.options.OptionsClassProvider; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.annotation.Nullable; /** * Knows about every rule Blaze supports and the associated configuration options. * *

This class is initialized on server startup and the set of rules, build info factories * and configuration options is guaranteed not to change over the life time of the Blaze server. */ public class ConfiguredRuleClassProvider implements RuleClassProvider { /** * Predicate for determining whether the analysis cache should be cleared, given the new set of * build options and the diff from the old set. */ @FunctionalInterface public interface OptionsDiffPredicate { public static final OptionsDiffPredicate ALWAYS_INVALIDATE = (diff, options) -> true; public boolean apply(OptionsDiff diff, BuildOptions newOptions); } /** * Custom dependency validation logic. */ public interface PrerequisiteValidator { /** * Checks whether the rule in {@code contextBuilder} is allowed to depend on {@code * prerequisite} through the attribute {@code attribute}. * *

Can be used for enforcing any organization-specific policies about the layout of the * workspace. */ void validate( RuleContext.Builder contextBuilder, ConfiguredTargetAndData prerequisite, Attribute attribute); } /** Validator to check for and warn on the deprecation of dependencies. */ public static final class DeprecationValidator implements PrerequisiteValidator { /** Checks if the given prerequisite is deprecated and prints a warning if so. */ @Override public void validate( RuleContext.Builder contextBuilder, ConfiguredTargetAndData prerequisite, Attribute attribute) { validateDirectPrerequisiteForDeprecation( contextBuilder, contextBuilder.getRule(), prerequisite, contextBuilder.forAspect()); } /** * Returns whether two packages are considered the same for purposes of deprecation warnings. * Dependencies within the same package do not print deprecation warnings; a package in the * javatests directory may also depend on its corresponding java package without a warning. */ public static boolean isSameLogicalPackage( PackageIdentifier thisPackage, PackageIdentifier prerequisitePackage) { if (thisPackage.equals(prerequisitePackage)) { // If the packages are equal, they are the same logical package (and just the same package). return true; } if (!thisPackage.getRepository().equals(prerequisitePackage.getRepository())) { // If the packages are in different repositories, they are not the same logical package. return false; } // If the packages are in the same repository, it's allowed iff this package is the javatests // companion to the prerequisite java package. String thisPackagePath = thisPackage.getPackageFragment().getPathString(); String prerequisitePackagePath = prerequisitePackage.getPackageFragment().getPathString(); return thisPackagePath.startsWith("javatests/") && prerequisitePackagePath.startsWith("java/") && thisPackagePath.substring("javatests/".length()).equals( prerequisitePackagePath.substring("java/".length())); } /** Returns whether a deprecation warning should be printed for the prerequisite described. */ private static boolean shouldEmitDeprecationWarningFor( String thisDeprecation, PackageIdentifier thisPackage, String prerequisiteDeprecation, PackageIdentifier prerequisitePackage, boolean forAspect) { // Don't report deprecation edges from javatests to java or within a package; // otherwise tests of deprecated code generate nuisance warnings. // Don't report deprecation if the current target is also deprecated, // or if the current context is evaluating an aspect, // as the base target would have already printed the deprecation warnings. return (!forAspect && prerequisiteDeprecation != null && !isSameLogicalPackage(thisPackage, prerequisitePackage) && thisDeprecation == null); } /** Checks if the given prerequisite is deprecated and prints a warning if so. */ public static void validateDirectPrerequisiteForDeprecation( RuleErrorConsumer errors, Rule rule, ConfiguredTargetAndData prerequisite, boolean forAspect) { Target prerequisiteTarget = prerequisite.getTarget(); Label prerequisiteLabel = prerequisiteTarget.getLabel(); PackageIdentifier thatPackage = prerequisiteLabel.getPackageIdentifier(); PackageIdentifier thisPackage = rule.getLabel().getPackageIdentifier(); if (prerequisiteTarget instanceof Rule) { Rule prerequisiteRule = (Rule) prerequisiteTarget; String thisDeprecation = NonconfigurableAttributeMapper.of(rule).has("deprecation", Type.STRING) ? NonconfigurableAttributeMapper.of(rule).get("deprecation", Type.STRING) : null; String thatDeprecation = NonconfigurableAttributeMapper.of(prerequisiteRule).has("deprecation", Type.STRING) ? NonconfigurableAttributeMapper.of(prerequisiteRule) .get("deprecation", Type.STRING) : null; if (shouldEmitDeprecationWarningFor( thisDeprecation, thisPackage, thatDeprecation, thatPackage, forAspect)) { errors.ruleWarning("target '" + rule.getLabel() + "' depends on deprecated target '" + prerequisiteLabel + "': " + thatDeprecation); } } if (prerequisiteTarget instanceof OutputFile) { Rule generatingRule = ((OutputFile) prerequisiteTarget).getGeneratingRule(); String thisDeprecation = NonconfigurableAttributeMapper.of(rule).get("deprecation", Type.STRING); String thatDeprecation = NonconfigurableAttributeMapper.of(generatingRule).get("deprecation", Type.STRING); if (shouldEmitDeprecationWarningFor( thisDeprecation, thisPackage, thatDeprecation, thatPackage, forAspect)) { errors.ruleWarning("target '" + rule.getLabel() + "' depends on the output file " + prerequisiteLabel + " of a deprecated rule " + generatingRule.getLabel() + "': " + thatDeprecation); } } } } /** * A coherent set of options, fragments, aspects and rules; each of these may declare a dependency * on other such sets. */ public interface RuleSet { /** Add stuff to the configured rule class provider builder. */ void init(ConfiguredRuleClassProvider.Builder builder); /** List of required modules. */ ImmutableList requires(); } /** Builder for {@link ConfiguredRuleClassProvider}. */ public static class Builder implements RuleDefinitionEnvironment { private final StringBuilder defaultWorkspaceFilePrefix = new StringBuilder(); private final StringBuilder defaultWorkspaceFileSuffix = new StringBuilder(); private Label preludeLabel; private String runfilesPrefix; private String toolsRepository; private final List configurationFragmentFactories = new ArrayList<>(); private final List buildInfoFactories = new ArrayList<>(); private final List> configurationOptions = new ArrayList<>(); private final Map ruleClassMap = new HashMap<>(); private final Map ruleDefinitionMap = new HashMap<>(); private final Map nativeAspectClassMap = new HashMap<>(); private final Map, RuleClass> ruleMap = new HashMap<>(); private final Digraph> dependencyGraph = new Digraph<>(); private List> universalFragments = new ArrayList<>(); @Nullable private RuleTransitionFactory trimmingTransitionFactory; private OptionsDiffPredicate shouldInvalidateCacheForDiff = OptionsDiffPredicate.ALWAYS_INVALIDATE; private PrerequisiteValidator prerequisiteValidator; private ImmutableList.Builder skylarkBootstraps = ImmutableList.builder(); private ImmutableMap.Builder skylarkAccessibleTopLevels = ImmutableMap.builder(); private Set reservedActionMnemonics = new TreeSet<>(); private BuildConfiguration.ActionEnvironmentProvider actionEnvironmentProvider = (BuildOptions options) -> ActionEnvironment.EMPTY; private ConstraintSemantics constraintSemantics = new ConstraintSemantics(); // TODO(pcloudy): Remove this field after Bazel rule definitions are not used internally. private String nativeLauncherLabel; public Builder setNativeLauncherLabel(String label) { this.nativeLauncherLabel = label; return this; } public Builder addWorkspaceFilePrefix(String contents) { defaultWorkspaceFilePrefix.append(contents); return this; } public Builder addWorkspaceFileSuffix(String contents) { defaultWorkspaceFileSuffix.append(contents); return this; } public Builder setPrelude(String preludeLabelString) { try { this.preludeLabel = Label.parseAbsolute(preludeLabelString, ImmutableMap.of()); } catch (LabelSyntaxException e) { String errorMsg = String.format("Prelude label '%s' is invalid: %s", preludeLabelString, e.getMessage()); throw new IllegalArgumentException(errorMsg); } return this; } public Builder setRunfilesPrefix(String runfilesPrefix) { this.runfilesPrefix = runfilesPrefix; return this; } public Builder setToolsRepository(String toolsRepository) { this.toolsRepository = toolsRepository; return this; } public Builder setPrerequisiteValidator(PrerequisiteValidator prerequisiteValidator) { this.prerequisiteValidator = prerequisiteValidator; return this; } public Builder addBuildInfoFactory(BuildInfoFactory factory) { buildInfoFactories.add(factory); return this; } public Builder addRuleDefinition(RuleDefinition ruleDefinition) { Class ruleDefinitionClass = ruleDefinition.getClass(); ruleDefinitionMap.put(ruleDefinitionClass.getName(), ruleDefinition); dependencyGraph.createNode(ruleDefinitionClass); for (Class ancestor : ruleDefinition.getMetadata().ancestors()) { dependencyGraph.addEdge(ancestor, ruleDefinitionClass); } return this; } public Builder addNativeAspectClass(NativeAspectClass aspectFactoryClass) { nativeAspectClassMap.put(aspectFactoryClass.getName(), aspectFactoryClass); return this; } public Builder addConfigurationOptions(Class configurationOptions) { this.configurationOptions.add(configurationOptions); return this; } /** * Adds an options class and a corresponding factory. There's usually a 1:1:1 correspondence * between option classes, factories, and fragments, such that the factory depends only on the * options class and creates the fragment. This method provides a convenient way of adding both * the options class and the factory in a single call. * *

Note that configuration fragments annotated with a Skylark name must have a unique * name; no two different configuration fragments can share the same name. */ public Builder addConfig( Class options, ConfigurationFragmentFactory factory) { // Enforce that the factory requires the options. Preconditions.checkState(factory.requiredOptions().contains(options)); this.configurationOptions.add(options); this.configurationFragmentFactories.add(factory); return this; } public Builder addConfigurationOptions( Collection> optionsClasses) { this.configurationOptions.addAll(optionsClasses); return this; } /** * Adds a configuration fragment factory. * *

Note that configuration fragments annotated with a Skylark name must have a unique * name; no two different configuration fragments can share the same name. */ public Builder addConfigurationFragment(ConfigurationFragmentFactory factory) { configurationFragmentFactories.add(factory); return this; } public Builder addUniversalConfigurationFragment( Class fragment) { this.universalFragments.add(fragment); return this; } public Builder addSkylarkBootstrap(Bootstrap bootstrap) { this.skylarkBootstraps.add(bootstrap); return this; } public Builder addSkylarkAccessibleTopLevels(String name, Object object) { this.skylarkAccessibleTopLevels.put(name, object); return this; } public Builder addReservedActionMnemonic(String mnemonic) { this.reservedActionMnemonics.add(mnemonic); return this; } public Builder setActionEnvironmentProvider( BuildConfiguration.ActionEnvironmentProvider actionEnvironmentProvider) { this.actionEnvironmentProvider = actionEnvironmentProvider; return this; } /** * Sets the logic that lets rules declare which environments they support and validates rules * don't depend on rules that aren't compatible with the same environments. Defaults to * {@ConstraintSemantics}. See {@ConstraintSemantics} for more details. */ public Builder setConstraintSemantics(ConstraintSemantics constraintSemantics) { this.constraintSemantics = constraintSemantics; return this; } /** * Adds a transition factory that produces a trimming transition to be run over all targets * after other transitions. * *

Transitions are run in the order they're added. * *

This is a temporary measure for supporting trimming of test rules and manual trimming of * feature flags, and support for this transition factory will likely be removed at some point * in the future (whenever automatic trimming is sufficiently workable). */ public Builder addTrimmingTransitionFactory(RuleTransitionFactory factory) { if (trimmingTransitionFactory == null) { trimmingTransitionFactory = Preconditions.checkNotNull(factory); } else { trimmingTransitionFactory = new ComposingRuleTransitionFactory( trimmingTransitionFactory, Preconditions.checkNotNull(factory)); } return this; } /** * Overrides the transition factory run over all targets. * * @see {@link #addTrimmingTransitionFactory(RuleTransitionFactory)} */ @VisibleForTesting(/* for testing trimming transition factories without relying on prod use */ ) public Builder overrideTrimmingTransitionFactoryForTesting(RuleTransitionFactory factory) { trimmingTransitionFactory = null; return this.addTrimmingTransitionFactory(factory); } /** * Sets the predicate which determines whether the analysis cache should be invalidated for the * given options diff. */ public Builder setShouldInvalidateCacheForDiff( OptionsDiffPredicate shouldInvalidateCacheForDiff) { Preconditions.checkState( this.shouldInvalidateCacheForDiff.equals(OptionsDiffPredicate.ALWAYS_INVALIDATE), "Cache invalidation function was already set"); this.shouldInvalidateCacheForDiff = shouldInvalidateCacheForDiff; return this; } /** * Overrides the predicate which determines whether the analysis cache should be invalidated for * the given options diff. */ @VisibleForTesting(/* for testing cache invalidation without relying on prod use */ ) public Builder overrideShouldInvalidateCacheForDiffForTesting( OptionsDiffPredicate shouldInvalidateCacheForDiff) { this.shouldInvalidateCacheForDiff = OptionsDiffPredicate.ALWAYS_INVALIDATE; return this.setShouldInvalidateCacheForDiff(shouldInvalidateCacheForDiff); } private RuleConfiguredTargetFactory createFactory( Class factoryClass) { try { Constructor ctor = factoryClass.getConstructor(); return ctor.newInstance(); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { throw new IllegalStateException(e); } } private RuleClass commitRuleDefinition(Class definitionClass) { RuleDefinition instance = checkNotNull(ruleDefinitionMap.get(definitionClass.getName()), "addRuleDefinition(new %s()) should be called before build()", definitionClass.getName()); RuleDefinition.Metadata metadata = instance.getMetadata(); checkArgument( ruleClassMap.get(metadata.name()) == null, "The rule " + metadata.name() + " was committed already, use another name"); List> ancestors = metadata.ancestors(); checkArgument( metadata.type() == ABSTRACT ^ metadata.factoryClass() != RuleConfiguredTargetFactory.class); checkArgument( (metadata.type() != TEST) || ancestors.contains(BaseRuleClasses.TestBaseRule.class)); RuleClass[] ancestorClasses = new RuleClass[ancestors.size()]; for (int i = 0; i < ancestorClasses.length; i++) { ancestorClasses[i] = ruleMap.get(ancestors.get(i)); if (ancestorClasses[i] == null) { // Ancestors should have been initialized by now throw new IllegalStateException("Ancestor " + ancestors.get(i) + " of " + metadata.name() + " is not initialized"); } } RuleConfiguredTargetFactory factory = null; if (metadata.type() != ABSTRACT) { factory = createFactory(metadata.factoryClass()); } RuleClass.Builder builder = new RuleClass.Builder( metadata.name(), metadata.type(), false, ancestorClasses); builder.factory(factory); RuleClass ruleClass = instance.build(builder, this); ruleMap.put(definitionClass, ruleClass); ruleClassMap.put(ruleClass.getName(), ruleClass); ruleDefinitionMap.put(ruleClass.getName(), instance); return ruleClass; } public ConfiguredRuleClassProvider build() { for (Node> ruleDefinition : dependencyGraph.getTopologicalOrder()) { commitRuleDefinition(ruleDefinition.getLabel()); } return new ConfiguredRuleClassProvider( preludeLabel, runfilesPrefix, toolsRepository, ImmutableMap.copyOf(ruleClassMap), ImmutableMap.copyOf(ruleDefinitionMap), ImmutableMap.copyOf(nativeAspectClassMap), defaultWorkspaceFilePrefix.toString(), defaultWorkspaceFileSuffix.toString(), ImmutableList.copyOf(buildInfoFactories), ImmutableList.copyOf(configurationOptions), ImmutableList.copyOf(configurationFragmentFactories), ImmutableList.copyOf(universalFragments), trimmingTransitionFactory, shouldInvalidateCacheForDiff, prerequisiteValidator, skylarkAccessibleTopLevels.build(), skylarkBootstraps.build(), ImmutableSet.copyOf(reservedActionMnemonics), actionEnvironmentProvider, constraintSemantics); } @Override public Label getToolsLabel(String labelValue) { return Label.parseAbsoluteUnchecked(toolsRepository + labelValue); } @Override public Label getLauncherLabel() { if (nativeLauncherLabel == null) { return null; } return getToolsLabel(nativeLauncherLabel); } @Override public String getToolsRepository() { return toolsRepository; } } /** * Default content that should be added at the beginning of the WORKSPACE file. */ private final String defaultWorkspaceFilePrefix; /** * Default content that should be added at the end of the WORKSPACE file. */ private final String defaultWorkspaceFileSuffix; /** * Label for the prelude file. */ private final Label preludeLabel; /** * The default runfiles prefix. */ private final String runfilesPrefix; /** * The path to the tools repository. */ private final String toolsRepository; /** * Maps rule class name to the metaclass instance for that rule. */ private final ImmutableMap ruleClassMap; /** * Maps rule class name to the rule definition objects. */ private final ImmutableMap ruleDefinitionMap; /** * Maps aspect name to the aspect factory meta class. */ private final ImmutableMap nativeAspectClassMap; /** * The configuration options that affect the behavior of the rules. */ private final ImmutableList> configurationOptions; /** The set of configuration fragment factories. */ private final ImmutableList configurationFragmentFactories; /** The transition factory used to produce the transition that will trim targets. */ @Nullable private final RuleTransitionFactory trimmingTransitionFactory; /** The predicate used to determine whether a diff requires the cache to be invalidated. */ private final OptionsDiffPredicate shouldInvalidateCacheForDiff; /** * Configuration fragments that should be available to all rules even when they don't * explicitly require it. */ private final ImmutableList> universalFragments; private final ImmutableList buildInfoFactories; private final PrerequisiteValidator prerequisiteValidator; private final Environment.GlobalFrame globals; private final ImmutableSet reservedActionMnemonics; private final BuildConfiguration.ActionEnvironmentProvider actionEnvironmentProvider; private final ImmutableMap> configurationFragmentMap; private final ConstraintSemantics constraintSemantics; private ConfiguredRuleClassProvider( Label preludeLabel, String runfilesPrefix, String toolsRepository, ImmutableMap ruleClassMap, ImmutableMap ruleDefinitionMap, ImmutableMap nativeAspectClassMap, String defaultWorkspaceFilePrefix, String defaultWorkspaceFileSuffix, ImmutableList buildInfoFactories, ImmutableList> configurationOptions, ImmutableList configurationFragments, ImmutableList> universalFragments, @Nullable RuleTransitionFactory trimmingTransitionFactory, OptionsDiffPredicate shouldInvalidateCacheForDiff, PrerequisiteValidator prerequisiteValidator, ImmutableMap skylarkAccessibleJavaClasses, ImmutableList skylarkBootstraps, ImmutableSet reservedActionMnemonics, BuildConfiguration.ActionEnvironmentProvider actionEnvironmentProvider, ConstraintSemantics constraintSemantics) { this.preludeLabel = preludeLabel; this.runfilesPrefix = runfilesPrefix; this.toolsRepository = toolsRepository; this.ruleClassMap = ruleClassMap; this.ruleDefinitionMap = ruleDefinitionMap; this.nativeAspectClassMap = nativeAspectClassMap; this.defaultWorkspaceFilePrefix = defaultWorkspaceFilePrefix; this.defaultWorkspaceFileSuffix = defaultWorkspaceFileSuffix; this.buildInfoFactories = buildInfoFactories; this.configurationOptions = configurationOptions; this.configurationFragmentFactories = configurationFragments; this.universalFragments = universalFragments; this.trimmingTransitionFactory = trimmingTransitionFactory; this.shouldInvalidateCacheForDiff = shouldInvalidateCacheForDiff; this.prerequisiteValidator = prerequisiteValidator; this.globals = createGlobals(skylarkAccessibleJavaClasses, skylarkBootstraps); this.reservedActionMnemonics = reservedActionMnemonics; this.actionEnvironmentProvider = actionEnvironmentProvider; this.configurationFragmentMap = createFragmentMap(configurationFragmentFactories); this.constraintSemantics = constraintSemantics; } public PrerequisiteValidator getPrerequisiteValidator() { return prerequisiteValidator; } @Override public Label getPreludeLabel() { return preludeLabel; } @Override public String getRunfilesPrefix() { return runfilesPrefix; } @Override public String getToolsRepository() { return toolsRepository; } @Override public Map getRuleClassMap() { return ruleClassMap; } @Override public Map getNativeAspectClassMap() { return nativeAspectClassMap; } @Override public NativeAspectClass getNativeAspectClass(String key) { return nativeAspectClassMap.get(key); } /** * Returns a list of build info factories that are needed for the supported languages. */ public ImmutableList getBuildInfoFactories() { return buildInfoFactories; } /** * Returns the set of configuration fragments provided by this module. */ public ImmutableList getConfigurationFragments() { return configurationFragmentFactories; } /** * Returns the transition factory used to produce the transition to trim targets. * *

This is a temporary measure for supporting manual trimming of feature flags, and support * for this transition factory will likely be removed at some point in the future (whenever * automatic trimming is sufficiently workable */ @Nullable public RuleTransitionFactory getTrimmingTransitionFactory() { return trimmingTransitionFactory; } /** Returns whether the analysis cache should be invalidated for the given options diff. */ public boolean shouldInvalidateCacheForDiff(OptionsDiff diff, BuildOptions newOptions) { return shouldInvalidateCacheForDiff.apply(diff, newOptions); } /** * Returns the set of configuration options that are supported in this module. */ public ImmutableList> getConfigurationOptions() { return configurationOptions; } /** * Returns the definition of the rule class definition with the specified name. */ public RuleDefinition getRuleClassDefinition(String ruleClassName) { return ruleDefinitionMap.get(ruleClassName); } /** * Returns the configuration fragment that should be available to all rules even when they * don't explicitly require it. */ public ImmutableList> getUniversalFragments() { return universalFragments; } /** * Returns the defaults package for the default settings. */ public String getDefaultsPackageContent(InvocationPolicy invocationPolicy) { return DefaultsPackage.getDefaultsPackageContent(configurationOptions, invocationPolicy); } /** * Returns the defaults package for the given options taken from an optionsProvider. */ public String getDefaultsPackageContent(OptionsClassProvider optionsProvider) { return DefaultsPackage.getDefaultsPackageContent( BuildOptions.of(configurationOptions, optionsProvider)); } /** * Creates a BuildOptions class for the given options taken from an optionsProvider. */ public BuildOptions createBuildOptions(OptionsClassProvider optionsProvider) { return BuildOptions.of(configurationOptions, optionsProvider); } private Environment.GlobalFrame createGlobals( ImmutableMap skylarkAccessibleTopLevels, ImmutableList bootstraps) { ImmutableMap.Builder envBuilder = ImmutableMap.builder(); SkylarkModules.addSkylarkGlobalsToBuilder(envBuilder); envBuilder.putAll(skylarkAccessibleTopLevels.entrySet()); for (Bootstrap bootstrap : bootstraps) { bootstrap.addBindingsToBuilder(envBuilder); } return GlobalFrame.createForBuiltins(envBuilder.build()); } private static ImmutableMap> createFragmentMap( Iterable configurationFragmentFactories) { ImmutableMap.Builder> mapBuilder = ImmutableMap.builder(); for (ConfigurationFragmentFactory fragmentFactory : configurationFragmentFactories) { Class fragmentClass = fragmentFactory.creates(); SkylarkModule fragmentModule = SkylarkInterfaceUtils.getSkylarkModule((fragmentClass)); if (fragmentModule != null) { mapBuilder.put(fragmentModule.name(), fragmentClass); } } return mapBuilder.build(); } private Environment createSkylarkRuleClassEnvironment( Mutability mutability, Environment.GlobalFrame globals, SkylarkSemantics skylarkSemantics, EventHandler eventHandler, String astFileContentHashCode, Map importMap) { Environment env = Environment.builder(mutability) .setGlobals(globals) .setSemantics(skylarkSemantics) .setEventHandler(eventHandler) .setFileContentHashCode(astFileContentHashCode) .setImportedExtensions(importMap) .setPhase(Phase.LOADING) .build(); SkylarkUtils.setToolsRepository(env, toolsRepository); SkylarkUtils.setFragmentMap(env, configurationFragmentMap); return env; } @Override public Environment createSkylarkRuleClassEnvironment( Label extensionLabel, Mutability mutability, SkylarkSemantics skylarkSemantics, EventHandler eventHandler, String astFileContentHashCode, Map importMap) { return createSkylarkRuleClassEnvironment( mutability, globals.withLabel(extensionLabel), skylarkSemantics, eventHandler, astFileContentHashCode, importMap); } @Override public String getDefaultWorkspacePrefix() { return defaultWorkspaceFilePrefix; } @Override public String getDefaultWorkspaceSuffix() { return defaultWorkspaceFileSuffix; } @Override public Map> getConfigurationFragmentMap() { return configurationFragmentMap; } public ConstraintSemantics getConstraintSemantics() { return constraintSemantics; } /** Returns all skylark objects in global scope for this RuleClassProvider. */ public Map getTransitiveGlobalBindings() { return globals.getTransitiveBindings(); } /** Returns all registered {@link BuildConfiguration.Fragment} classes. */ public ImmutableSortedSet> getAllFragments() { ImmutableSortedSet.Builder> fragmentsBuilder = ImmutableSortedSet.orderedBy(BuildConfiguration.lexicalFragmentSorter); for (ConfigurationFragmentFactory factory : getConfigurationFragments()) { fragmentsBuilder.add(factory.creates()); } fragmentsBuilder.addAll(getUniversalFragments()); return fragmentsBuilder.build(); } /** Returns a reserved set of action mnemonics. These cannot be used from a Skylark action. */ public ImmutableSet getReservedActionMnemonics() { return reservedActionMnemonics; } public BuildConfiguration.ActionEnvironmentProvider getActionEnvironmentProvider() { return actionEnvironmentProvider; } }