| // Copyright 2019 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.transitions; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.base.Preconditions; |
| |
| /** |
| * A transition factory that composes two other transition factories in an ordered sequence. |
| * |
| * <p>Example: |
| * |
| * <pre> |
| * transitionFactory1: { someSetting = $oldVal + " foo" } |
| * transitionFactory2: { someSetting = $oldVal + " bar" } |
| * ComposingTransitionFactory(transitionFactory1, transitionFactory2): |
| * { someSetting = $oldVal + " foo bar" } |
| * </pre> |
| */ |
| @AutoValue |
| public abstract class ComposingTransitionFactory<T> implements TransitionFactory<T> { |
| |
| /** |
| * Creates a {@link ComposingTransitionFactory} that applies the given factories in sequence: |
| * {@code fromOptions -> transition1 -> transition2 -> toOptions }. |
| * |
| * <p>Note that this method checks for transition factories that cannot be composed, such as if |
| * one of the transitions is {@link NoTransition} or the host transition, and returns an |
| * efficiently composed transition. |
| */ |
| public static <T> TransitionFactory<T> of( |
| TransitionFactory<T> transitionFactory1, TransitionFactory<T> transitionFactory2) { |
| |
| Preconditions.checkNotNull(transitionFactory1); |
| Preconditions.checkNotNull(transitionFactory2); |
| |
| if (isFinal(transitionFactory1)) { |
| // Since no other transition can be composed with transitionFactory1, use it directly. |
| return transitionFactory1; |
| } else if (NoTransition.isInstance(transitionFactory1)) { |
| // Since transitionFactory1 causes no changes, use transitionFactory2 directly. |
| return transitionFactory2; |
| } |
| |
| if (NoTransition.isInstance(transitionFactory2)) { |
| // Since transitionFactory2 causes no changes, use transitionFactory1 directly. |
| return transitionFactory1; |
| } else if (isFinal(transitionFactory2)) { |
| // When the second transition is null or a HOST transition, there's no need to compose. But |
| // this also |
| // improves performance: host transitions are common, and ConfiguredTargetFunction has special |
| // optimized logic to handle them. If they were buried in the last segment of a |
| // ComposingTransition, those optimizations wouldn't trigger. |
| return transitionFactory2; |
| } |
| |
| return create(transitionFactory1, transitionFactory2); |
| } |
| |
| private static <T> boolean isFinal(TransitionFactory<T> transitionFactory) { |
| return NullTransition.isInstance(transitionFactory) || transitionFactory.isHost(); |
| } |
| |
| private static <T> TransitionFactory<T> create( |
| TransitionFactory<T> transitionFactory1, TransitionFactory<T> transitionFactory2) { |
| return new AutoValue_ComposingTransitionFactory<T>(transitionFactory1, transitionFactory2); |
| } |
| |
| abstract TransitionFactory<T> transitionFactory1(); |
| |
| abstract TransitionFactory<T> transitionFactory2(); |
| |
| @Override |
| public ConfigurationTransition create(T data) { |
| ConfigurationTransition transition1 = transitionFactory1().create(data); |
| ConfigurationTransition transition2 = transitionFactory2().create(data); |
| return new ComposingTransition(transition1, transition2); |
| } |
| |
| @Override |
| public boolean isHost() { |
| return transitionFactory1().isHost() || transitionFactory2().isHost(); |
| } |
| |
| @Override |
| public boolean isSplit() { |
| return transitionFactory1().isSplit() || transitionFactory2().isSplit(); |
| } |
| } |