blob: 025d8b54cceee9abffe7ac04cdd6c5bdd1255920 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
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;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.common.base.Predicate;
20import com.google.common.cache.LoadingCache;
21import com.google.common.collect.ImmutableList;
Greg Estren00049432015-08-25 16:43:47 +000022import com.google.common.collect.ImmutableListMultimap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023import com.google.common.collect.ImmutableMap;
24import com.google.common.collect.ImmutableSet;
25import com.google.common.collect.Iterables;
26import com.google.common.collect.ListMultimap;
27import com.google.common.collect.Lists;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028import com.google.common.collect.Sets;
29import com.google.common.eventbus.EventBus;
30import com.google.devtools.build.lib.actions.Action;
31import com.google.devtools.build.lib.actions.ActionGraph;
32import com.google.devtools.build.lib.actions.Artifact;
33import com.google.devtools.build.lib.actions.ArtifactFactory;
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +000034import com.google.devtools.build.lib.actions.ArtifactOwner;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035import com.google.devtools.build.lib.actions.PackageRootResolver;
36import com.google.devtools.build.lib.actions.Root;
37import com.google.devtools.build.lib.analysis.DependencyResolver.Dependency;
38import com.google.devtools.build.lib.analysis.ExtraActionArtifactsProvider.ExtraArtifactSet;
39import com.google.devtools.build.lib.analysis.config.BinTools;
40import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
41import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
42import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000043import com.google.devtools.build.lib.cmdline.Label;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000044import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Lukacs Berki6916be22015-02-19 13:36:06 +000045import com.google.devtools.build.lib.collect.nestedset.NestedSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
47import com.google.devtools.build.lib.collect.nestedset.Order;
48import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049import com.google.devtools.build.lib.events.Event;
50import com.google.devtools.build.lib.events.EventHandler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010051import com.google.devtools.build.lib.events.StoredEventHandler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010052import com.google.devtools.build.lib.packages.Attribute;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000053import com.google.devtools.build.lib.packages.BuildType;
Dmitry Lomov8ff06452015-10-21 19:16:30 +000054import com.google.devtools.build.lib.packages.NativeAspectClass;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010055import com.google.devtools.build.lib.packages.NoSuchThingException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056import com.google.devtools.build.lib.packages.PackageSpecification;
57import com.google.devtools.build.lib.packages.RawAttributeMapper;
58import com.google.devtools.build.lib.packages.Rule;
59import com.google.devtools.build.lib.packages.Target;
60import com.google.devtools.build.lib.packages.TargetUtils;
Ulf Adamsb82a56c2015-09-23 16:56:21 +000061import com.google.devtools.build.lib.pkgcache.LoadedPackageProvider;
Ulf Adamsd8099362015-11-02 14:56:46 +000062import com.google.devtools.build.lib.pkgcache.LoadingResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010063import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory;
Googlercdc90e92015-02-11 00:18:07 +000064import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory.CoverageReportActionsWrapper;
Ulf Adamsfc154ae2015-08-31 12:32:14 +000065import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +000066import com.google.devtools.build.lib.skyframe.ActionLookupValue;
Dmitry Lomove2033b12015-08-19 16:57:49 +000067import com.google.devtools.build.lib.skyframe.AspectValue;
Dmitry Lomovc15ba2e2015-10-30 15:50:01 +000068import com.google.devtools.build.lib.skyframe.AspectValue.AspectValueKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010069import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
70import com.google.devtools.build.lib.skyframe.CoverageReportValue;
Dmitry Lomove2033b12015-08-19 16:57:49 +000071import com.google.devtools.build.lib.skyframe.SkyframeAnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010072import com.google.devtools.build.lib.skyframe.SkyframeBuildView;
73import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
74import com.google.devtools.build.lib.syntax.EvalException;
Mark Schaller6df81792015-12-10 18:47:47 +000075import com.google.devtools.build.lib.util.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import com.google.devtools.build.lib.util.RegexFilter;
77import com.google.devtools.build.lib.vfs.Path;
Dmitry Lomov0b832ce2015-10-20 10:03:14 +000078import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.skyframe.SkyKey;
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +000080import com.google.devtools.build.skyframe.WalkableGraph;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081import com.google.devtools.common.options.Option;
82import com.google.devtools.common.options.OptionsBase;
83
Dmitry Lomove2033b12015-08-19 16:57:49 +000084import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085import java.util.Collection;
86import java.util.HashMap;
87import java.util.HashSet;
88import java.util.LinkedHashSet;
89import java.util.List;
90import java.util.Map;
91import java.util.Set;
92import java.util.concurrent.ExecutionException;
93import java.util.logging.Logger;
94
95import javax.annotation.Nullable;
96
97/**
98 * <p>The BuildView presents a semantically-consistent and transitively-closed
99 * dependency graph for some set of packages.
100 *
101 * <h2>Package design</h2>
102 *
103 * <p>This package contains the Blaze dependency analysis framework (aka
104 * "analysis phase"). The goal of this code is to perform semantic analysis of
105 * all of the build targets required for a given build, to report
106 * errors/warnings for any problems in the input, and to construct an "action
107 * graph" (see {@code lib.actions} package) correctly representing the work to
108 * be done during the execution phase of the build.
109 *
110 * <p><b>Configurations</b> the inputs to a build come from two sources: the
111 * intrinsic inputs, specified in the BUILD file, are called <em>targets</em>.
112 * The environmental inputs, coming from the build tool, the command-line, or
113 * configuration files, are called the <em>configuration</em>. Only when a
114 * target and a configuration are combined is there sufficient information to
115 * perform a build. </p>
116 *
117 * <p>Targets are implemented by the {@link Target} hierarchy in the {@code
118 * lib.packages} code. Configurations are implemented by {@link
119 * BuildConfiguration}. The pair of these together is represented by an
120 * instance of class {@link ConfiguredTarget}; this is the root of a hierarchy
121 * with different implementations for each kind of target: source file, derived
122 * file, rules, etc.
123 *
124 * <p>The framework code in this package (as opposed to its subpackages) is
125 * responsible for constructing the {@code ConfiguredTarget} graph for a given
126 * target and configuration, taking care of such issues as:
127 * <ul>
128 * <li>caching common subgraphs.
129 * <li>detecting and reporting cycles.
130 * <li>correct propagation of errors through the graph.
131 * <li>reporting universal errors, such as dependencies from production code
132 * to tests, or to experimental branches.
133 * <li>capturing and replaying errors.
134 * <li>maintaining the graph from one build to the next to
135 * avoid unnecessary recomputation.
136 * <li>checking software licenses.
137 * </ul>
138 *
139 * <p>See also {@link ConfiguredTarget} which documents some important
140 * invariants.
141 */
142public class BuildView {
143
144 /**
145 * Options that affect the <i>mechanism</i> of analysis. These are distinct from {@link
146 * com.google.devtools.build.lib.analysis.config.BuildOptions}, which affect the <i>value</i>
147 * of a BuildConfiguration.
148 */
149 public static class Options extends OptionsBase {
150
151 @Option(name = "keep_going",
152 abbrev = 'k',
153 defaultValue = "false",
154 category = "strategy",
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000155 help = "Continue as much as possible after an error. While the"
156 + " target that failed, and those that depend on it, cannot be"
157 + " analyzed (or built), the other prerequisites of these"
158 + " targets can be analyzed (or built) all the same.")
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100159 public boolean keepGoing;
160
161 @Option(name = "analysis_warnings_as_errors",
Janak Ramakrishnanae8e9222015-04-28 17:37:13 +0000162 deprecationWarning = "analysis_warnings_as_errors is now a no-op and will be removed in"
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000163 + " an upcoming Blaze release",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100164 defaultValue = "false",
165 category = "strategy",
166 help = "Treat visible analysis warnings as errors.")
167 public boolean analysisWarningsAsErrors;
168
169 @Option(name = "discard_analysis_cache",
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000170 defaultValue = "false",
171 category = "strategy",
172 help = "Discard the analysis cache immediately after the analysis phase completes."
173 + " Reduces memory usage by ~10%, but makes further incremental builds slower.")
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100174 public boolean discardAnalysisCache;
175
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100176 @Option(name = "experimental_extra_action_filter",
177 defaultValue = "",
178 category = "experimental",
179 converter = RegexFilter.RegexFilterConverter.class,
180 help = "Filters set of targets to schedule extra_actions for.")
181 public RegexFilter extraActionFilter;
182
183 @Option(name = "experimental_extra_action_top_level_only",
184 defaultValue = "false",
185 category = "experimental",
186 help = "Only schedules extra_actions for top level targets.")
187 public boolean extraActionTopLevelOnly;
188
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000189 @Option(name = "experimental_interleave_loading_and_analysis",
190 defaultValue = "false",
191 category = "experimental",
192 help = "Interleave loading and analysis phases, so that one target may be analyzed at"
193 + " the same time as an unrelated target is loaded.")
194 public boolean interleaveLoadingAndAnalysis;
195
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100196 @Option(name = "version_window_for_dirty_node_gc",
197 defaultValue = "0",
198 category = "undocumented",
199 help = "Nodes that have been dirty for more than this many versions will be deleted"
200 + " from the graph upon the next update. Values must be non-negative long integers,"
201 + " or -1 indicating the maximum possible window.")
202 public long versionWindowForDirtyNodeGc;
203 }
204
205 private static Logger LOG = Logger.getLogger(BuildView.class.getName());
206
207 private final BlazeDirectories directories;
208
209 private final SkyframeExecutor skyframeExecutor;
210 private final SkyframeBuildView skyframeBuildView;
211
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100212 private final ConfiguredRuleClassProvider ruleClassProvider;
213
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100214 /**
215 * A factory class to create the coverage report action. May be null.
216 */
217 @Nullable private final CoverageReportActionFactory coverageReportActionFactory;
218
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100219 @VisibleForTesting
220 public Set<SkyKey> getSkyframeEvaluatedTargetKeysForTesting() {
221 return skyframeBuildView.getEvaluatedTargetKeys();
222 }
223
224 /** The number of targets freshly evaluated in the last analysis run. */
225 public int getTargetsVisited() {
226 return skyframeBuildView.getEvaluatedTargetKeys().size();
227 }
228
Ulf Adams59dbf682015-09-17 11:36:43 +0000229 public BuildView(BlazeDirectories directories,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100230 ConfiguredRuleClassProvider ruleClassProvider,
231 SkyframeExecutor skyframeExecutor,
Ulf Adams5a96d532015-09-26 09:00:57 +0000232 CoverageReportActionFactory coverageReportActionFactory) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100233 this.directories = directories;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100234 this.coverageReportActionFactory = coverageReportActionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100235 this.ruleClassProvider = ruleClassProvider;
236 this.skyframeExecutor = Preconditions.checkNotNull(skyframeExecutor);
Ulf Adams89eefd72015-09-23 08:00:43 +0000237 this.skyframeBuildView = skyframeExecutor.getSkyframeBuildView();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100238 }
239
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100240 /**
241 * Returns whether the given configured target has errors.
242 */
243 @VisibleForTesting
244 public boolean hasErrors(ConfiguredTarget configuredTarget) {
245 return configuredTarget == null;
246 }
247
248 /**
249 * Sets the configurations. Not thread-safe. DO NOT CALL except from tests!
250 */
251 @VisibleForTesting
Ulf Adams79f05212015-02-27 16:40:00 +0000252 public void setConfigurationsForTesting(BuildConfigurationCollection configurations) {
Ulf Adams003fe962015-09-26 09:51:39 +0000253 skyframeBuildView.setConfigurations(configurations);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100254 }
255
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100256 public ArtifactFactory getArtifactFactory() {
Ulf Adams89eefd72015-09-23 08:00:43 +0000257 return skyframeBuildView.getArtifactFactory();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100258 }
259
260 @VisibleForTesting
261 WorkspaceStatusAction getLastWorkspaceBuildInfoActionForTesting() {
262 return skyframeExecutor.getLastWorkspaceStatusActionForTesting();
263 }
264
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100265 public TransitiveInfoCollection getGeneratingRule(OutputFileConfiguredTarget target) {
266 return target.getGeneratingRule();
267 }
268
269 @Override
270 public int hashCode() {
271 throw new UnsupportedOperationException(); // avoid nondeterminism
272 }
273
274 /**
275 * Return value for {@link BuildView#update} and {@code BuildTool.prepareToBuild}.
276 */
277 public static final class AnalysisResult {
278
Dmitry Lomove2033b12015-08-19 16:57:49 +0000279 public static final AnalysisResult EMPTY =
280 new AnalysisResult(
281 ImmutableList.<ConfiguredTarget>of(),
282 ImmutableList.<AspectValue>of(),
283 null,
284 null,
285 null,
286 ImmutableList.<Artifact>of(),
287 ImmutableList.<ConfiguredTarget>of(),
288 ImmutableList.<ConfiguredTarget>of(),
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000289 null,
290 ImmutableMap.<PackageIdentifier, Path>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100291
292 private final ImmutableList<ConfiguredTarget> targetsToBuild;
293 @Nullable private final ImmutableList<ConfiguredTarget> targetsToTest;
294 @Nullable private final String error;
295 private final ActionGraph actionGraph;
296 private final ImmutableSet<Artifact> artifactsToBuild;
297 private final ImmutableSet<ConfiguredTarget> parallelTests;
298 private final ImmutableSet<ConfiguredTarget> exclusiveTests;
299 @Nullable private final TopLevelArtifactContext topLevelContext;
Dmitry Lomove2033b12015-08-19 16:57:49 +0000300 private final ImmutableList<AspectValue> aspects;
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000301 private final ImmutableMap<PackageIdentifier, Path> packageRoots;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100302
303 private AnalysisResult(
Dmitry Lomove2033b12015-08-19 16:57:49 +0000304 Collection<ConfiguredTarget> targetsToBuild,
305 Collection<AspectValue> aspects,
306 Collection<ConfiguredTarget> targetsToTest,
307 @Nullable String error,
308 ActionGraph actionGraph,
309 Collection<Artifact> artifactsToBuild,
310 Collection<ConfiguredTarget> parallelTests,
311 Collection<ConfiguredTarget> exclusiveTests,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000312 TopLevelArtifactContext topLevelContext,
313 ImmutableMap<PackageIdentifier, Path> packageRoots) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100314 this.targetsToBuild = ImmutableList.copyOf(targetsToBuild);
Dmitry Lomove2033b12015-08-19 16:57:49 +0000315 this.aspects = ImmutableList.copyOf(aspects);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100316 this.targetsToTest = targetsToTest == null ? null : ImmutableList.copyOf(targetsToTest);
317 this.error = error;
318 this.actionGraph = actionGraph;
319 this.artifactsToBuild = ImmutableSet.copyOf(artifactsToBuild);
320 this.parallelTests = ImmutableSet.copyOf(parallelTests);
321 this.exclusiveTests = ImmutableSet.copyOf(exclusiveTests);
322 this.topLevelContext = topLevelContext;
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000323 this.packageRoots = packageRoots;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100324 }
325
326 /**
327 * Returns configured targets to build.
328 */
329 public Collection<ConfiguredTarget> getTargetsToBuild() {
330 return targetsToBuild;
331 }
332
333 /**
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000334 * The map from package names to the package root where each package was found; this is used to
335 * set up the symlink tree.
336 */
337 public ImmutableMap<PackageIdentifier, Path> getPackageRoots() {
338 return packageRoots;
339 }
340
341 /**
Dmitry Lomove2033b12015-08-19 16:57:49 +0000342 * Returns aspects of configured targets to build.
343 *
344 * <p>If this list is empty, build the targets returned by {@code getTargetsToBuild()}.
345 * Otherwise, only build these aspects of the targets returned by {@code getTargetsToBuild()}.
346 */
347 public Collection<AspectValue> getAspects() {
348 return aspects;
349 }
350
351 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100352 * Returns the configured targets to run as tests, or {@code null} if testing was not
353 * requested (e.g. "build" command rather than "test" command).
354 */
355 @Nullable
356 public Collection<ConfiguredTarget> getTargetsToTest() {
357 return targetsToTest;
358 }
359
360 public ImmutableSet<Artifact> getAdditionalArtifactsToBuild() {
361 return artifactsToBuild;
362 }
363
364 public ImmutableSet<ConfiguredTarget> getExclusiveTests() {
365 return exclusiveTests;
366 }
367
368 public ImmutableSet<ConfiguredTarget> getParallelTests() {
369 return parallelTests;
370 }
371
372 /**
373 * Returns an error description (if any).
374 */
375 @Nullable public String getError() {
376 return error;
377 }
378
Ulf Adams988bb212015-08-25 12:51:48 +0000379 public boolean hasError() {
380 return error != null;
381 }
382
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100383 /**
384 * Returns the action graph.
385 */
386 public ActionGraph getActionGraph() {
387 return actionGraph;
388 }
389
390 public TopLevelArtifactContext getTopLevelContext() {
391 return topLevelContext;
392 }
393 }
394
395
396 /**
397 * Returns the collection of configured targets corresponding to any of the provided targets.
398 */
399 @VisibleForTesting
400 static Iterable<? extends ConfiguredTarget> filterTestsByTargets(
401 Collection<? extends ConfiguredTarget> targets,
402 final Set<? extends Target> allowedTargets) {
Dmitry Lomove2033b12015-08-19 16:57:49 +0000403 return Iterables.filter(
404 targets,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100405 new Predicate<ConfiguredTarget>() {
406 @Override
Dmitry Lomove2033b12015-08-19 16:57:49 +0000407 public boolean apply(ConfiguredTarget rule) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100408 return allowedTargets.contains(rule.getTarget());
409 }
410 });
411 }
412
Ulf Adams59dbf682015-09-17 11:36:43 +0000413 private void prepareToBuild(BuildConfigurationCollection configurations,
414 PackageRootResolver resolver) throws ViewCreationFailedException {
Janak Ramakrishnan317bf222015-03-31 14:35:16 +0000415 for (BuildConfiguration config : configurations.getAllConfigurations()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100416 config.prepareToBuild(directories.getExecRoot(), getArtifactFactory(), resolver);
417 }
418 }
419
420 @ThreadCompatible
Dmitry Lomove2033b12015-08-19 16:57:49 +0000421 public AnalysisResult update(
422 LoadingResult loadingResult,
423 BuildConfigurationCollection configurations,
424 List<String> aspects,
425 Options viewOptions,
426 TopLevelArtifactContext topLevelOptions,
427 EventHandler eventHandler,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000428 EventBus eventBus,
429 boolean loadingEnabled)
Dmitry Lomove2033b12015-08-19 16:57:49 +0000430 throws ViewCreationFailedException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100431 LOG.info("Starting analysis");
432 pollInterruptedStatus();
433
434 skyframeBuildView.resetEvaluatedConfiguredTargetKeysSet();
435
436 Collection<Target> targets = loadingResult.getTargets();
437 eventBus.post(new AnalysisPhaseStartedEvent(targets));
438
Ulf Adams003fe962015-09-26 09:51:39 +0000439 skyframeBuildView.setConfigurations(configurations);
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000440
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100441 // Determine the configurations.
Ulf Adams59dbf682015-09-17 11:36:43 +0000442 List<TargetAndConfiguration> nodes = nodesForTargets(configurations, targets);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100443
444 List<ConfiguredTargetKey> targetSpecs =
445 Lists.transform(nodes, new Function<TargetAndConfiguration, ConfiguredTargetKey>() {
446 @Override
447 public ConfiguredTargetKey apply(TargetAndConfiguration node) {
448 return new ConfiguredTargetKey(node.getLabel(), node.getConfiguration());
449 }
450 });
451
Dmitry Lomovc15ba2e2015-10-30 15:50:01 +0000452 List<AspectValueKey> aspectKeys = new ArrayList<>();
Dmitry Lomove2033b12015-08-19 16:57:49 +0000453 for (String aspect : aspects) {
Dmitry Lomov0b832ce2015-10-20 10:03:14 +0000454
455 // Syntax: label%aspect
456 int delimiterPosition = aspect.indexOf('%');
457 if (delimiterPosition >= 0) {
John Fielda97e17f2015-11-13 02:19:52 +0000458 // TODO(jfield): For consistency with Skylark loads, the aspect should be specified
459 // as an absolute path. Also, we probably need to do at least basic validation of
460 // path well-formedness here.
461 PathFragment bzlFile = new PathFragment("/" + aspect.substring(0, delimiterPosition));
Dmitry Lomov0b832ce2015-10-20 10:03:14 +0000462
463 String skylarkFunctionName = aspect.substring(delimiterPosition + 1);
Dmitry Lomove2033b12015-08-19 16:57:49 +0000464 for (ConfiguredTargetKey targetSpec : targetSpecs) {
465 aspectKeys.add(
Dmitry Lomov0b832ce2015-10-20 10:03:14 +0000466 AspectValue.createSkylarkAspectKey(
467 targetSpec.getLabel(),
468 targetSpec.getConfiguration(),
469 bzlFile,
470 skylarkFunctionName));
Dmitry Lomove2033b12015-08-19 16:57:49 +0000471 }
472 } else {
Dmitry Lomov0b832ce2015-10-20 10:03:14 +0000473 @SuppressWarnings("unchecked")
Dmitry Lomovc15ba2e2015-10-30 15:50:01 +0000474 final Class<? extends ConfiguredNativeAspectFactory> aspectFactoryClass =
475 (Class<? extends ConfiguredNativeAspectFactory>)
Dmitry Lomov0b832ce2015-10-20 10:03:14 +0000476 ruleClassProvider.getAspectFactoryMap().get(aspect);
477 if (aspectFactoryClass != null) {
478 for (ConfiguredTargetKey targetSpec : targetSpecs) {
479 aspectKeys.add(
480 AspectValue.createAspectKey(
Dmitry Lomov8ff06452015-10-21 19:16:30 +0000481 targetSpec.getLabel(),
482 targetSpec.getConfiguration(),
483 new NativeAspectClass(aspectFactoryClass)));
Dmitry Lomov0b832ce2015-10-20 10:03:14 +0000484 }
485 } else {
486 throw new ViewCreationFailedException("Aspect '" + aspect + "' is unknown");
487 }
Dmitry Lomove2033b12015-08-19 16:57:49 +0000488 }
489 }
490
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000491 // Configuration of some BuildConfiguration.Fragments may require information about
492 // artifactRoots, so we need to set them before calling prepareToBuild. In that case loading
493 // phase has to be enabled.
494 if (loadingEnabled) {
Ulf Adams59dbf682015-09-17 11:36:43 +0000495 setArtifactRoots(loadingResult.getPackageRoots(), configurations);
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000496 }
Ulf Adams5b9009b2015-09-24 09:52:53 +0000497 prepareToBuild(configurations, new SkyframePackageRootResolver(skyframeExecutor, eventHandler));
Ulf Adams3ab82f72015-09-04 12:10:53 +0000498 skyframeExecutor.injectWorkspaceStatusData();
Dmitry Lomove2033b12015-08-19 16:57:49 +0000499 SkyframeAnalysisResult skyframeAnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100500 try {
Dmitry Lomove2033b12015-08-19 16:57:49 +0000501 skyframeAnalysisResult =
502 skyframeBuildView.configureTargets(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000503 eventHandler, targetSpecs, aspectKeys, eventBus, viewOptions.keepGoing);
Ulf Adams59dbf682015-09-17 11:36:43 +0000504 setArtifactRoots(skyframeAnalysisResult.getPackageRoots(), configurations);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100505 } finally {
506 skyframeBuildView.clearInvalidatedConfiguredTargets();
507 }
508
509 int numTargetsToAnalyze = nodes.size();
Dmitry Lomove2033b12015-08-19 16:57:49 +0000510 int numSuccessful = skyframeAnalysisResult.getConfiguredTargets().size();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100511 boolean analysisSuccessful = (numSuccessful == numTargetsToAnalyze);
512 if (0 < numSuccessful && numSuccessful < numTargetsToAnalyze) {
513 String msg = String.format("Analysis succeeded for only %d of %d top-level targets",
514 numSuccessful, numTargetsToAnalyze);
515 eventHandler.handle(Event.info(msg));
516 LOG.info(msg);
517 }
518
Dmitry Lomove2033b12015-08-19 16:57:49 +0000519 AnalysisResult result =
520 createResult(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000521 eventHandler,
Dmitry Lomove2033b12015-08-19 16:57:49 +0000522 loadingResult,
523 topLevelOptions,
524 viewOptions,
525 skyframeAnalysisResult.getConfiguredTargets(),
526 skyframeAnalysisResult.getAspects(),
527 skyframeAnalysisResult.getWalkableGraph(),
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000528 skyframeAnalysisResult.getPackageRoots(),
Dmitry Lomove2033b12015-08-19 16:57:49 +0000529 analysisSuccessful);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100530 LOG.info("Finished analysis");
531 return result;
532 }
533
Dmitry Lomove2033b12015-08-19 16:57:49 +0000534 private AnalysisResult createResult(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000535 EventHandler eventHandler,
Dmitry Lomove2033b12015-08-19 16:57:49 +0000536 LoadingResult loadingResult,
537 TopLevelArtifactContext topLevelOptions,
538 BuildView.Options viewOptions,
539 Collection<ConfiguredTarget> configuredTargets,
540 Collection<AspectValue> aspects,
541 final WalkableGraph graph,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000542 ImmutableMap<PackageIdentifier, Path> packageRoots,
Dmitry Lomove2033b12015-08-19 16:57:49 +0000543 boolean analysisSuccessful)
544 throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100545 Collection<Target> testsToRun = loadingResult.getTestsToRun();
546 Collection<ConfiguredTarget> allTargetsToTest = null;
547 if (testsToRun != null) {
548 // Determine the subset of configured targets that are meant to be run as tests.
Dmitry Lomov8b1a0942015-11-19 15:14:15 +0000549 // Do not remove <ConfiguredTarget>: workaround for Java 7 type inference.
550 allTargetsToTest =
551 Lists.<ConfiguredTarget>newArrayList(
552 filterTestsByTargets(configuredTargets, Sets.newHashSet(testsToRun)));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100553 }
554
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100555 Set<Artifact> artifactsToBuild = new HashSet<>();
556 Set<ConfiguredTarget> parallelTests = new HashSet<>();
557 Set<ConfiguredTarget> exclusiveTests = new HashSet<>();
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000558
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100559 // build-info and build-changelist.
Ulf Adams5b9009b2015-09-24 09:52:53 +0000560 Collection<Artifact> buildInfoArtifacts =
561 skyframeExecutor.getWorkspaceStatusArtifacts(eventHandler);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100562 Preconditions.checkState(buildInfoArtifacts.size() == 2, buildInfoArtifacts);
563 artifactsToBuild.addAll(buildInfoArtifacts);
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000564
565 // Extra actions
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100566 addExtraActionsIfRequested(viewOptions, artifactsToBuild, configuredTargets);
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000567
568 // Coverage
569 NestedSet<Artifact> baselineCoverageArtifacts = getBaselineCoverageArtifacts(configuredTargets);
570 Iterables.addAll(artifactsToBuild, baselineCoverageArtifacts);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100571 if (coverageReportActionFactory != null) {
Googlercdc90e92015-02-11 00:18:07 +0000572 CoverageReportActionsWrapper actionsWrapper;
573 actionsWrapper = coverageReportActionFactory.createCoverageReportActionsWrapper(
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100574 allTargetsToTest,
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000575 baselineCoverageArtifacts,
Ulf Adams89eefd72015-09-23 08:00:43 +0000576 getArtifactFactory(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100577 CoverageReportValue.ARTIFACT_OWNER);
Googlercdc90e92015-02-11 00:18:07 +0000578 if (actionsWrapper != null) {
579 ImmutableList <Action> actions = actionsWrapper.getActions();
580 skyframeExecutor.injectCoverageReportData(actions);
581 artifactsToBuild.addAll(actionsWrapper.getCoverageOutputs());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100582 }
583 }
584
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000585 // Tests. This must come last, so that the exclusive tests are scheduled after everything else.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100586 scheduleTestsIfRequested(parallelTests, exclusiveTests, topLevelOptions, allTargetsToTest);
587
588 String error = !loadingResult.hasLoadingError()
589 ? (analysisSuccessful
590 ? null
591 : "execution phase succeeded, but not all targets were analyzed")
592 : "execution phase succeeded, but there were loading phase errors";
Eric Fellheimer9c1e12f2015-08-06 20:23:55 +0000593
594 final ActionGraph actionGraph = new ActionGraph() {
595 @Nullable
596 @Override
597 public Action getGeneratingAction(Artifact artifact) {
598 ArtifactOwner artifactOwner = artifact.getArtifactOwner();
599 if (artifactOwner instanceof ActionLookupValue.ActionLookupKey) {
600 SkyKey key = ActionLookupValue.key((ActionLookupValue.ActionLookupKey) artifactOwner);
601 ActionLookupValue val = (ActionLookupValue) graph.getValue(key);
602 return val == null ? null : val.getGeneratingAction(artifact);
603 }
604 return null;
605 }
606 };
Dmitry Lomove2033b12015-08-19 16:57:49 +0000607 return new AnalysisResult(
608 configuredTargets,
609 aspects,
610 allTargetsToTest,
611 error,
612 actionGraph,
613 artifactsToBuild,
614 parallelTests,
615 exclusiveTests,
Marian Lobur86bd4fd2015-09-16 10:01:38 +0000616 topLevelOptions,
617 packageRoots);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100618 }
619
Lukacs Berki6916be22015-02-19 13:36:06 +0000620 private static NestedSet<Artifact> getBaselineCoverageArtifacts(
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100621 Collection<ConfiguredTarget> configuredTargets) {
Lukacs Berki6916be22015-02-19 13:36:06 +0000622 NestedSetBuilder<Artifact> baselineCoverageArtifacts = NestedSetBuilder.stableOrder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100623 for (ConfiguredTarget target : configuredTargets) {
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000624 InstrumentedFilesProvider provider = target.getProvider(InstrumentedFilesProvider.class);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100625 if (provider != null) {
Ulf Adamsfc154ae2015-08-31 12:32:14 +0000626 baselineCoverageArtifacts.addTransitive(provider.getBaselineCoverageArtifacts());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100627 }
628 }
Lukacs Berki6916be22015-02-19 13:36:06 +0000629 return baselineCoverageArtifacts.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100630 }
631
632 private void addExtraActionsIfRequested(BuildView.Options viewOptions,
633 Set<Artifact> artifactsToBuild, Iterable<ConfiguredTarget> topLevelTargets) {
634 NestedSetBuilder<ExtraArtifactSet> builder = NestedSetBuilder.stableOrder();
635 for (ConfiguredTarget topLevel : topLevelTargets) {
636 ExtraActionArtifactsProvider provider = topLevel.getProvider(
637 ExtraActionArtifactsProvider.class);
638 if (provider != null) {
639 if (viewOptions.extraActionTopLevelOnly) {
640 builder.add(ExtraArtifactSet.of(topLevel.getLabel(), provider.getExtraActionArtifacts()));
641 } else {
642 builder.addTransitive(provider.getTransitiveExtraActionArtifacts());
643 }
644 }
645 }
646
647 RegexFilter filter = viewOptions.extraActionFilter;
648 for (ExtraArtifactSet set : builder.build()) {
649 boolean filterMatches = filter == null || filter.isIncluded(set.getLabel().toString());
650 if (filterMatches) {
Ulf Adams07dba942015-03-05 14:47:37 +0000651 artifactsToBuild.addAll(set.getArtifacts());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100652 }
653 }
654 }
655
656 private static void scheduleTestsIfRequested(Collection<ConfiguredTarget> targetsToTest,
657 Collection<ConfiguredTarget> targetsToTestExclusive, TopLevelArtifactContext topLevelOptions,
658 Collection<ConfiguredTarget> allTestTargets) {
Lukacs Berki3f4d4e92015-02-24 10:28:26 +0000659 Set<String> outputGroups = topLevelOptions.outputGroups();
Lukacs Berki1e79b962015-03-03 10:59:21 +0000660 if (!outputGroups.contains(OutputGroupProvider.FILES_TO_COMPILE)
661 && !outputGroups.contains(OutputGroupProvider.COMPILATION_PREREQUISITES)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100662 && allTestTargets != null) {
663 scheduleTests(targetsToTest, targetsToTestExclusive, allTestTargets,
664 topLevelOptions.runTestsExclusively());
665 }
666 }
667
668
669 /**
670 * Returns set of artifacts representing test results, writing into targetsToTest and
671 * targetsToTestExclusive.
672 */
673 private static void scheduleTests(Collection<ConfiguredTarget> targetsToTest,
674 Collection<ConfiguredTarget> targetsToTestExclusive,
675 Collection<ConfiguredTarget> allTestTargets,
676 boolean isExclusive) {
677 for (ConfiguredTarget target : allTestTargets) {
678 if (target.getTarget() instanceof Rule) {
679 boolean exclusive =
680 isExclusive || TargetUtils.isExclusiveTestRule((Rule) target.getTarget());
681 Collection<ConfiguredTarget> testCollection = exclusive
682 ? targetsToTestExclusive
683 : targetsToTest;
684 testCollection.add(target);
685 }
686 }
687 }
688
689 @VisibleForTesting
Ulf Adams59dbf682015-09-17 11:36:43 +0000690 List<TargetAndConfiguration> nodesForTargets(BuildConfigurationCollection configurations,
691 Collection<Target> targets) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100692 // We use a hash set here to remove duplicate nodes; this can happen for input files and package
693 // groups.
694 LinkedHashSet<TargetAndConfiguration> nodes = new LinkedHashSet<>(targets.size());
695 for (BuildConfiguration config : configurations.getTargetConfigurations()) {
696 for (Target target : targets) {
697 nodes.add(new TargetAndConfiguration(target,
698 BuildConfigurationCollection.configureTopLevelTarget(config, target)));
699 }
700 }
701 return ImmutableList.copyOf(nodes);
702 }
703
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100704 /**
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000705 * Sets the possible artifact roots in the artifact factory. This allows the factory to resolve
706 * paths with unknown roots to artifacts.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100707 */
708 @VisibleForTesting // for BuildViewTestCase
Ulf Adams59dbf682015-09-17 11:36:43 +0000709 public void setArtifactRoots(ImmutableMap<PackageIdentifier, Path> packageRoots,
710 BuildConfigurationCollection configurations) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100711 Map<Path, Root> rootMap = new HashMap<>();
712 Map<PackageIdentifier, Root> realPackageRoots = new HashMap<>();
713 for (Map.Entry<PackageIdentifier, Path> entry : packageRoots.entrySet()) {
714 Root root = rootMap.get(entry.getValue());
715 if (root == null) {
716 root = Root.asSourceRoot(entry.getValue());
717 rootMap.put(entry.getValue(), root);
718 }
719 realPackageRoots.put(entry.getKey(), root);
720 }
721 // Source Artifact roots:
Ulf Adams89eefd72015-09-23 08:00:43 +0000722 getArtifactFactory().setPackageRoots(realPackageRoots);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100723
724 // Derived Artifact roots:
725 ImmutableList.Builder<Root> roots = ImmutableList.builder();
726
727 // build-info.txt and friends; this root is not configuration specific.
728 roots.add(directories.getBuildDataDirectory());
729
730 // The roots for each configuration - duplicates are automatically removed in the call below.
731 for (BuildConfiguration cfg : configurations.getAllConfigurations()) {
732 roots.addAll(cfg.getRoots());
733 }
734
Ulf Adams89eefd72015-09-23 08:00:43 +0000735 getArtifactFactory().setDerivedArtifactRoots(roots.build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100736 }
737
738 /**
Ulf Adams9c505cb2015-09-28 13:38:14 +0000739 * Tests and clears the current thread's pending "interrupted" status, and
740 * throws InterruptedException iff it was set.
741 */
742 protected final void pollInterruptedStatus() throws InterruptedException {
743 if (Thread.interrupted()) {
744 throw new InterruptedException();
745 }
746 }
747
748 /**
749 * Drops the analysis cache. If building with Skyframe, targets in {@code topLevelTargets} may
750 * remain in the cache for use during the execution phase.
751 *
752 * @see BuildView.Options#discardAnalysisCache
753 */
754 public void clearAnalysisCache(Collection<ConfiguredTarget> topLevelTargets) {
755 skyframeBuildView.clearAnalysisCache(topLevelTargets);
756 }
757
758 // For ide_build_info
759 public ConfiguredTarget getConfiguredTargetForIdeInfo(
760 EventHandler eventHandler, Label label, BuildConfiguration configuration) {
761 return Iterables.getFirst(
762 skyframeExecutor.getConfiguredTargets(
763 eventHandler,
764 configuration,
765 ImmutableList.of(new Dependency(label, configuration)),
766 true),
767 null);
768 }
769
770 public ConfiguredTarget getConfiguredTargetForIdeInfo(
771 EventHandler eventHandler, Target target, BuildConfiguration config) {
772 return getConfiguredTargetForIdeInfo(eventHandler, target.getLabel(), config);
773 }
774
775 public Iterable<ConfiguredTarget> getDirectPrerequisitesForIdeInfo(
776 EventHandler eventHandler, ConfiguredTarget ct, BuildConfigurationCollection configurations)
777 throws InterruptedException {
778 return getDirectPrerequisitesForTesting(eventHandler, ct, configurations);
779 }
780
781 public Iterable<Dependency> getDirectPrerequisiteDependenciesForIdeInfo(
782 EventHandler eventHandler, ConfiguredTarget ct,
783 @Nullable final LoadingCache<Label, Target> targetCache,
784 BuildConfigurationCollection configurations) throws InterruptedException {
785 return getDirectPrerequisiteDependenciesForTesting(
786 eventHandler, ct, targetCache, configurations);
787 }
788
789 // For testing
790 @VisibleForTesting
791 public Iterable<ConfiguredTarget> getDirectPrerequisitesForTesting(
792 EventHandler eventHandler, ConfiguredTarget ct, BuildConfigurationCollection configurations)
793 throws InterruptedException {
794 return skyframeExecutor.getConfiguredTargets(
795 eventHandler, ct.getConfiguration(),
796 getDirectPrerequisiteDependenciesForTesting(eventHandler, ct, null, configurations), false);
797 }
798
799 @VisibleForTesting
800 public Iterable<Dependency> getDirectPrerequisiteDependenciesForTesting(
Ulf Adams24e813a2015-09-28 14:34:08 +0000801 final EventHandler eventHandler, ConfiguredTarget ct,
Ulf Adams9c505cb2015-09-28 13:38:14 +0000802 @Nullable final LoadingCache<Label, Target> targetCache,
803 BuildConfigurationCollection configurations) throws InterruptedException {
804 if (!(ct.getTarget() instanceof Rule)) {
805 return ImmutableList.of();
806 }
807
808 class SilentDependencyResolver extends DependencyResolver {
809 @Override
810 protected void invalidVisibilityReferenceHook(TargetAndConfiguration node, Label label) {
811 // The error must have been reported already during analysis.
812 }
813
814 @Override
815 protected void invalidPackageGroupReferenceHook(TargetAndConfiguration node, Label label) {
816 // The error must have been reported already during analysis.
817 }
818
819 @Override
820 protected Target getTarget(Label label) throws NoSuchThingException {
821 if (targetCache == null) {
Ulf Adams24e813a2015-09-28 14:34:08 +0000822 return LoadedPackageProvider.Bridge.getLoadedTarget(
823 skyframeExecutor.getPackageManager(), eventHandler, label);
Ulf Adams9c505cb2015-09-28 13:38:14 +0000824 }
825
826 try {
827 return targetCache.get(label);
828 } catch (ExecutionException e) {
829 // All lookups should succeed because we should not be looking up any targets in error.
830 throw new IllegalStateException(e);
831 }
832 }
833 }
834
835 DependencyResolver dependencyResolver = new SilentDependencyResolver();
836 TargetAndConfiguration ctgNode =
837 new TargetAndConfiguration(ct.getTarget(), ct.getConfiguration());
838 return dependencyResolver.dependentNodes(ctgNode, configurations.getHostConfiguration(),
839 getConfigurableAttributeKeysForTesting(eventHandler, ctgNode));
840 }
841
842 /**
843 * Returns ConfigMatchingProvider instances corresponding to the configurable attribute keys
844 * present in this rule's attributes.
845 */
846 private Set<ConfigMatchingProvider> getConfigurableAttributeKeysForTesting(
847 EventHandler eventHandler, TargetAndConfiguration ctg) {
848 if (!(ctg.getTarget() instanceof Rule)) {
849 return ImmutableSet.of();
850 }
851 Rule rule = (Rule) ctg.getTarget();
852 ImmutableSet.Builder<ConfigMatchingProvider> keys = ImmutableSet.builder();
853 RawAttributeMapper mapper = RawAttributeMapper.of(rule);
854 for (Attribute attribute : rule.getAttributes()) {
855 for (Label label : mapper.getConfigurabilityKeys(attribute.getName(), attribute.getType())) {
856 if (BuildType.Selector.isReservedLabel(label)) {
857 continue;
858 }
859 ConfiguredTarget ct = getConfiguredTargetForTesting(
860 eventHandler, label, ctg.getConfiguration());
861 keys.add(Preconditions.checkNotNull(ct.getProvider(ConfigMatchingProvider.class)));
862 }
863 }
864 return keys.build();
865 }
866
867 private ListMultimap<Attribute, ConfiguredTarget> getPrerequisiteMapForTesting(
Ulf Adams24e813a2015-09-28 14:34:08 +0000868 final EventHandler eventHandler, ConfiguredTarget target,
Ulf Adams9c505cb2015-09-28 13:38:14 +0000869 BuildConfigurationCollection configurations) throws InterruptedException {
870 DependencyResolver resolver = new DependencyResolver() {
871 @Override
872 protected void invalidVisibilityReferenceHook(TargetAndConfiguration node, Label label) {
873 throw new RuntimeException("bad visibility on " + label + " during testing unexpected");
874 }
875
876 @Override
877 protected void invalidPackageGroupReferenceHook(TargetAndConfiguration node, Label label) {
878 throw new RuntimeException("bad package group on " + label + " during testing unexpected");
879 }
880
881 @Override
882 protected Target getTarget(Label label) throws NoSuchThingException {
Ulf Adams24e813a2015-09-28 14:34:08 +0000883 return LoadedPackageProvider.Bridge.getLoadedTarget(
884 skyframeExecutor.getPackageManager(), eventHandler, label);
Ulf Adams9c505cb2015-09-28 13:38:14 +0000885 }
886 };
887 TargetAndConfiguration ctNode = new TargetAndConfiguration(target);
888 ListMultimap<Attribute, Dependency> depNodeNames;
889 try {
Dmitry Lomov6231d082015-11-02 17:17:20 +0000890 depNodeNames =
891 resolver.dependentNodeMap(
892 ctNode,
893 configurations.getHostConfiguration(),
894 /*aspect=*/ null,
895 getConfigurableAttributeKeysForTesting(eventHandler, ctNode));
Ulf Adams9c505cb2015-09-28 13:38:14 +0000896 } catch (EvalException e) {
897 throw new IllegalStateException(e);
898 }
899
900 ImmutableMap<Dependency, ConfiguredTarget> cts = skyframeExecutor.getConfiguredTargetMap(
901 eventHandler,
902 ctNode.getConfiguration(), ImmutableSet.copyOf(depNodeNames.values()), false);
903
904 ImmutableListMultimap.Builder<Attribute, ConfiguredTarget> builder =
905 ImmutableListMultimap.builder();
906 for (Map.Entry<Attribute, Dependency> entry : depNodeNames.entries()) {
907 builder.put(entry.getKey(), cts.get(entry.getValue()));
908 }
909 return builder.build();
910 }
911
912 /**
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000913 * Returns a configured target for the specified target and configuration. Returns {@code null}
914 * if something goes wrong.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100915 */
916 @VisibleForTesting
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000917 public ConfiguredTarget getConfiguredTargetForTesting(
918 EventHandler eventHandler, Label label, BuildConfiguration config) {
919 return skyframeExecutor.getConfiguredTargetForTesting(eventHandler, label, config);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100920 }
921
922 /**
923 * Returns a RuleContext which is the same as the original RuleContext of the target parameter.
924 */
925 @VisibleForTesting
Florian Weikert4b67d4f2015-09-14 13:35:34 +0000926 public RuleContext getRuleContextForTesting(
Ulf Adamse7704672015-09-21 14:37:41 +0000927 ConfiguredTarget target, StoredEventHandler eventHandler,
Ulf Adams5a96d532015-09-26 09:00:57 +0000928 BuildConfigurationCollection configurations, BinTools binTools) throws InterruptedException {
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000929 BuildConfiguration targetConfig = target.getConfiguration();
930 CachingAnalysisEnvironment env =
Ulf Adams89eefd72015-09-23 08:00:43 +0000931 new CachingAnalysisEnvironment(getArtifactFactory(),
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000932 new ConfiguredTargetKey(target.getLabel(), targetConfig),
933 /*isSystemEnv=*/false, targetConfig.extendedSanityChecks(), eventHandler,
934 /*skyframeEnv=*/null, targetConfig.isActionsEnabled(), binTools);
935 return getRuleContextForTesting(eventHandler, target, env, configurations);
Ulf Adams79f05212015-02-27 16:40:00 +0000936 }
937
938 /**
939 * Creates and returns a rule context that is equivalent to the one that was used to create the
940 * given configured target.
941 */
942 @VisibleForTesting
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000943 public RuleContext getRuleContextForTesting(EventHandler eventHandler, ConfiguredTarget target,
944 AnalysisEnvironment env, BuildConfigurationCollection configurations)
945 throws InterruptedException {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000946 BuildConfiguration targetConfig = target.getConfiguration();
Ulf Adams79f05212015-02-27 16:40:00 +0000947 return new RuleContext.Builder(
Greg Estren00049432015-08-25 16:43:47 +0000948 env, (Rule) target.getTarget(), targetConfig, configurations.getHostConfiguration(),
Ulf Adams79f05212015-02-27 16:40:00 +0000949 ruleClassProvider.getPrerequisiteValidator())
950 .setVisibility(NestedSetBuilder.<PackageSpecification>create(
951 Order.STABLE_ORDER, PackageSpecification.EVERYTHING))
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000952 .setPrerequisites(getPrerequisiteMapForTesting(eventHandler, target, configurations))
Ulf Adams79f05212015-02-27 16:40:00 +0000953 .setConfigConditions(ImmutableSet.<ConfigMatchingProvider>of())
Greg Estrenc5a352f2015-11-13 17:25:36 +0000954 .setUniversalFragment(ruleClassProvider.getUniversalFragment())
Ulf Adams79f05212015-02-27 16:40:00 +0000955 .build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100956 }
957
958 /**
Googler9263b462015-05-13 19:22:24 +0000959 * For a configured target dependentTarget, returns the desired configured target
960 * that is depended upon. Useful for obtaining the a target with aspects
961 * required by the dependent.
962 */
963 @VisibleForTesting
964 public ConfiguredTarget getPrerequisiteConfiguredTargetForTesting(
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000965 EventHandler eventHandler, ConfiguredTarget dependentTarget, Label desiredTarget,
Ulf Adamse7704672015-09-21 14:37:41 +0000966 BuildConfigurationCollection configurations)
Florian Weikert4b67d4f2015-09-14 13:35:34 +0000967 throws InterruptedException {
Googler9263b462015-05-13 19:22:24 +0000968 Collection<ConfiguredTarget> configuredTargets =
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000969 getPrerequisiteMapForTesting(eventHandler, dependentTarget, configurations).values();
Googler9263b462015-05-13 19:22:24 +0000970 for (ConfiguredTarget ct : configuredTargets) {
Ulf Adamsa385d3e2015-09-28 13:21:45 +0000971 if (ct.getLabel().equals(desiredTarget)) {
Googler9263b462015-05-13 19:22:24 +0000972 return ct;
973 }
974 }
975 return null;
976 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100977}