| // Copyright 2016 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.packages; | |
| import com.google.common.base.Predicate; | |
| import com.google.common.base.Predicates; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.common.collect.Iterables; | |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; | |
| import com.google.devtools.build.lib.util.Preconditions; | |
| /** | |
| * Represents a constraint on a set of providers required by a dependency (of a rule | |
| * or an aspect). | |
| * | |
| * Currently we support three kinds of constraints: | |
| * <ul> | |
| * <li>accept any dependency.</li> | |
| * <li>accept no dependency (used for aspects-on-aspects to indicate | |
| * that an aspect never wants to see any other aspect applied to a target.</li> | |
| * <li>accept a dependency that provides all providers from one of several sets of providers. | |
| * It just so happens that in all current usages these sets are either all | |
| * native providers or all Skylark providers, so this is the only use case this | |
| * class currently supports. | |
| * </li> | |
| * </ul> | |
| */ | |
| @Immutable | |
| public final class RequiredProviders { | |
| /** A constraint: either ANY, NONE, or RESTRICTED */ | |
| private final Constraint constraint; | |
| /** | |
| * Sets of native providers. | |
| * If non-empty, {@link #constraint} is {@link Constraint#RESTRICTED} | |
| */ | |
| private final ImmutableList<ImmutableSet<Class<?>>> nativeProviders; | |
| /** | |
| * Sets of native providers. | |
| * If non-empty, {@link #constraint} is {@link Constraint#RESTRICTED} | |
| */ | |
| private final ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> skylarkProviders; | |
| /** | |
| * Represents one of the constraints as desctibed in {@link RequiredProviders} | |
| */ | |
| private enum Constraint { | |
| /** Accept any dependency */ | |
| ANY { | |
| @Override | |
| public boolean satisfies(AdvertisedProviderSet advertisedProviderSet, | |
| RequiredProviders requiredProviders) { | |
| return true; | |
| } | |
| @Override | |
| public boolean satisfies(Predicate<Class<?>> hasNativeProvider, | |
| Predicate<SkylarkProviderIdentifier> hasSkylarkProvider, | |
| RequiredProviders requiredProviders) { | |
| return true; | |
| } | |
| }, | |
| /** Accept no dependency */ | |
| NONE { | |
| @Override | |
| public boolean satisfies(AdvertisedProviderSet advertisedProviderSet, | |
| RequiredProviders requiredProviders) { | |
| return false; | |
| } | |
| @Override | |
| public boolean satisfies(Predicate<Class<?>> hasNativeProvider, | |
| Predicate<SkylarkProviderIdentifier> hasSkylarkProvider, | |
| RequiredProviders requiredProviders) { | |
| return false; | |
| } | |
| }, | |
| /** Accept a dependency that has all providers from one of the sets. */ | |
| RESTRICTED { | |
| @Override | |
| public boolean satisfies(Predicate<Class<?>> hasNativeProvider, | |
| Predicate<SkylarkProviderIdentifier> hasSkylarkProvider, | |
| RequiredProviders requiredProviders) { | |
| for (ImmutableSet<Class<?>> nativeProviderSet : requiredProviders.nativeProviders) { | |
| if (Iterables.all(nativeProviderSet, hasNativeProvider)) { | |
| return true; | |
| } | |
| } | |
| for (ImmutableSet<SkylarkProviderIdentifier> skylarkProviderSet | |
| : requiredProviders.skylarkProviders) { | |
| if (Iterables.all(skylarkProviderSet, hasSkylarkProvider)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| }; | |
| /** Checks if {@code advertisedProviderSet} satisfies these {@code RequiredProviders} */ | |
| public boolean satisfies(final AdvertisedProviderSet advertisedProviderSet, | |
| RequiredProviders requiredProviders) { | |
| if (advertisedProviderSet.canHaveAnyProvider()) { | |
| return true; | |
| } | |
| return satisfies( | |
| new Predicate<Class<?>>() { | |
| @Override | |
| public boolean apply(Class<?> aClass) { | |
| return advertisedProviderSet.getNativeProviders().contains(aClass); | |
| } | |
| }, | |
| Predicates.in(advertisedProviderSet.getSkylarkProviders()), | |
| requiredProviders | |
| ); | |
| } | |
| /** | |
| * Checks if a set of providers encoded by predicates {@code hasNativeProviders} | |
| * and {@code hasSkylarkProvider} satisfies these {@code RequiredProviders} | |
| */ | |
| abstract boolean satisfies(Predicate<Class<?>> hasNativeProvider, | |
| Predicate<SkylarkProviderIdentifier> hasSkylarkProvider, | |
| RequiredProviders requiredProviders); | |
| } | |
| /** Checks if {@code advertisedProviderSet} satisfies this {@code RequiredProviders} instance. */ | |
| public boolean isSatisfiedBy(AdvertisedProviderSet advertisedProviderSet) { | |
| return constraint.satisfies(advertisedProviderSet, this); | |
| } | |
| /** | |
| * Checks if a set of providers encoded by predicates {@code hasNativeProviders} | |
| * and {@code hasSkylarkProvider} satisfies this {@code RequiredProviders} instance. | |
| */ | |
| public boolean isSatisfiedBy( | |
| Predicate<Class<?>> hasNativeProvider, | |
| Predicate<SkylarkProviderIdentifier> hasSkylarkProvider) { | |
| return constraint.satisfies(hasNativeProvider, hasSkylarkProvider, this); | |
| } | |
| private RequiredProviders( | |
| Constraint constraint, | |
| ImmutableList<ImmutableSet<Class<?>>> nativeProviders, | |
| ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> skylarkProviders) { | |
| this.constraint = constraint; | |
| Preconditions.checkState(constraint.equals(Constraint.RESTRICTED) | |
| || (nativeProviders.isEmpty() && skylarkProviders.isEmpty()) | |
| ); | |
| this.nativeProviders = nativeProviders; | |
| this.skylarkProviders = skylarkProviders; | |
| } | |
| /** | |
| * A builder for {@link RequiredProviders} that accepts any dependency | |
| * unless restriction provider sets are added. | |
| */ | |
| public static Builder acceptAnyBuilder() { | |
| return new Builder(false); | |
| } | |
| /** | |
| * A builder for {@link RequiredProviders} that accepts no dependency | |
| * unless restriction provider sets are added. | |
| */ | |
| public static Builder acceptNoneBuilder() { | |
| return new Builder(true); | |
| } | |
| /** A builder for {@link RequiredProviders} */ | |
| public static class Builder { | |
| private final ImmutableList.Builder<ImmutableSet<Class<?>>> nativeProviders; | |
| private final ImmutableList.Builder<ImmutableSet<SkylarkProviderIdentifier>> skylarkProviders; | |
| private Constraint constraint; | |
| private Builder(boolean acceptNone) { | |
| constraint = acceptNone ? Constraint.NONE : Constraint.ANY; | |
| nativeProviders = ImmutableList.builder(); | |
| skylarkProviders = ImmutableList.builder(); | |
| } | |
| /** | |
| * Add an alternative set of Skylark providers. | |
| * | |
| * If all of these providers are present in the dependency, the dependency satisfies | |
| * {@link RequiredProviders}. | |
| */ | |
| public Builder addSkylarkSet(ImmutableSet<SkylarkProviderIdentifier> skylarkProviderSet) { | |
| constraint = Constraint.RESTRICTED; | |
| Preconditions.checkState(!skylarkProviderSet.isEmpty()); | |
| this.skylarkProviders.add(skylarkProviderSet); | |
| return this; | |
| } | |
| /** | |
| * Add an alternative set of native providers. | |
| * | |
| * If all of these providers are present in the dependency, the dependency satisfies | |
| * {@link RequiredProviders}. | |
| */ | |
| public Builder addNativeSet(ImmutableSet<Class<?>> nativeProviderSet) { | |
| constraint = Constraint.RESTRICTED; | |
| Preconditions.checkState(!nativeProviderSet.isEmpty()); | |
| this.nativeProviders.add(nativeProviderSet); | |
| return this; | |
| } | |
| public RequiredProviders build() { | |
| return new RequiredProviders(constraint, nativeProviders.build(), skylarkProviders.build()); | |
| } | |
| } | |
| } |