blob: 18b35469bb9a5a6650654e6b328dd2d6129228c6 [file] [log] [blame]
// Copyright 2018 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.rules.config;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_KEYED_STRING_DICT;
import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.CoreOptions;
import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
/**
* A transition factory for trimming feature flags manually via an attribute which specifies the
* feature flags used by transitive dependencies.
*/
public class ConfigFeatureFlagTaggedTrimmingTransitionFactory implements TransitionFactory<Rule> {
/** Applies manual trimming to the given set of flags. */
public static final class ConfigFeatureFlagTaggedTrimmingTransition implements PatchTransition {
public static final ConfigFeatureFlagTaggedTrimmingTransition EMPTY =
new ConfigFeatureFlagTaggedTrimmingTransition(ImmutableSortedSet.of());
private final ImmutableSortedSet<Label> flags;
private final int cachedHashCode;
ConfigFeatureFlagTaggedTrimmingTransition(ImmutableSortedSet<Label> flags) {
this.flags = flags;
this.cachedHashCode = this.flags.hashCode();
}
@Override
public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
if (!(options.contains(ConfigFeatureFlagOptions.class)
&& options.get(ConfigFeatureFlagOptions.class)
.enforceTransitiveConfigsForConfigFeatureFlag
&& options.get(CoreOptions.class).useDistinctHostConfiguration)) {
return options;
}
return FeatureFlagValue.trimFlagValues(options, flags);
}
@Override
public boolean equals(Object other) {
return other instanceof ConfigFeatureFlagTaggedTrimmingTransition
&& this.flags.equals(((ConfigFeatureFlagTaggedTrimmingTransition) other).flags);
}
@Override
public int hashCode() {
return cachedHashCode;
}
@Override
public String toString() {
return String.format("ConfigFeatureFlagTaggedTrimmingTransition{flags=%s}", flags);
}
}
private final String attributeName;
public ConfigFeatureFlagTaggedTrimmingTransitionFactory(String attributeName) {
this.attributeName = attributeName;
}
@Override
public PatchTransition create(Rule rule) {
NonconfigurableAttributeMapper attrs = NonconfigurableAttributeMapper.of(rule);
RuleClass ruleClass = rule.getRuleClassObject();
if (ruleClass.getName().equals(ConfigRuleClasses.ConfigFeatureFlagRule.RULE_NAME)) {
return new ConfigFeatureFlagTaggedTrimmingTransition(ImmutableSortedSet.of(rule.getLabel()));
}
ImmutableSortedSet.Builder<Label> requiredLabelsBuilder =
new ImmutableSortedSet.Builder<>(Ordering.natural());
if (attrs.isAttributeValueExplicitlySpecified(attributeName)
&& !attrs.get(attributeName, NODEP_LABEL_LIST).isEmpty()) {
requiredLabelsBuilder.addAll(attrs.get(attributeName, NODEP_LABEL_LIST));
}
if (ruleClass.getTransitionFactory() instanceof ConfigFeatureFlagTransitionFactory) {
String settingAttribute =
((ConfigFeatureFlagTransitionFactory) ruleClass.getTransitionFactory())
.getAttributeName();
// Because the process of setting a flag also creates a dependency on that flag, we need to
// include all the set flags, even if they aren't actually declared as used by this rule.
requiredLabelsBuilder.addAll(attrs.get(settingAttribute, LABEL_KEYED_STRING_DICT).keySet());
}
ImmutableSortedSet<Label> requiredLabels = requiredLabelsBuilder.build();
if (requiredLabels.isEmpty()) {
return ConfigFeatureFlagTaggedTrimmingTransition.EMPTY;
}
return new ConfigFeatureFlagTaggedTrimmingTransition(requiredLabels);
}
}