blob: 5166cb677c8069d63e2fccec86e6e7e92ab1d27b [file] [log] [blame]
// Copyright 2017 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.config;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Attribute.Transition;
import com.google.devtools.build.lib.packages.RuleClass;
/**
* Maps non-{@link PatchTransition} declarations to their implementable equivalents.
*
* <p>Blaze applies configuration transitions by executing {@link PatchTransition} instances. But
* for legacy reasons, not every transition declaration is a {@link PatchTransition}. The most
* prominent example is {@link Attribute.ConfigurationTransition}, which defines its transitions as
* enums. These transitions are used all over the place. So we need a way to continue to support
* them.
*
* <p>Hence this class.
*
* <p>Going forward, we should eliminate the need for this class by eliminating
* non-{@link PatchTransition} transitions. This is conceptually straightforward: replace
* declarations of the form {@link RuleClass.Builder#cfg(Transition)} with
* {@link RuleClass.Builder#cfg(PatchTransition)}. That way, transition declarations "just work",
* with no extra fuss. But this is a migration that will take some time to complete.
*
* {@link Attribute.ConfigurationTransition#DATA} provides the most complicated challenge. This is
* C++/LIPO logic, and the implementation is in C++ rule code
* ({@link com.google.devtools.build.lib.rules.cpp.transitions.DisableLipoTransition}). But the enum
* is defined in {@link Attribute}, which is in {@code lib.packages}, which has access to neither
* rule-specific nor configuration-specific code. Furthermore, many non-C++ rules declare this
* transition. We ultimately need a cleaner way to inject this rules-specific logic into general
* Blaze code.
*/
public final class DynamicTransitionMapper {
/**
* Use this to declare a no-op transition that keeps the input configuration.
*/
public static final Transition SELF = new Transition() {};
private final ImmutableMap<Transition, Transition> map;
/**
* Creates a new mapper with the given mapping. Any transition not in this mapping triggers
* an {@link IllegalArgumentException}.
*/
public DynamicTransitionMapper(ImmutableMap<Transition, Transition> map) {
this.map = map;
}
/**
* Given an input transition, returns the equivalent transition Blaze's implementation logic knows
* how to apply.
*
* <p>When the input is a {@link PatchTransition}, this just returns the input. This is because
* that's the kind of transition that Blaze natively applies. For this reason, all inputs should
* ideally be {@link PatchTransition}s.
*
* <p>Non-{@link PatchTransition} inputs that aren't mapped here throw an
* {@link IllegalArgumentException}.
*/
public Transition map(Transition fromTransition) {
if (fromTransition instanceof PatchTransition
|| fromTransition instanceof Attribute.SplitTransition<?>
|| fromTransition == null) {
return fromTransition;
}
Transition toTransition = map.get(fromTransition);
if (toTransition == SELF) {
return fromTransition;
} else if (toTransition != null) {
return toTransition;
}
throw new IllegalArgumentException("No dynamic mapping for " + fromTransition.toString());
}
}