| // 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; | |
| import static com.google.common.base.Preconditions.checkArgument; | |
| import com.google.common.base.MoreObjects; | |
| import com.google.common.collect.Collections2; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.common.collect.ImmutableSortedSet; | |
| import com.google.devtools.build.lib.analysis.config.Fragment; | |
| import com.google.devtools.build.lib.analysis.config.FragmentClassSet; | |
| import com.google.devtools.build.lib.analysis.config.FragmentOptions; | |
| import com.google.devtools.build.lib.cmdline.Label; | |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; | |
| import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; | |
| import com.google.devtools.build.lib.util.ClassName; | |
| import java.util.List; | |
| /** | |
| * Provides a user-friendly list of the {@link Fragment}s and {@link | |
| * com.google.devtools.build.lib.analysis.config.FragmentOptions} required by this target and its | |
| * transitive dependencies. | |
| * | |
| * <p>See {@link com.google.devtools.build.lib.analysis.config.RequiredFragmentsUtil} for details. | |
| */ | |
| @Immutable | |
| public final class RequiredConfigFragmentsProvider implements TransitiveInfoProvider { | |
| @SerializationConstant | |
| public static final RequiredConfigFragmentsProvider EMPTY = | |
| new RequiredConfigFragmentsProvider( | |
| ImmutableSet.of(), | |
| FragmentClassSet.of(ImmutableSet.of()), | |
| ImmutableSet.of(), | |
| ImmutableSet.of()); | |
| private final ImmutableSet<Class<? extends FragmentOptions>> optionsClasses; | |
| private final FragmentClassSet fragmentClasses; | |
| private final ImmutableSet<String> defines; | |
| private final ImmutableSet<Label> starlarkOptions; | |
| private RequiredConfigFragmentsProvider( | |
| ImmutableSet<Class<? extends FragmentOptions>> optionsClasses, | |
| FragmentClassSet fragmentClasses, | |
| ImmutableSet<String> defines, | |
| ImmutableSet<Label> starlarkOptions) { | |
| this.optionsClasses = optionsClasses; | |
| this.fragmentClasses = fragmentClasses; | |
| this.defines = defines; | |
| this.starlarkOptions = starlarkOptions; | |
| } | |
| public ImmutableSet<Class<? extends FragmentOptions>> getOptionsClasses() { | |
| return optionsClasses; | |
| } | |
| public FragmentClassSet getFragmentClasses() { | |
| return fragmentClasses; | |
| } | |
| public ImmutableSet<String> getDefines() { | |
| return defines; | |
| } | |
| public ImmutableSet<Label> getStarlarkOptions() { | |
| return starlarkOptions; | |
| } | |
| @Override | |
| public String toString() { | |
| return MoreObjects.toStringHelper(this) | |
| .add( | |
| "optionsClasses", | |
| Collections2.transform(optionsClasses, ClassName::getSimpleNameWithOuter)) | |
| .add("fragmentClasses", fragmentClasses) | |
| .add("defines", defines) | |
| .add("starlarkOptions", starlarkOptions) | |
| .toString(); | |
| } | |
| /** Merges the values of two {@link RequiredConfigFragmentsProvider} instances. */ | |
| public static RequiredConfigFragmentsProvider merge( | |
| RequiredConfigFragmentsProvider a, RequiredConfigFragmentsProvider b) { | |
| if (a == EMPTY) { | |
| return b; | |
| } | |
| if (b == EMPTY) { | |
| return a; | |
| } | |
| return builder().merge(a).merge(b).build(); | |
| } | |
| /** Merges the values of one or more {@link RequiredConfigFragmentsProvider} instances. */ | |
| public static RequiredConfigFragmentsProvider merge( | |
| List<RequiredConfigFragmentsProvider> providers) { | |
| checkArgument(!providers.isEmpty()); | |
| RequiredConfigFragmentsProvider.Builder merged = null; | |
| RequiredConfigFragmentsProvider candidate = EMPTY; | |
| for (RequiredConfigFragmentsProvider provider : providers) { | |
| if (provider == EMPTY) { | |
| continue; | |
| } | |
| if (merged != null) { | |
| merged.merge(provider); | |
| } else if (candidate == EMPTY) { | |
| candidate = provider; | |
| } else { | |
| merged = builder().merge(candidate).merge(provider); | |
| } | |
| } | |
| return merged == null ? candidate : merged.build(); | |
| } | |
| public static Builder builder() { | |
| return new Builder(); | |
| } | |
| /** Builder for required config fragments. */ | |
| public static final class Builder { | |
| private final ImmutableSet.Builder<Class<? extends FragmentOptions>> optionsClasses = | |
| ImmutableSet.builder(); | |
| private final ImmutableSet.Builder<Class<? extends Fragment>> fragmentClasses = | |
| ImmutableSortedSet.orderedBy(FragmentClassSet.LEXICAL_FRAGMENT_SORTER); | |
| private final ImmutableSet.Builder<String> defines = ImmutableSet.builder(); | |
| private final ImmutableSet.Builder<Label> starlarkOptions = ImmutableSet.builder(); | |
| private Builder() {} | |
| public Builder addOptionsClass(Class<? extends FragmentOptions> optionsClass) { | |
| optionsClasses.add(optionsClass); | |
| return this; | |
| } | |
| public Builder addOptionsClasses(Iterable<Class<? extends FragmentOptions>> optionsClasses) { | |
| this.optionsClasses.addAll(optionsClasses); | |
| return this; | |
| } | |
| public Builder addFragmentClasses(Iterable<Class<? extends Fragment>> fragmentClasses) { | |
| this.fragmentClasses.addAll(fragmentClasses); | |
| return this; | |
| } | |
| public Builder addDefine(String define) { | |
| defines.add(define); | |
| return this; | |
| } | |
| public Builder addDefines(Iterable<String> defines) { | |
| this.defines.addAll(defines); | |
| return this; | |
| } | |
| public Builder addStarlarkOption(Label starlarkOption) { | |
| starlarkOptions.add(starlarkOption); | |
| return this; | |
| } | |
| public Builder addStarlarkOptions(Iterable<Label> starlarkOptions) { | |
| this.starlarkOptions.addAll(starlarkOptions); | |
| return this; | |
| } | |
| public Builder merge(RequiredConfigFragmentsProvider provider) { | |
| optionsClasses.addAll(provider.optionsClasses); | |
| fragmentClasses.addAll(provider.fragmentClasses); | |
| defines.addAll(provider.defines); | |
| starlarkOptions.addAll(provider.starlarkOptions); | |
| return this; | |
| } | |
| public RequiredConfigFragmentsProvider build() { | |
| ImmutableSet<Class<? extends FragmentOptions>> optionsClasses = this.optionsClasses.build(); | |
| ImmutableSet<Class<? extends Fragment>> fragmentClasses = this.fragmentClasses.build(); | |
| ImmutableSet<String> defines = this.defines.build(); | |
| ImmutableSet<Label> starlarkOptions = this.starlarkOptions.build(); | |
| if (optionsClasses.isEmpty() | |
| && fragmentClasses.isEmpty() | |
| && defines.isEmpty() | |
| && starlarkOptions.isEmpty()) { | |
| return EMPTY; | |
| } | |
| return new RequiredConfigFragmentsProvider( | |
| optionsClasses, FragmentClassSet.of(fragmentClasses), defines, starlarkOptions); | |
| } | |
| } | |
| } |