blob: 97a30fba4bce53e9221ff8cd32ff4c5284aacca1 [file] [log] [blame]
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.analysis;
16
17import com.google.common.annotations.VisibleForTesting;
18import com.google.common.base.Function;
19import com.google.common.base.Preconditions;
20import com.google.common.base.Predicate;
21import com.google.common.cache.LoadingCache;
22import com.google.common.collect.ImmutableList;
Greg Estren00049432015-08-25 16:43:47 +000023import com.google.common.collect.ImmutableListMultimap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010024import com.google.common.collect.ImmutableMap;
25import com.google.common.collect.ImmutableSet;
26import com.google.common.collect.Iterables;
27import com.google.common.collect.ListMultimap;
28import com.google.common.collect.Lists;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.common.collect.Sets;
30import com.google.common.eventbus.EventBus;
31import com.google.devtools.build.lib.actions.Action;
32import com.google.devtools.build.lib.actions.ActionGraph;
33import com.google.devtools.build.lib.actions.Artifact;
34import com.google.devtools.build.lib.actions.ArtifactFactory;
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +000035import com.google.devtools.build.lib.actions.ArtifactOwner;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036import com.google.devtools.build.lib.actions.PackageRootResolver;
37import com.google.devtools.build.lib.actions.Root;
38import com.google.devtools.build.lib.analysis.DependencyResolver.Dependency;
39import com.google.devtools.build.lib.analysis.ExtraActionArtifactsProvider.ExtraArtifactSet;
40import com.google.devtools.build.lib.analysis.config.BinTools;
41import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
42import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
43import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000044import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000045import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Lukacs Berki6916be22015-02-19 13:36:06 +000046import com.google.devtools.build.lib.collect.nestedset.NestedSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
48import com.google.devtools.build.lib.collect.nestedset.Order;
49import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
50import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010051import com.google.devtools.build.lib.events.Event;
52import com.google.devtools.build.lib.events.EventHandler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010053import com.google.devtools.build.lib.events.StoredEventHandler;
Marian Lobur42020002015-09-02 12:22:46 +000054import com.google.devtools.build.lib.packages.AspectParameters;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010055import com.google.devtools.build.lib.packages.Attribute;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000056import com.google.devtools.build.lib.packages.BuildType;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010057import com.google.devtools.build.lib.packages.NoSuchPackageException;
58import com.google.devtools.build.lib.packages.NoSuchTargetException;
59import com.google.devtools.build.lib.packages.NoSuchThingException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010060import com.google.devtools.build.lib.packages.PackageSpecification;
61import com.google.devtools.build.lib.packages.RawAttributeMapper;
62import com.google.devtools.build.lib.packages.Rule;
63import com.google.devtools.build.lib.packages.Target;
64import com.google.devtools.build.lib.packages.TargetUtils;
Ulf Adamsb82a56c2015-09-23 16:56:21 +000065import com.google.devtools.build.lib.pkgcache.LoadedPackageProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010066import com.google.devtools.build.lib.pkgcache.LoadingPhaseRunner.LoadingResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010067import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory;
Googlercdc90e92015-02-11 00:18:07 +000068import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory.CoverageReportActionsWrapper;
Ulf Adamsfc154ae2015-08-31 12:32:14 +000069import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +000070import com.google.devtools.build.lib.skyframe.ActionLookupValue;
Dmitry Lomove2033b12015-08-19 16:57:49 +000071import com.google.devtools.build.lib.skyframe.AspectValue;
72import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010073import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
74import com.google.devtools.build.lib.skyframe.CoverageReportValue;
Dmitry Lomove2033b12015-08-19 16:57:49 +000075import com.google.devtools.build.lib.skyframe.SkyframeAnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import com.google.devtools.build.lib.skyframe.SkyframeBuildView;
77import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
78import com.google.devtools.build.lib.syntax.EvalException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.lib.util.RegexFilter;
80import com.google.devtools.build.lib.vfs.Path;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081import com.google.devtools.build.skyframe.SkyKey;
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +000082import com.google.devtools.build.skyframe.WalkableGraph;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083import com.google.devtools.common.options.Option;
84import com.google.devtools.common.options.OptionsBase;
85
Dmitry Lomove2033b12015-08-19 16:57:49 +000086import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010087import java.util.Collection;
88import java.util.HashMap;
89import java.util.HashSet;
90import java.util.LinkedHashSet;
91import java.util.List;
92import java.util.Map;
93import java.util.Set;
94import java.util.concurrent.ExecutionException;
95import java.util.logging.Logger;
96
97import javax.annotation.Nullable;
98
99/**
100 * <p>The BuildView presents a semantically-consistent and transitively-closed
101 * dependency graph for some set of packages.
102 *
103 * <h2>Package design</h2>
104 *
105 * <p>This package contains the Blaze dependency analysis framework (aka
106 * "analysis phase"). The goal of this code is to perform semantic analysis of
107 * all of the build targets required for a given build, to report
108 * errors/warnings for any problems in the input, and to construct an "action
109 * graph" (see {@code lib.actions} package) correctly representing the work to
110 * be done during the execution phase of the build.
111 *
112 * <p><b>Configurations</b> the inputs to a build come from two sources: the
113 * intrinsic inputs, specified in the BUILD file, are called <em>targets</em>.
114 * The environmental inputs, coming from the build tool, the command-line, or
115 * configuration files, are called the <em>configuration</em>. Only when a
116 * target and a configuration are combined is there sufficient information to
117 * perform a build. </p>
118 *
119 * <p>Targets are implemented by the {@link Target} hierarchy in the {@code
120 * lib.packages} code. Configurations are implemented by {@link
121 * BuildConfiguration}. The pair of these together is represented by an
122 * instance of class {@link ConfiguredTarget}; this is the root of a hierarchy
123 * with different implementations for each kind of target: source file, derived
124 * file, rules, etc.
125 *
126 * <p>The framework code in this package (as opposed to its subpackages) is
127 * responsible for constructing the {@code ConfiguredTarget} graph for a given
128 * target and configuration, taking care of such issues as:
129 * <ul>
130 * <li>caching common subgraphs.
131 * <li>detecting and reporting cycles.
132 * <li>correct propagation of errors through the graph.
133 * <li>reporting universal errors, such as dependencies from production code
134 * to tests, or to experimental branches.
135 * <li>capturing and replaying errors.
136 * <li>maintaining the graph from one build to the next to
137 * avoid unnecessary recomputation.
138 * <li>checking software licenses.
139 * </ul>
140 *
141 * <p>See also {@link ConfiguredTarget} which documents some important
142 * invariants.
143 */
144public class BuildView {
145
146 /**
147 * Options that affect the <i>mechanism</i> of analysis. These are distinct from {@link
148 * com.google.devtools.build.lib.analysis.config.BuildOptions}, which affect the <i>value</i>
149 * of a BuildConfiguration.
150 */
151 public static class Options extends OptionsBase {
152
153 @Option(name = "keep_going",
154 abbrev = 'k',
155 defaultValue = "false",
156 category = "strategy",
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000157 help = "Continue as much as possible after an error. While the"
158 + " target that failed, and those that depend on it, cannot be"
159 + " analyzed (or built), the other prerequisites of these"
160 + " targets can be analyzed (or built) all the same.")
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100161 public boolean keepGoing;
162
163 @Option(name = "analysis_warnings_as_errors",
Janak Ramakrishnanae8e9222015-04-28 17:37:13 +0000164 deprecationWarning = "analysis_warnings_as_errors is now a no-op and will be removed in"
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000165 + " an upcoming Blaze release",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100166 defaultValue = "false",
167 category = "strategy",
168 help = "Treat visible analysis warnings as errors.")
169 public boolean analysisWarningsAsErrors;
170
171 @Option(name = "discard_analysis_cache",
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000172 defaultValue = "false",
173 category = "strategy",
174 help = "Discard the analysis cache immediately after the analysis phase completes."
175 + " Reduces memory usage by ~10%, but makes further incremental builds slower.")
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100176 public boolean discardAnalysisCache;
177
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100178 @Option(name = "experimental_extra_action_filter",
179 defaultValue = "",
180 category = "experimental",
181 converter = RegexFilter.RegexFilterConverter.class,
182 help = "Filters set of targets to schedule extra_actions for.")
183 public RegexFilter extraActionFilter;
184
185 @Option(name = "experimental_extra_action_top_level_only",
186 defaultValue = "false",
187 category = "experimental",
188 help = "Only schedules extra_actions for top level targets.")
189 public boolean extraActionTopLevelOnly;
190
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000191 @Option(name = "experimental_interleave_loading_and_analysis",
192 defaultValue = "false",
193 category = "experimental",
194 help = "Interleave loading and analysis phases, so that one target may be analyzed at"
195 + " the same time as an unrelated target is loaded.")
196 public boolean interleaveLoadingAndAnalysis;
197
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100198 @Option(name = "version_window_for_dirty_node_gc",
199 defaultValue = "0",
200 category = "undocumented",
201 help = "Nodes that have been dirty for more than this many versions will be deleted"
202 + " from the graph upon the next update. Values must be non-negative long integers,"
203 + " or -1 indicating the maximum possible window.")
204 public long versionWindowForDirtyNodeGc;
205 }
206
207 private static Logger LOG = Logger.getLogger(BuildView.class.getName());
208
209 private final BlazeDirectories directories;
210
211 private final SkyframeExecutor skyframeExecutor;
212 private final SkyframeBuildView skyframeBuildView;
213
Ulf Adams59dbf682015-09-17 11:36:43 +0000214 // Same as skyframeExecutor.getPackageManager().
Ulf Adamsb82a56c2015-09-23 16:56:21 +0000215 private final LoadedPackageProvider packageManager;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100216
217 private final BinTools binTools;
218
219 private BuildConfigurationCollection configurations;
220
221 private final ConfiguredRuleClassProvider ruleClassProvider;
222
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100223 /**
224 * A factory class to create the coverage report action. May be null.
225 */
226 @Nullable private final CoverageReportActionFactory coverageReportActionFactory;
227
228 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100229 * Used only for testing that we clear Skyframe caches correctly.
230 * TODO(bazel-team): Remove this once we get rid of legacy Skyframe synchronization.
231 */
Ulf Adams59dbf682015-09-17 11:36:43 +0000232 private boolean skyframeCacheWasInvalidated;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100233
234 /**
235 * If the last build was executed with {@code Options#discard_analysis_cache} and we are not
236 * running Skyframe full, we should clear the legacy data since it is out-of-sync.
237 */
Ulf Adams59dbf682015-09-17 11:36:43 +0000238 private boolean skyframeAnalysisWasDiscarded;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100239
240 @VisibleForTesting
241 public Set<SkyKey> getSkyframeEvaluatedTargetKeysForTesting() {
242 return skyframeBuildView.getEvaluatedTargetKeys();
243 }
244
245 /** The number of targets freshly evaluated in the last analysis run. */
246 public int getTargetsVisited() {
247 return skyframeBuildView.getEvaluatedTargetKeys().size();
248 }
249
250 /**
251 * Returns true iff Skyframe was invalidated during the analysis phase.
252 * TODO(bazel-team): Remove this once we do not need to keep legacy in sync with Skyframe.
253 */
254 @VisibleForTesting
255 boolean wasSkyframeCacheInvalidatedDuringAnalysis() {
256 return skyframeCacheWasInvalidated;
257 }
258
Ulf Adams59dbf682015-09-17 11:36:43 +0000259 public BuildView(BlazeDirectories directories,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100260 ConfiguredRuleClassProvider ruleClassProvider,
261 SkyframeExecutor skyframeExecutor,
262 BinTools binTools, CoverageReportActionFactory coverageReportActionFactory) {
263 this.directories = directories;
Ulf Adams59dbf682015-09-17 11:36:43 +0000264 this.packageManager = skyframeExecutor.getPackageManager();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100265 this.binTools = binTools;
266 this.coverageReportActionFactory = coverageReportActionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100267 this.ruleClassProvider = ruleClassProvider;
268 this.skyframeExecutor = Preconditions.checkNotNull(skyframeExecutor);
Ulf Adams89eefd72015-09-23 08:00:43 +0000269 this.skyframeBuildView = skyframeExecutor.getSkyframeBuildView();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100270 }
271
272 /** Returns the action graph. */
273 public ActionGraph getActionGraph() {
274 return new ActionGraph() {
275 @Override
276 public Action getGeneratingAction(Artifact artifact) {
277 return skyframeExecutor.getGeneratingAction(artifact);
278 }
279 };
280 }
281
282 /**
283 * Returns whether the given configured target has errors.
284 */
285 @VisibleForTesting
286 public boolean hasErrors(ConfiguredTarget configuredTarget) {
287 return configuredTarget == null;
288 }
289
290 /**
291 * Sets the configurations. Not thread-safe. DO NOT CALL except from tests!
292 */
293 @VisibleForTesting
Ulf Adams79f05212015-02-27 16:40:00 +0000294 public void setConfigurationsForTesting(BuildConfigurationCollection configurations) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100295 this.configurations = configurations;
Greg Estren00049432015-08-25 16:43:47 +0000296 skyframeBuildView.setTopLevelHostConfiguration(configurations.getHostConfiguration());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100297 }
298
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100299 public ArtifactFactory getArtifactFactory() {
Ulf Adams89eefd72015-09-23 08:00:43 +0000300 return skyframeBuildView.getArtifactFactory();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100301 }
302
303 @VisibleForTesting
304 WorkspaceStatusAction getLastWorkspaceBuildInfoActionForTesting() {
305 return skyframeExecutor.getLastWorkspaceStatusActionForTesting();
306 }
307
308 /**
309 * Returns a corresponding ConfiguredTarget, if one exists; otherwise throws an {@link
310 * NoSuchConfiguredTargetException}.
311 */
312 @ThreadSafe
313 private ConfiguredTarget getConfiguredTarget(Target target, BuildConfiguration config)
314 throws NoSuchConfiguredTargetException {
315 ConfiguredTarget result =
316 getExistingConfiguredTarget(target.getLabel(), config);
317 if (result == null) {
318 throw new NoSuchConfiguredTargetException(target.getLabel(), config);
319 }
320 return result;
321 }
322
323 /**
324 * Obtains a {@link ConfiguredTarget} given a {@code label}, by delegating
325 * to the package cache and
326 * {@link #getConfiguredTarget(Target, BuildConfiguration)}.
327 */
328 public ConfiguredTarget getConfiguredTarget(Label label, BuildConfiguration config)
329 throws NoSuchPackageException, NoSuchTargetException, NoSuchConfiguredTargetException {
330 return getConfiguredTarget(packageManager.getLoadedTarget(label), config);
331 }
332
Ulf Adamse7704672015-09-21 14:37:41 +0000333 public Iterable<ConfiguredTarget> getDirectPrerequisites(ConfiguredTarget ct,
334 BuildConfigurationCollection configurations)
Florian Weikert4b67d4f2015-09-14 13:35:34 +0000335 throws InterruptedException {
Ulf Adamse7704672015-09-21 14:37:41 +0000336 return getDirectPrerequisites(ct, null, configurations);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100337 }
338
Michael Staib638c5482015-07-16 08:53:21 +0000339 public Iterable<ConfiguredTarget> getDirectPrerequisites(
Ulf Adamse7704672015-09-21 14:37:41 +0000340 ConfiguredTarget ct, @Nullable final LoadingCache<Label, Target> targetCache,
341 BuildConfigurationCollection configurations)
Florian Weikert4b67d4f2015-09-14 13:35:34 +0000342 throws InterruptedException {
Greg Estren00049432015-08-25 16:43:47 +0000343 return skyframeExecutor.getConfiguredTargets(ct.getConfiguration(),
Ulf Adamse7704672015-09-21 14:37:41 +0000344 getDirectPrerequisiteDependencies(ct, targetCache, configurations), false);
Michael Staib638c5482015-07-16 08:53:21 +0000345 }
346
347 public Iterable<Dependency> getDirectPrerequisiteDependencies(
Ulf Adamse7704672015-09-21 14:37:41 +0000348 ConfiguredTarget ct, @Nullable final LoadingCache<Label, Target> targetCache,
349 BuildConfigurationCollection configurations)
Florian Weikert4b67d4f2015-09-14 13:35:34 +0000350 throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100351 if (!(ct.getTarget() instanceof Rule)) {
352 return ImmutableList.of();
353 }
354
355 class SilentDependencyResolver extends DependencyResolver {
356 @Override
357 protected void invalidVisibilityReferenceHook(TargetAndConfiguration node, Label label) {
358 // The error must have been reported already during analysis.
359 }
360
361 @Override
362 protected void invalidPackageGroupReferenceHook(TargetAndConfiguration node, Label label) {
363 // The error must have been reported already during analysis.
364 }
365
366 @Override
367 protected Target getTarget(Label label) throws NoSuchThingException {
368 if (targetCache == null) {
369 return packageManager.getLoadedTarget(label);
370 }
371
372 try {
373 return targetCache.get(label);
374 } catch (ExecutionException e) {
375 // All lookups should succeed because we should not be looking up any targets in error.
376 throw new IllegalStateException(e);
377 }
378 }
379 }
380
381 DependencyResolver dependencyResolver = new SilentDependencyResolver();
382 TargetAndConfiguration ctgNode =
383 new TargetAndConfiguration(ct.getTarget(), ct.getConfiguration());
Greg Estren00049432015-08-25 16:43:47 +0000384 return dependencyResolver.dependentNodes(ctgNode, configurations.getHostConfiguration(),
385 getConfigurableAttributeKeys(ctgNode));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100386 }
387
388 /**
389 * Returns ConfigMatchingProvider instances corresponding to the configurable attribute keys
390 * present in this rule's attributes.
391 */
392 private Set<ConfigMatchingProvider> getConfigurableAttributeKeys(TargetAndConfiguration ctg) {
393 if (!(ctg.getTarget() instanceof Rule)) {
394 return ImmutableSet.of();
395 }
396 Rule rule = (Rule) ctg.getTarget();
397 ImmutableSet.Builder<ConfigMatchingProvider> keys = ImmutableSet.builder();
398 RawAttributeMapper mapper = RawAttributeMapper.of(rule);
399 for (Attribute attribute : rule.getAttributes()) {
400 for (Label label : mapper.getConfigurabilityKeys(attribute.getName(), attribute.getType())) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +0000401 if (BuildType.Selector.isReservedLabel(label)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100402 continue;
403 }
404 try {
405 ConfiguredTarget ct = getConfiguredTarget(label, ctg.getConfiguration());
406 keys.add(Preconditions.checkNotNull(ct.getProvider(ConfigMatchingProvider.class)));
Ulf Adams07dba942015-03-05 14:47:37 +0000407 } catch (
408 NoSuchPackageException | NoSuchTargetException | NoSuchConfiguredTargetException e) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100409 // All lookups should succeed because we should not be looking up any targets in error.
410 throw new IllegalStateException(e);
411 }
412 }
413 }
414 return keys.build();
415 }
416
417 public TransitiveInfoCollection getGeneratingRule(OutputFileConfiguredTarget target) {
418 return target.getGeneratingRule();
419 }
420
421 @Override
422 public int hashCode() {
423 throw new UnsupportedOperationException(); // avoid nondeterminism
424 }
425
426 /**
427 * Return value for {@link BuildView#update} and {@code BuildTool.prepareToBuild}.
428 */
429 public static final class AnalysisResult {
430
Dmitry Lomove2033b12015-08-19 16:57:49 +0000431 public static final AnalysisResult EMPTY =
432 new AnalysisResult(
433 ImmutableList.<ConfiguredTarget>of(),
434 ImmutableList.<AspectValue>of(),
435 null,
436 null,
437 null,
438 ImmutableList.<Artifact>of(),
439 ImmutableList.<ConfiguredTarget>of(),
440 ImmutableList.<ConfiguredTarget>of(),
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000441 null,
442 ImmutableMap.<PackageIdentifier, Path>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100443
444 private final ImmutableList<ConfiguredTarget> targetsToBuild;
445 @Nullable private final ImmutableList<ConfiguredTarget> targetsToTest;
446 @Nullable private final String error;
447 private final ActionGraph actionGraph;
448 private final ImmutableSet<Artifact> artifactsToBuild;
449 private final ImmutableSet<ConfiguredTarget> parallelTests;
450 private final ImmutableSet<ConfiguredTarget> exclusiveTests;
451 @Nullable private final TopLevelArtifactContext topLevelContext;
Dmitry Lomove2033b12015-08-19 16:57:49 +0000452 private final ImmutableList<AspectValue> aspects;
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000453 private final ImmutableMap<PackageIdentifier, Path> packageRoots;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100454
455 private AnalysisResult(
Dmitry Lomove2033b12015-08-19 16:57:49 +0000456 Collection<ConfiguredTarget> targetsToBuild,
457 Collection<AspectValue> aspects,
458 Collection<ConfiguredTarget> targetsToTest,
459 @Nullable String error,
460 ActionGraph actionGraph,
461 Collection<Artifact> artifactsToBuild,
462 Collection<ConfiguredTarget> parallelTests,
463 Collection<ConfiguredTarget> exclusiveTests,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000464 TopLevelArtifactContext topLevelContext,
465 ImmutableMap<PackageIdentifier, Path> packageRoots) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100466 this.targetsToBuild = ImmutableList.copyOf(targetsToBuild);
Dmitry Lomove2033b12015-08-19 16:57:49 +0000467 this.aspects = ImmutableList.copyOf(aspects);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100468 this.targetsToTest = targetsToTest == null ? null : ImmutableList.copyOf(targetsToTest);
469 this.error = error;
470 this.actionGraph = actionGraph;
471 this.artifactsToBuild = ImmutableSet.copyOf(artifactsToBuild);
472 this.parallelTests = ImmutableSet.copyOf(parallelTests);
473 this.exclusiveTests = ImmutableSet.copyOf(exclusiveTests);
474 this.topLevelContext = topLevelContext;
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000475 this.packageRoots = packageRoots;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100476 }
477
478 /**
479 * Returns configured targets to build.
480 */
481 public Collection<ConfiguredTarget> getTargetsToBuild() {
482 return targetsToBuild;
483 }
484
485 /**
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000486 * The map from package names to the package root where each package was found; this is used to
487 * set up the symlink tree.
488 */
489 public ImmutableMap<PackageIdentifier, Path> getPackageRoots() {
490 return packageRoots;
491 }
492
493 /**
Dmitry Lomove2033b12015-08-19 16:57:49 +0000494 * Returns aspects of configured targets to build.
495 *
496 * <p>If this list is empty, build the targets returned by {@code getTargetsToBuild()}.
497 * Otherwise, only build these aspects of the targets returned by {@code getTargetsToBuild()}.
498 */
499 public Collection<AspectValue> getAspects() {
500 return aspects;
501 }
502
503 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100504 * Returns the configured targets to run as tests, or {@code null} if testing was not
505 * requested (e.g. "build" command rather than "test" command).
506 */
507 @Nullable
508 public Collection<ConfiguredTarget> getTargetsToTest() {
509 return targetsToTest;
510 }
511
512 public ImmutableSet<Artifact> getAdditionalArtifactsToBuild() {
513 return artifactsToBuild;
514 }
515
516 public ImmutableSet<ConfiguredTarget> getExclusiveTests() {
517 return exclusiveTests;
518 }
519
520 public ImmutableSet<ConfiguredTarget> getParallelTests() {
521 return parallelTests;
522 }
523
524 /**
525 * Returns an error description (if any).
526 */
527 @Nullable public String getError() {
528 return error;
529 }
530
Ulf Adams988bb212015-08-25 12:51:48 +0000531 public boolean hasError() {
532 return error != null;
533 }
534
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100535 /**
536 * Returns the action graph.
537 */
538 public ActionGraph getActionGraph() {
539 return actionGraph;
540 }
541
542 public TopLevelArtifactContext getTopLevelContext() {
543 return topLevelContext;
544 }
545 }
546
547
548 /**
549 * Returns the collection of configured targets corresponding to any of the provided targets.
550 */
551 @VisibleForTesting
552 static Iterable<? extends ConfiguredTarget> filterTestsByTargets(
553 Collection<? extends ConfiguredTarget> targets,
554 final Set<? extends Target> allowedTargets) {
Dmitry Lomove2033b12015-08-19 16:57:49 +0000555 return Iterables.filter(
556 targets,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100557 new Predicate<ConfiguredTarget>() {
558 @Override
Dmitry Lomove2033b12015-08-19 16:57:49 +0000559 public boolean apply(ConfiguredTarget rule) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100560 return allowedTargets.contains(rule.getTarget());
561 }
562 });
563 }
564
Ulf Adams59dbf682015-09-17 11:36:43 +0000565 private void prepareToBuild(BuildConfigurationCollection configurations,
566 PackageRootResolver resolver) throws ViewCreationFailedException {
Janak Ramakrishnan317bf222015-03-31 14:35:16 +0000567 for (BuildConfiguration config : configurations.getAllConfigurations()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100568 config.prepareToBuild(directories.getExecRoot(), getArtifactFactory(), resolver);
569 }
570 }
571
572 @ThreadCompatible
Dmitry Lomove2033b12015-08-19 16:57:49 +0000573 public AnalysisResult update(
574 LoadingResult loadingResult,
575 BuildConfigurationCollection configurations,
576 List<String> aspects,
577 Options viewOptions,
578 TopLevelArtifactContext topLevelOptions,
579 EventHandler eventHandler,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000580 EventBus eventBus,
581 boolean loadingEnabled)
Dmitry Lomove2033b12015-08-19 16:57:49 +0000582 throws ViewCreationFailedException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100583 LOG.info("Starting analysis");
584 pollInterruptedStatus();
585
586 skyframeBuildView.resetEvaluatedConfiguredTargetKeysSet();
587
588 Collection<Target> targets = loadingResult.getTargets();
589 eventBus.post(new AnalysisPhaseStartedEvent(targets));
590
591 skyframeCacheWasInvalidated = false;
592 // Clear all cached ConfiguredTargets on configuration change. We need to do this explicitly
593 // because we need to make sure that the legacy action graph does not contain multiple actions
594 // with different versions of the same (target/host/etc.) configuration.
595 // In the future the action graph will be probably be keyed by configurations, which should
596 // obviate the need for this workaround.
597 //
598 // Also if --discard_analysis_cache was used in the last build we want to clear the legacy
599 // data.
600 if ((this.configurations != null && !configurations.equals(this.configurations))
601 || skyframeAnalysisWasDiscarded) {
Nathan Harmatad87167e2015-06-18 23:46:33 +0000602 LOG.info("Discarding analysis cache: configurations have changed.");
603
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100604 skyframeExecutor.dropConfiguredTargets();
605 skyframeCacheWasInvalidated = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100606 }
607 skyframeAnalysisWasDiscarded = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100608 this.configurations = configurations;
Greg Estren00049432015-08-25 16:43:47 +0000609 skyframeBuildView.setTopLevelHostConfiguration(this.configurations.getHostConfiguration());
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000610
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100611 // Determine the configurations.
Ulf Adams59dbf682015-09-17 11:36:43 +0000612 List<TargetAndConfiguration> nodes = nodesForTargets(configurations, targets);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100613
614 List<ConfiguredTargetKey> targetSpecs =
615 Lists.transform(nodes, new Function<TargetAndConfiguration, ConfiguredTargetKey>() {
616 @Override
617 public ConfiguredTargetKey apply(TargetAndConfiguration node) {
618 return new ConfiguredTargetKey(node.getLabel(), node.getConfiguration());
619 }
620 });
621
Dmitry Lomove2033b12015-08-19 16:57:49 +0000622 List<AspectKey> aspectKeys = new ArrayList<>();
623 for (String aspect : aspects) {
624 @SuppressWarnings("unchecked")
625 final Class<? extends ConfiguredAspectFactory> aspectFactoryClass =
626 (Class<? extends ConfiguredAspectFactory>)
627 ruleClassProvider.getAspectFactoryMap().get(aspect);
628 if (aspectFactoryClass != null) {
629 for (ConfiguredTargetKey targetSpec : targetSpecs) {
630 aspectKeys.add(
631 AspectValue.createAspectKey(
632 targetSpec.getLabel(), targetSpec.getConfiguration(), aspectFactoryClass));
633 }
634 } else {
635 throw new ViewCreationFailedException("Aspect '" + aspect + "' is unknown");
636 }
637 }
638
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000639 // Configuration of some BuildConfiguration.Fragments may require information about
640 // artifactRoots, so we need to set them before calling prepareToBuild. In that case loading
641 // phase has to be enabled.
642 if (loadingEnabled) {
Ulf Adams59dbf682015-09-17 11:36:43 +0000643 setArtifactRoots(loadingResult.getPackageRoots(), configurations);
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000644 }
Ulf Adams5b9009b2015-09-24 09:52:53 +0000645 prepareToBuild(configurations, new SkyframePackageRootResolver(skyframeExecutor, eventHandler));
Ulf Adams3ab82f72015-09-04 12:10:53 +0000646 skyframeExecutor.injectWorkspaceStatusData();
Dmitry Lomove2033b12015-08-19 16:57:49 +0000647 SkyframeAnalysisResult skyframeAnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100648 try {
Dmitry Lomove2033b12015-08-19 16:57:49 +0000649 skyframeAnalysisResult =
650 skyframeBuildView.configureTargets(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000651 eventHandler, targetSpecs, aspectKeys, eventBus, viewOptions.keepGoing);
Ulf Adams59dbf682015-09-17 11:36:43 +0000652 setArtifactRoots(skyframeAnalysisResult.getPackageRoots(), configurations);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100653 } finally {
654 skyframeBuildView.clearInvalidatedConfiguredTargets();
655 }
656
657 int numTargetsToAnalyze = nodes.size();
Dmitry Lomove2033b12015-08-19 16:57:49 +0000658 int numSuccessful = skyframeAnalysisResult.getConfiguredTargets().size();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100659 boolean analysisSuccessful = (numSuccessful == numTargetsToAnalyze);
660 if (0 < numSuccessful && numSuccessful < numTargetsToAnalyze) {
661 String msg = String.format("Analysis succeeded for only %d of %d top-level targets",
662 numSuccessful, numTargetsToAnalyze);
663 eventHandler.handle(Event.info(msg));
664 LOG.info(msg);
665 }
666
Dmitry Lomove2033b12015-08-19 16:57:49 +0000667 AnalysisResult result =
668 createResult(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000669 eventHandler,
Dmitry Lomove2033b12015-08-19 16:57:49 +0000670 loadingResult,
671 topLevelOptions,
672 viewOptions,
673 skyframeAnalysisResult.getConfiguredTargets(),
674 skyframeAnalysisResult.getAspects(),
675 skyframeAnalysisResult.getWalkableGraph(),
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000676 skyframeAnalysisResult.getPackageRoots(),
Dmitry Lomove2033b12015-08-19 16:57:49 +0000677 analysisSuccessful);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100678 LOG.info("Finished analysis");
679 return result;
680 }
681
Dmitry Lomove2033b12015-08-19 16:57:49 +0000682 private AnalysisResult createResult(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000683 EventHandler eventHandler,
Dmitry Lomove2033b12015-08-19 16:57:49 +0000684 LoadingResult loadingResult,
685 TopLevelArtifactContext topLevelOptions,
686 BuildView.Options viewOptions,
687 Collection<ConfiguredTarget> configuredTargets,
688 Collection<AspectValue> aspects,
689 final WalkableGraph graph,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000690 ImmutableMap<PackageIdentifier, Path> packageRoots,
Dmitry Lomove2033b12015-08-19 16:57:49 +0000691 boolean analysisSuccessful)
692 throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100693 Collection<Target> testsToRun = loadingResult.getTestsToRun();
694 Collection<ConfiguredTarget> allTargetsToTest = null;
695 if (testsToRun != null) {
696 // Determine the subset of configured targets that are meant to be run as tests.
697 allTargetsToTest = Lists.newArrayList(
698 filterTestsByTargets(configuredTargets, Sets.newHashSet(testsToRun)));
699 }
700
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100701 Set<Artifact> artifactsToBuild = new HashSet<>();
702 Set<ConfiguredTarget> parallelTests = new HashSet<>();
703 Set<ConfiguredTarget> exclusiveTests = new HashSet<>();
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000704
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100705 // build-info and build-changelist.
Ulf Adams5b9009b2015-09-24 09:52:53 +0000706 Collection<Artifact> buildInfoArtifacts =
707 skyframeExecutor.getWorkspaceStatusArtifacts(eventHandler);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100708 Preconditions.checkState(buildInfoArtifacts.size() == 2, buildInfoArtifacts);
709 artifactsToBuild.addAll(buildInfoArtifacts);
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000710
711 // Extra actions
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100712 addExtraActionsIfRequested(viewOptions, artifactsToBuild, configuredTargets);
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000713
714 // Coverage
715 NestedSet<Artifact> baselineCoverageArtifacts = getBaselineCoverageArtifacts(configuredTargets);
716 Iterables.addAll(artifactsToBuild, baselineCoverageArtifacts);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100717 if (coverageReportActionFactory != null) {
Googlercdc90e92015-02-11 00:18:07 +0000718 CoverageReportActionsWrapper actionsWrapper;
719 actionsWrapper = coverageReportActionFactory.createCoverageReportActionsWrapper(
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100720 allTargetsToTest,
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000721 baselineCoverageArtifacts,
Ulf Adams89eefd72015-09-23 08:00:43 +0000722 getArtifactFactory(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100723 CoverageReportValue.ARTIFACT_OWNER);
Googlercdc90e92015-02-11 00:18:07 +0000724 if (actionsWrapper != null) {
725 ImmutableList <Action> actions = actionsWrapper.getActions();
726 skyframeExecutor.injectCoverageReportData(actions);
727 artifactsToBuild.addAll(actionsWrapper.getCoverageOutputs());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100728 }
729 }
730
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000731 // Tests. This must come last, so that the exclusive tests are scheduled after everything else.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100732 scheduleTestsIfRequested(parallelTests, exclusiveTests, topLevelOptions, allTargetsToTest);
733
734 String error = !loadingResult.hasLoadingError()
735 ? (analysisSuccessful
736 ? null
737 : "execution phase succeeded, but not all targets were analyzed")
738 : "execution phase succeeded, but there were loading phase errors";
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +0000739
740 final ActionGraph actionGraph = new ActionGraph() {
741 @Nullable
742 @Override
743 public Action getGeneratingAction(Artifact artifact) {
744 ArtifactOwner artifactOwner = artifact.getArtifactOwner();
745 if (artifactOwner instanceof ActionLookupValue.ActionLookupKey) {
746 SkyKey key = ActionLookupValue.key((ActionLookupValue.ActionLookupKey) artifactOwner);
747 ActionLookupValue val = (ActionLookupValue) graph.getValue(key);
748 return val == null ? null : val.getGeneratingAction(artifact);
749 }
750 return null;
751 }
752 };
Dmitry Lomove2033b12015-08-19 16:57:49 +0000753 return new AnalysisResult(
754 configuredTargets,
755 aspects,
756 allTargetsToTest,
757 error,
758 actionGraph,
759 artifactsToBuild,
760 parallelTests,
761 exclusiveTests,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000762 topLevelOptions,
763 packageRoots);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100764 }
765
Lukacs Berki6916be22015-02-19 13:36:06 +0000766 private static NestedSet<Artifact> getBaselineCoverageArtifacts(
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100767 Collection<ConfiguredTarget> configuredTargets) {
Lukacs Berki6916be22015-02-19 13:36:06 +0000768 NestedSetBuilder<Artifact> baselineCoverageArtifacts = NestedSetBuilder.stableOrder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100769 for (ConfiguredTarget target : configuredTargets) {
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000770 InstrumentedFilesProvider provider = target.getProvider(InstrumentedFilesProvider.class);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100771 if (provider != null) {
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000772 baselineCoverageArtifacts.addTransitive(provider.getBaselineCoverageArtifacts());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100773 }
774 }
Lukacs Berki6916be22015-02-19 13:36:06 +0000775 return baselineCoverageArtifacts.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100776 }
777
778 private void addExtraActionsIfRequested(BuildView.Options viewOptions,
779 Set<Artifact> artifactsToBuild, Iterable<ConfiguredTarget> topLevelTargets) {
780 NestedSetBuilder<ExtraArtifactSet> builder = NestedSetBuilder.stableOrder();
781 for (ConfiguredTarget topLevel : topLevelTargets) {
782 ExtraActionArtifactsProvider provider = topLevel.getProvider(
783 ExtraActionArtifactsProvider.class);
784 if (provider != null) {
785 if (viewOptions.extraActionTopLevelOnly) {
786 builder.add(ExtraArtifactSet.of(topLevel.getLabel(), provider.getExtraActionArtifacts()));
787 } else {
788 builder.addTransitive(provider.getTransitiveExtraActionArtifacts());
789 }
790 }
791 }
792
793 RegexFilter filter = viewOptions.extraActionFilter;
794 for (ExtraArtifactSet set : builder.build()) {
795 boolean filterMatches = filter == null || filter.isIncluded(set.getLabel().toString());
796 if (filterMatches) {
Ulf Adams07dba942015-03-05 14:47:37 +0000797 artifactsToBuild.addAll(set.getArtifacts());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100798 }
799 }
800 }
801
802 private static void scheduleTestsIfRequested(Collection<ConfiguredTarget> targetsToTest,
803 Collection<ConfiguredTarget> targetsToTestExclusive, TopLevelArtifactContext topLevelOptions,
804 Collection<ConfiguredTarget> allTestTargets) {
Lukacs Berki3f4d4e92015-02-24 10:28:26 +0000805 Set<String> outputGroups = topLevelOptions.outputGroups();
Lukacs Berki1e79b962015-03-03 10:59:21 +0000806 if (!outputGroups.contains(OutputGroupProvider.FILES_TO_COMPILE)
807 && !outputGroups.contains(OutputGroupProvider.COMPILATION_PREREQUISITES)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100808 && allTestTargets != null) {
809 scheduleTests(targetsToTest, targetsToTestExclusive, allTestTargets,
810 topLevelOptions.runTestsExclusively());
811 }
812 }
813
814
815 /**
816 * Returns set of artifacts representing test results, writing into targetsToTest and
817 * targetsToTestExclusive.
818 */
819 private static void scheduleTests(Collection<ConfiguredTarget> targetsToTest,
820 Collection<ConfiguredTarget> targetsToTestExclusive,
821 Collection<ConfiguredTarget> allTestTargets,
822 boolean isExclusive) {
823 for (ConfiguredTarget target : allTestTargets) {
824 if (target.getTarget() instanceof Rule) {
825 boolean exclusive =
826 isExclusive || TargetUtils.isExclusiveTestRule((Rule) target.getTarget());
827 Collection<ConfiguredTarget> testCollection = exclusive
828 ? targetsToTestExclusive
829 : targetsToTest;
830 testCollection.add(target);
831 }
832 }
833 }
834
835 @VisibleForTesting
Ulf Adams59dbf682015-09-17 11:36:43 +0000836 List<TargetAndConfiguration> nodesForTargets(BuildConfigurationCollection configurations,
837 Collection<Target> targets) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100838 // We use a hash set here to remove duplicate nodes; this can happen for input files and package
839 // groups.
840 LinkedHashSet<TargetAndConfiguration> nodes = new LinkedHashSet<>(targets.size());
841 for (BuildConfiguration config : configurations.getTargetConfigurations()) {
842 for (Target target : targets) {
843 nodes.add(new TargetAndConfiguration(target,
844 BuildConfigurationCollection.configureTopLevelTarget(config, target)));
845 }
846 }
847 return ImmutableList.copyOf(nodes);
848 }
849
850 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100851 * Returns an existing ConfiguredTarget for the specified target and
852 * configuration, or null if none exists. No validity check is done.
853 */
854 @ThreadSafe
855 public ConfiguredTarget getExistingConfiguredTarget(Target target, BuildConfiguration config) {
856 return getExistingConfiguredTarget(target.getLabel(), config);
857 }
858
859 /**
860 * Returns an existing ConfiguredTarget for the specified node, or null if none exists. No
861 * validity check is done.
862 */
863 @ThreadSafe
864 private ConfiguredTarget getExistingConfiguredTarget(
865 Label label, BuildConfiguration configuration) {
866 return Iterables.getFirst(
867 skyframeExecutor.getConfiguredTargets(
Greg Estren00049432015-08-25 16:43:47 +0000868 configuration, ImmutableList.of(new Dependency(label, configuration)), true),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100869 null);
870 }
871
Ulf Adamse7704672015-09-21 14:37:41 +0000872 private ListMultimap<Attribute, ConfiguredTarget> getPrerequisiteMapForTesting(
873 ConfiguredTarget target, BuildConfigurationCollection configurations)
874 throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100875 DependencyResolver resolver = new DependencyResolver() {
876 @Override
877 protected void invalidVisibilityReferenceHook(TargetAndConfiguration node, Label label) {
878 throw new RuntimeException("bad visibility on " + label + " during testing unexpected");
879 }
880
881 @Override
882 protected void invalidPackageGroupReferenceHook(TargetAndConfiguration node, Label label) {
883 throw new RuntimeException("bad package group on " + label + " during testing unexpected");
884 }
885
886 @Override
887 protected Target getTarget(Label label) throws NoSuchThingException {
888 return packageManager.getLoadedTarget(label);
889 }
890 };
891 TargetAndConfiguration ctNode = new TargetAndConfiguration(target);
892 ListMultimap<Attribute, Dependency> depNodeNames;
893 try {
Marian Lobur702cad72015-09-02 09:53:58 +0000894 depNodeNames = resolver.dependentNodeMap(ctNode, configurations.getHostConfiguration(),
Marian Lobur42020002015-09-02 12:22:46 +0000895 /*aspect=*/null, AspectParameters.EMPTY, getConfigurableAttributeKeys(ctNode));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100896 } catch (EvalException e) {
897 throw new IllegalStateException(e);
898 }
899
Greg Estren00049432015-08-25 16:43:47 +0000900 ImmutableMap<Dependency, ConfiguredTarget> cts = skyframeExecutor.getConfiguredTargetMap(
901 ctNode.getConfiguration(), ImmutableSet.copyOf(depNodeNames.values()), false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100902
Greg Estren00049432015-08-25 16:43:47 +0000903 ImmutableListMultimap.Builder<Attribute, ConfiguredTarget> builder =
904 ImmutableListMultimap.builder();
905 for (Map.Entry<Attribute, Dependency> entry : depNodeNames.entries()) {
906 builder.put(entry.getKey(), cts.get(entry.getValue()));
907 }
908 return builder.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100909 }
910
911 /**
912 * Sets the possible artifact roots in the artifact factory. This allows the
913 * factory to resolve paths with unknown roots to artifacts.
914 * <p>
915 * <em>Note: This must be called before any call to
916 * {@link #getConfiguredTarget(Label, BuildConfiguration)}
917 * </em>
918 */
919 @VisibleForTesting // for BuildViewTestCase
Ulf Adams59dbf682015-09-17 11:36:43 +0000920 public void setArtifactRoots(ImmutableMap<PackageIdentifier, Path> packageRoots,
921 BuildConfigurationCollection configurations) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100922 Map<Path, Root> rootMap = new HashMap<>();
923 Map<PackageIdentifier, Root> realPackageRoots = new HashMap<>();
924 for (Map.Entry<PackageIdentifier, Path> entry : packageRoots.entrySet()) {
925 Root root = rootMap.get(entry.getValue());
926 if (root == null) {
927 root = Root.asSourceRoot(entry.getValue());
928 rootMap.put(entry.getValue(), root);
929 }
930 realPackageRoots.put(entry.getKey(), root);
931 }
932 // Source Artifact roots:
Ulf Adams89eefd72015-09-23 08:00:43 +0000933 getArtifactFactory().setPackageRoots(realPackageRoots);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100934
935 // Derived Artifact roots:
936 ImmutableList.Builder<Root> roots = ImmutableList.builder();
937
938 // build-info.txt and friends; this root is not configuration specific.
939 roots.add(directories.getBuildDataDirectory());
940
941 // The roots for each configuration - duplicates are automatically removed in the call below.
942 for (BuildConfiguration cfg : configurations.getAllConfigurations()) {
943 roots.addAll(cfg.getRoots());
944 }
945
Ulf Adams89eefd72015-09-23 08:00:43 +0000946 getArtifactFactory().setDerivedArtifactRoots(roots.build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100947 }
948
949 /**
950 * Returns a configured target for the specified target and configuration.
951 * This should only be called from test cases, and is needed, because
952 * plain {@link #getConfiguredTarget(Target, BuildConfiguration)} does not
953 * construct the configured target graph, and would thus fail if called from
954 * outside an update.
955 */
956 @VisibleForTesting
957 public ConfiguredTarget getConfiguredTargetForTesting(Label label, BuildConfiguration config)
958 throws NoSuchPackageException, NoSuchTargetException {
959 return getConfiguredTargetForTesting(packageManager.getLoadedTarget(label), config);
960 }
961
962 @VisibleForTesting
963 public ConfiguredTarget getConfiguredTargetForTesting(Target target, BuildConfiguration config) {
964 return skyframeExecutor.getConfiguredTargetForTesting(target.getLabel(), config);
965 }
966
967 /**
968 * Returns a RuleContext which is the same as the original RuleContext of the target parameter.
969 */
970 @VisibleForTesting
Florian Weikert4b67d4f2015-09-14 13:35:34 +0000971 public RuleContext getRuleContextForTesting(
Ulf Adamse7704672015-09-21 14:37:41 +0000972 ConfiguredTarget target, StoredEventHandler eventHandler,
973 BuildConfigurationCollection configurations) throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100974 BuildConfiguration config = target.getConfiguration();
975 CachingAnalysisEnvironment analysisEnvironment =
Ulf Adams89eefd72015-09-23 08:00:43 +0000976 new CachingAnalysisEnvironment(getArtifactFactory(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100977 new ConfiguredTargetKey(target.getLabel(), config),
978 /*isSystemEnv=*/false, config.extendedSanityChecks(), eventHandler,
979 /*skyframeEnv=*/null, config.isActionsEnabled(), binTools);
Ulf Adams79f05212015-02-27 16:40:00 +0000980 return new RuleContext.Builder(analysisEnvironment,
Greg Estren00049432015-08-25 16:43:47 +0000981 (Rule) target.getTarget(), config, configurations.getHostConfiguration(),
Greg Estren9eb1cf02015-06-26 22:18:35 +0000982 ruleClassProvider.getPrerequisiteValidator())
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100983 .setVisibility(NestedSetBuilder.<PackageSpecification>create(
984 Order.STABLE_ORDER, PackageSpecification.EVERYTHING))
Ulf Adamse7704672015-09-21 14:37:41 +0000985 .setPrerequisites(getPrerequisiteMapForTesting(target, configurations))
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100986 .setConfigConditions(ImmutableSet.<ConfigMatchingProvider>of())
987 .build();
Ulf Adams79f05212015-02-27 16:40:00 +0000988 }
989
990 /**
991 * Creates and returns a rule context that is equivalent to the one that was used to create the
992 * given configured target.
993 */
994 @VisibleForTesting
Ulf Adamse7704672015-09-21 14:37:41 +0000995 public RuleContext getRuleContextForTesting(ConfiguredTarget target, AnalysisEnvironment env,
996 BuildConfigurationCollection configurations) throws InterruptedException {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000997 BuildConfiguration targetConfig = target.getConfiguration();
Ulf Adams79f05212015-02-27 16:40:00 +0000998 return new RuleContext.Builder(
Greg Estren00049432015-08-25 16:43:47 +0000999 env, (Rule) target.getTarget(), targetConfig, configurations.getHostConfiguration(),
Ulf Adams79f05212015-02-27 16:40:00 +00001000 ruleClassProvider.getPrerequisiteValidator())
1001 .setVisibility(NestedSetBuilder.<PackageSpecification>create(
1002 Order.STABLE_ORDER, PackageSpecification.EVERYTHING))
Ulf Adamse7704672015-09-21 14:37:41 +00001003 .setPrerequisites(getPrerequisiteMapForTesting(target, configurations))
Ulf Adams79f05212015-02-27 16:40:00 +00001004 .setConfigConditions(ImmutableSet.<ConfigMatchingProvider>of())
1005 .build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001006 }
1007
1008 /**
Googler9263b462015-05-13 19:22:24 +00001009 * For a configured target dependentTarget, returns the desired configured target
1010 * that is depended upon. Useful for obtaining the a target with aspects
1011 * required by the dependent.
1012 */
1013 @VisibleForTesting
1014 public ConfiguredTarget getPrerequisiteConfiguredTargetForTesting(
Ulf Adamse7704672015-09-21 14:37:41 +00001015 ConfiguredTarget dependentTarget, ConfiguredTarget desiredTarget,
1016 BuildConfigurationCollection configurations)
Florian Weikert4b67d4f2015-09-14 13:35:34 +00001017 throws InterruptedException {
Googler9263b462015-05-13 19:22:24 +00001018 Collection<ConfiguredTarget> configuredTargets =
Ulf Adamse7704672015-09-21 14:37:41 +00001019 getPrerequisiteMapForTesting(dependentTarget, configurations).values();
Googler9263b462015-05-13 19:22:24 +00001020 for (ConfiguredTarget ct : configuredTargets) {
1021 if (ct.getLabel().equals(desiredTarget.getLabel())) {
1022 return ct;
1023 }
1024 }
1025 return null;
1026 }
1027
1028 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001029 * Tests and clears the current thread's pending "interrupted" status, and
1030 * throws InterruptedException iff it was set.
1031 */
1032 protected final void pollInterruptedStatus() throws InterruptedException {
1033 if (Thread.interrupted()) {
1034 throw new InterruptedException();
1035 }
1036 }
1037
1038 /**
1039 * Drops the analysis cache. If building with Skyframe, targets in {@code topLevelTargets} may
1040 * remain in the cache for use during the execution phase.
1041 *
1042 * @see BuildView.Options#discardAnalysisCache
1043 */
1044 public void clearAnalysisCache(Collection<ConfiguredTarget> topLevelTargets) {
1045 // TODO(bazel-team): Consider clearing packages too to save more memory.
1046 skyframeAnalysisWasDiscarded = true;
1047 skyframeExecutor.clearAnalysisCache(topLevelTargets);
1048 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001049}