| // Copyright 2014 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.cache.Cache; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.analysis.BlazeDirectories; |
| import com.google.devtools.build.lib.analysis.ConfigurationCollectionFactory; |
| import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible; |
| import com.google.devtools.build.lib.events.EventHandler; |
| import com.google.devtools.build.lib.util.Preconditions; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import javax.annotation.Nullable; |
| |
| /** |
| * A factory class for {@link BuildConfiguration} instances. This is unfortunately more complex, |
| * and should be simplified in the future, if |
| * possible. Right now, creating a {@link BuildConfiguration} instance involves |
| * creating the instance itself and the related configurations; the main method |
| * is {@link #createConfigurations}. |
| * |
| * <p>Avoid calling into this class, and instead use the skyframe infrastructure to obtain |
| * configuration instances. |
| * |
| * <p>Blaze currently relies on the fact that all {@link BuildConfiguration} |
| * instances used in a build can be constructed ahead of time by this class. |
| */ |
| @ThreadCompatible // safe as long as separate instances are used |
| public final class ConfigurationFactory { |
| private final List<ConfigurationFragmentFactory> configurationFragmentFactories; |
| private final ConfigurationCollectionFactory configurationCollectionFactory; |
| |
| public ConfigurationFactory( |
| ConfigurationCollectionFactory configurationCollectionFactory, |
| ConfigurationFragmentFactory... fragmentFactories) { |
| this(configurationCollectionFactory, ImmutableList.copyOf(fragmentFactories)); |
| } |
| |
| public ConfigurationFactory( |
| ConfigurationCollectionFactory configurationCollectionFactory, |
| List<ConfigurationFragmentFactory> fragmentFactories) { |
| this.configurationCollectionFactory = |
| Preconditions.checkNotNull(configurationCollectionFactory); |
| this.configurationFragmentFactories = ImmutableList.copyOf(fragmentFactories); |
| } |
| |
| /** |
| * Creates a set of build configurations with top-level configuration having the given options. |
| * |
| * <p>The rest of the configurations are created based on the set of transitions available. |
| */ |
| @Nullable |
| public BuildConfiguration createConfigurations( |
| Cache<String, BuildConfiguration> cache, |
| PackageProviderForConfigurations loadedPackageProvider, |
| BuildOptions buildOptions, |
| EventHandler errorEventListener) |
| throws InvalidConfigurationException, InterruptedException { |
| return configurationCollectionFactory.createConfigurations(this, cache, |
| loadedPackageProvider, buildOptions, errorEventListener); |
| } |
| |
| /** |
| * Returns a {@link com.google.devtools.build.lib.analysis.config.BuildConfiguration} based on the |
| * given set of build options. |
| * |
| * <p>If the configuration has already been created, re-uses it, otherwise, creates a new one. |
| */ |
| @Nullable |
| public BuildConfiguration getConfiguration( |
| PackageProviderForConfigurations loadedPackageProvider, |
| BuildOptions buildOptions, |
| boolean actionsDisabled, |
| Cache<String, BuildConfiguration> cache) |
| throws InvalidConfigurationException, InterruptedException { |
| |
| String cacheKey = buildOptions.computeCacheKey(); |
| BuildConfiguration result = cache.getIfPresent(cacheKey); |
| if (result != null) { |
| return result; |
| } |
| |
| Map<Class<? extends Fragment>, Fragment> fragments = new HashMap<>(); |
| // Create configuration fragments |
| for (ConfigurationFragmentFactory factory : configurationFragmentFactories) { |
| Class<? extends Fragment> fragmentType = factory.creates(); |
| Fragment fragment = loadedPackageProvider.getFragment(buildOptions, fragmentType); |
| if (fragment != null && fragments.get(fragment.getClass()) == null) { |
| fragments.put(fragment.getClass(), fragment); |
| } |
| } |
| BlazeDirectories directories = loadedPackageProvider.getDirectories(); |
| if (loadedPackageProvider.valuesMissing()) { |
| return null; |
| } |
| |
| result = new BuildConfiguration(directories, fragments, buildOptions, actionsDisabled); |
| cache.put(cacheKey, result); |
| return result; |
| } |
| |
| public List<ConfigurationFragmentFactory> getFactories() { |
| return configurationFragmentFactories; |
| } |
| } |