blob: 1fc503c9861b8313ca7002485332d0de2e9d6b09 [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.
14package com.google.devtools.build.lib.buildtool;
15
mstaibd9b141d2017-09-14 20:47:31 +020016import static com.google.common.collect.ImmutableSet.toImmutableSet;
Eric Fellheimere9b41c62016-06-14 15:39:51 +000017
steinman13a628a2019-01-09 08:39:32 -080018import com.google.common.annotations.VisibleForTesting;
lebacac22462021-09-22 01:45:34 -070019import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import com.google.common.base.Predicate;
21import com.google.common.base.Stopwatch;
mschaller40379082019-02-01 14:14:47 -080022import com.google.common.base.Throwables;
Philipp Wollermann45bf15b2015-06-18 13:06:16 +000023import com.google.common.collect.ImmutableList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010024import com.google.common.collect.ImmutableMap;
25import com.google.common.collect.ImmutableSet;
ichern121933e2020-01-27 02:08:19 -080026import com.google.common.collect.ImmutableSortedSet;
lebacac22462021-09-22 01:45:34 -070027import com.google.common.collect.Iterables;
janakr0dfb4662020-04-20 08:37:53 -070028import com.google.common.flogger.GoogleLogger;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.devtools.build.lib.actions.Action;
30import com.google.devtools.build.lib.actions.ActionCacheChecker;
lebaf7b8b722021-11-16 06:09:08 -080031import com.google.devtools.build.lib.actions.ActionExecutionStatusReporter;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032import com.google.devtools.build.lib.actions.ActionGraph;
ulfjack5b99e502017-07-20 22:22:36 +020033import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
Ulf Adams3d67e002016-03-29 16:23:01 +000034import com.google.devtools.build.lib.actions.ArtifactFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035import com.google.devtools.build.lib.actions.BuildFailedException;
jcater85d666f2020-04-15 07:22:21 -070036import com.google.devtools.build.lib.actions.DynamicStrategyRegistry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037import com.google.devtools.build.lib.actions.Executor;
janakrae323982017-09-29 21:11:53 +020038import com.google.devtools.build.lib.actions.PackageRoots;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039import com.google.devtools.build.lib.actions.ResourceManager;
Mark Schallerdffb6ee2015-02-25 20:01:01 +000040import com.google.devtools.build.lib.actions.ResourceSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010041import com.google.devtools.build.lib.actions.TestExecException;
42import com.google.devtools.build.lib.actions.cache.ActionCache;
jmmvccb43ee2017-08-30 22:07:10 +020043import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics;
ulfjackc23bdac2018-06-13 03:06:16 -070044import com.google.devtools.build.lib.analysis.AnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.analysis.ConfiguredTarget;
Googlerbfd4e242016-07-15 22:23:37 +000046import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
jcaterc864f872020-01-28 09:01:45 -080048import com.google.devtools.build.lib.analysis.WorkspaceStatusAction;
Lukacs Berki7b2f2e82016-11-23 14:16:43 +000049import com.google.devtools.build.lib.analysis.actions.SymlinkTreeActionContext;
jhorvitz33f76482021-10-28 10:13:26 -070050import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
brandjon7b5043f2019-11-25 12:30:22 -080051import com.google.devtools.build.lib.analysis.config.BuildOptions;
52import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
schmitt4d6aff92020-01-13 10:49:30 -080053import com.google.devtools.build.lib.analysis.test.TestActionContext;
Googler87636392019-12-30 12:57:56 -080054import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.ConvenienceSymlink;
55import com.google.devtools.build.lib.buildtool.BuildRequestOptions.ConvenienceSymlinksMode;
56import com.google.devtools.build.lib.buildtool.buildevent.ConvenienceSymlinksIdentifiedEvent;
arostovtsev20b056a2019-08-30 15:00:31 -070057import com.google.devtools.build.lib.buildtool.buildevent.ExecRootPreparedEvent;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import com.google.devtools.build.lib.buildtool.buildevent.ExecutionPhaseCompleteEvent;
lebaf7b8b722021-11-16 06:09:08 -080059import com.google.devtools.build.lib.buildtool.buildevent.ExecutionProgressReceiverAvailableEvent;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010060import com.google.devtools.build.lib.buildtool.buildevent.ExecutionStartingEvent;
Kristina Chodorow33aada22016-06-22 14:23:47 +000061import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062import com.google.devtools.build.lib.events.Event;
63import com.google.devtools.build.lib.events.EventHandler;
64import com.google.devtools.build.lib.events.EventKind;
65import com.google.devtools.build.lib.events.Reporter;
Ulf Adamsdba3c832016-12-21 16:50:02 +000066import com.google.devtools.build.lib.exec.BlazeExecutor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010067import com.google.devtools.build.lib.exec.CheckUpToDateFilter;
68import com.google.devtools.build.lib.exec.ExecutionOptions;
Ulf Adamsdba3c832016-12-21 16:50:02 +000069import com.google.devtools.build.lib.exec.ExecutorBuilder;
schmittbe241a12020-01-16 13:30:55 -080070import com.google.devtools.build.lib.exec.ExecutorLifecycleListener;
jcaterbf144b92020-03-27 12:04:28 -070071import com.google.devtools.build.lib.exec.ModuleActionContextRegistry;
jcater85d666f2020-04-15 07:22:21 -070072import com.google.devtools.build.lib.exec.RemoteLocalFallbackRegistry;
jcaterbf144b92020-03-27 12:04:28 -070073import com.google.devtools.build.lib.exec.SpawnStrategyRegistry;
jcaterac4c06c2020-04-14 13:20:32 -070074import com.google.devtools.build.lib.exec.SpawnStrategyResolver;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010075import com.google.devtools.build.lib.exec.SymlinkTreeStrategy;
adonovan240bdea2020-09-03 15:24:12 -070076import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
Nathan Harmatad4803012015-09-08 20:03:22 +000077import com.google.devtools.build.lib.profiler.AutoProfiler;
janakrb182a3f2020-04-04 08:05:48 -070078import com.google.devtools.build.lib.profiler.GoogleAutoProfilerUtils;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.lib.profiler.ProfilePhase;
80import com.google.devtools.build.lib.profiler.Profiler;
81import com.google.devtools.build.lib.profiler.ProfilerTask;
ulfjack4cf2ebd2018-06-11 06:00:36 -070082import com.google.devtools.build.lib.profiler.SilentCloseable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083import com.google.devtools.build.lib.runtime.BlazeModule;
84import com.google.devtools.build.lib.runtime.BlazeRuntime;
Ulf Adams633f5392015-09-15 11:13:08 +000085import com.google.devtools.build.lib.runtime.CommandEnvironment;
Googler2e1104e2020-05-08 06:51:08 -070086import com.google.devtools.build.lib.server.FailureDetails;
mschallerb976a8b2020-05-11 11:00:14 -070087import com.google.devtools.build.lib.server.FailureDetails.Execution;
88import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
Googler2e1104e2020-05-08 06:51:08 -070089import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
lebab52a1902021-09-23 01:35:13 -070090import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010091import com.google.devtools.build.lib.skyframe.Builder;
cpeyser8e9b28f2018-06-04 08:05:13 -070092import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
lebacac22462021-09-22 01:45:34 -070093import com.google.devtools.build.lib.skyframe.PackageRootsNoSymlinkCreation;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010095import com.google.devtools.build.lib.util.AbruptExitException;
Googler2e1104e2020-05-08 06:51:08 -070096import com.google.devtools.build.lib.util.DetailedExitCode;
Eric Fellheimerf3b43af2015-11-13 19:51:20 +000097import com.google.devtools.build.lib.vfs.ModifiedFileSet;
shahane35e8cf2018-06-18 08:14:01 -070098import com.google.devtools.build.lib.vfs.OutputService;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010099import com.google.devtools.build.lib.vfs.Path;
100import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -0800101import com.google.devtools.build.lib.vfs.Root;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100102import java.io.IOException;
103import java.io.OutputStream;
lberki0d8d4cf2017-09-05 16:01:44 +0200104import java.io.OutputStreamWriter;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100105import java.io.PrintWriter;
lberki0d8d4cf2017-09-05 16:01:44 +0200106import java.nio.charset.StandardCharsets;
jhorvitz4d5f3542021-07-19 10:12:29 -0700107import java.time.Duration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100108import java.util.Collection;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100109import java.util.HashSet;
lebacac22462021-09-22 01:45:34 -0700110import java.util.List;
jhorvitzcd477f22021-05-05 10:18:22 -0700111import java.util.Objects;
janakrae323982017-09-29 21:11:53 +0200112import java.util.Optional;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100113import java.util.Set;
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000114import java.util.UUID;
jmmvccb43ee2017-08-30 22:07:10 +0200115import java.util.concurrent.TimeUnit;
brandjon7b5043f2019-11-25 12:30:22 -0800116import javax.annotation.Nullable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100117
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100118/**
119 * This class manages the execution phase. The entry point is {@link #executeBuild}.
120 *
121 * <p>This is only intended for use by {@link BuildTool}.
122 *
mstaibd9b141d2017-09-14 20:47:31 +0200123 * <p>This class contains an ActionCache, and refers to the Blaze Runtime's BuildView and
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100124 * PackageCache.
125 *
126 * @see BuildTool
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000127 * @see com.google.devtools.build.lib.analysis.BuildView
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100128 */
129public class ExecutionTool {
janakr0dfb4662020-04-20 08:37:53 -0700130 private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100131
Ulf Adams633f5392015-09-15 11:13:08 +0000132 private final CommandEnvironment env;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100133 private final BlazeRuntime runtime;
134 private final BuildRequest request;
135 private BlazeExecutor executor;
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000136 private final ActionInputPrefetcher prefetcher;
schmittbe241a12020-01-16 13:30:55 -0800137 private final ImmutableSet<ExecutorLifecycleListener> executorLifecycleListeners;
jcater40b60742020-05-15 07:04:00 -0700138 private final SpawnStrategyRegistry spawnStrategyRegistry;
139 private final ModuleActionContextRegistry actionContextRegistry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100140
janakrca6d7ac2020-08-18 07:42:05 -0700141 ExecutionTool(CommandEnvironment env, BuildRequest request)
142 throws AbruptExitException, InterruptedException {
Ulf Adams633f5392015-09-15 11:13:08 +0000143 this.env = env;
144 this.runtime = env.getRuntime();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100145 this.request = request;
146
felly472320c2018-10-29 14:27:00 -0700147 try {
148 env.getExecRoot().createDirectoryAndParents();
149 } catch (IOException e) {
mschallerb976a8b2020-05-11 11:00:14 -0700150 throw createExitException("Execroot creation failed", Code.EXECROOT_CREATION_FAILURE, e);
ulfjackef5b63d2018-06-15 07:19:11 -0700151 }
Philipp Wollermann590ea392015-08-25 13:57:33 +0000152
jcaterbf144b92020-03-27 12:04:28 -0700153 ExecutorBuilder executorBuilder = new ExecutorBuilder();
154 ModuleActionContextRegistry.Builder actionContextRegistryBuilder =
jcater283f3402020-06-09 10:59:52 -0700155 ModuleActionContextRegistry.builder();
156 SpawnStrategyRegistry.Builder spawnStrategyRegistryBuilder = SpawnStrategyRegistry.builder();
jcater85d666f2020-04-15 07:22:21 -0700157 actionContextRegistryBuilder.register(SpawnStrategyResolver.class, new SpawnStrategyResolver());
jcaterbf144b92020-03-27 12:04:28 -0700158
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000159 for (BlazeModule module : runtime.getBlazeModules()) {
jcaterbf144b92020-03-27 12:04:28 -0700160 try (SilentCloseable ignored = Profiler.instance().profile(module + ".executorInit")) {
161 module.executorInit(env, request, executorBuilder);
162 }
163
164 try (SilentCloseable ignored =
165 Profiler.instance().profile(module + ".registerActionContexts")) {
166 module.registerActionContexts(actionContextRegistryBuilder, env, request);
167 }
168
169 try (SilentCloseable ignored =
170 Profiler.instance().profile(module + ".registerSpawnStrategies")) {
171 module.registerSpawnStrategies(spawnStrategyRegistryBuilder, env);
ulfjackef5b63d2018-06-15 07:19:11 -0700172 }
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000173 }
jcaterbf144b92020-03-27 12:04:28 -0700174 actionContextRegistryBuilder.register(
jcaterc864f872020-01-28 09:01:45 -0800175 SymlinkTreeActionContext.class,
176 new SymlinkTreeStrategy(env.getOutputService(), env.getBlazeWorkspace().getBinTools()));
177 // TODO(philwo) - the ExecutionTool should not add arbitrary dependencies on its own, instead
178 // these dependencies should be added to the ActionContextConsumer of the module that actually
179 // depends on them.
jcaterbf144b92020-03-27 12:04:28 -0700180 actionContextRegistryBuilder
181 .restrictTo(WorkspaceStatusAction.Context.class, "")
182 .restrictTo(SymlinkTreeActionContext.class, "");
schmitt4d6aff92020-01-13 10:49:30 -0800183
jcaterbf144b92020-03-27 12:04:28 -0700184 this.prefetcher = executorBuilder.getActionInputPrefetcher();
185 this.executorLifecycleListeners = executorBuilder.getExecutorLifecycleListeners();
jcaterc864f872020-01-28 09:01:45 -0800186
187 // There are many different SpawnActions, and we want to control the action context they use
188 // independently from each other, for example, to run genrules locally and Java compile action
189 // in prod. Thus, for SpawnActions, we decide the action context to use not only based on the
190 // context class, but also the mnemonic of the action.
191 ExecutionOptions options = request.getOptions(ExecutionOptions.class);
192 // TODO(jmmv): This should live in some testing-related Blaze module, not here.
jcaterbf144b92020-03-27 12:04:28 -0700193 actionContextRegistryBuilder.restrictTo(TestActionContext.class, options.testStrategy);
194
jcater85d666f2020-04-15 07:22:21 -0700195 SpawnStrategyRegistry spawnStrategyRegistry = spawnStrategyRegistryBuilder.build();
196 actionContextRegistryBuilder.register(SpawnStrategyRegistry.class, spawnStrategyRegistry);
197 actionContextRegistryBuilder.register(DynamicStrategyRegistry.class, spawnStrategyRegistry);
198 actionContextRegistryBuilder.register(RemoteLocalFallbackRegistry.class, spawnStrategyRegistry);
199
jhorvitzcd477f22021-05-05 10:18:22 -0700200 this.actionContextRegistry = actionContextRegistryBuilder.build();
jcater40b60742020-05-15 07:04:00 -0700201 this.spawnStrategyRegistry = spawnStrategyRegistry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100202 }
203
Googler7319c8a2020-05-11 08:52:56 -0700204 Executor getExecutor() throws AbruptExitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100205 if (executor == null) {
206 executor = createExecutor();
schmittbe241a12020-01-16 13:30:55 -0800207 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
208 executorLifecycleListener.executorCreated();
209 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100210 }
211 return executor;
212 }
213
buchgr7b515522019-03-29 04:42:17 -0700214 /** Creates an executor for the current set of blaze runtime, execution options, and request. */
mschallerb976a8b2020-05-11 11:00:14 -0700215 private BlazeExecutor createExecutor() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100216 return new BlazeExecutor(
tomluf903eb52017-10-27 12:12:11 -0400217 runtime.getFileSystem(),
Ulf Adams94b72db2016-03-30 11:58:37 +0000218 env.getExecRoot(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100219 getReporter(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100220 runtime.getClock(),
ajurkowskic0409462020-12-22 19:22:11 -0800221 runtime.getBugReporter(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100222 request,
jcater40b60742020-05-15 07:04:00 -0700223 actionContextRegistry,
224 spawnStrategyRegistry);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100225 }
226
Googler7319c8a2020-05-11 08:52:56 -0700227 void init() throws AbruptExitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100228 getExecutor();
229 }
230
231 void shutdown() {
schmittbe241a12020-01-16 13:30:55 -0800232 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
233 executorLifecycleListener.executionPhaseEnding();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100234 }
235 }
236
Googler2af2aa32020-01-30 06:45:55 -0800237 TestActionContext getTestActionContext() {
jcater40b60742020-05-15 07:04:00 -0700238 return actionContextRegistry.getContext(TestActionContext.class);
Googler2af2aa32020-01-30 06:45:55 -0800239 }
240
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100241 /**
lebacac22462021-09-22 01:45:34 -0700242 * Sets up for execution.
243 *
244 * <p>b/199053098: This method concentrates the setup steps for execution, which were previously
245 * scattered over several classes. We need this in order to merge analysis & execution phases.
246 * TODO(b/199053098): Minimize code duplication with the main code path.
247 */
lebaf7b8b722021-11-16 06:09:08 -0800248 public void prepareForExecution(
249 UUID buildId, Set<ConfiguredTargetKey> builtTargets, Set<AspectKey> builtAspects)
lebacac22462021-09-22 01:45:34 -0700250 throws AbruptExitException, BuildFailedException, InterruptedException {
251 init();
252
253 SkyframeExecutor skyframeExecutor = env.getSkyframeExecutor();
254 // TODO(b/199053098): Support symlink forest.
255 List<Root> pkgPathEntries = env.getPackageLocator().getPathEntries();
256 Preconditions.checkState(
257 pkgPathEntries.size() == 1,
258 "--experimental_merged_skyframe_analysis_execution requires a single package path entry."
259 + " Found a list of size: %s",
260 pkgPathEntries.size());
261 Root singleSourceRoot = Iterables.getOnlyElement(pkgPathEntries);
262 PackageRoots noSymlinkPackageRoots = new PackageRootsNoSymlinkCreation(singleSourceRoot);
263 env.getEventBus().post(new ExecRootPreparedEvent(noSymlinkPackageRoots.getPackageRootsMap()));
264 env.getSkyframeBuildView()
265 .getArtifactFactory()
266 .setPackageRoots(noSymlinkPackageRoots.getPackageRootLookup());
267
268 OutputService outputService = env.getOutputService();
269 ModifiedFileSet modifiedOutputFiles = ModifiedFileSet.EVERYTHING_MODIFIED;
270 if (outputService != null) {
271 try (SilentCloseable c = Profiler.instance().profile("outputService.startBuild")) {
272 modifiedOutputFiles =
273 outputService.startBuild(
274 env.getReporter(), buildId, request.getBuildOptions().finalizeActions);
275 }
276 } else {
277 // TODO(bazel-team): this could be just another OutputService
278 try (SilentCloseable c = Profiler.instance().profile("startLocalOutputBuild")) {
279 startLocalOutputBuild();
280 }
281 }
282 if (outputService == null || !outputService.actionFileSystemType().inMemoryFileSystem()) {
283 // Must be created after the output path is created above.
284 createActionLogDirectory();
285 }
286
287 ActionCache actionCache = getActionCache();
288 actionCache.resetStatistics();
289 SkyframeBuilder skyframeBuilder;
290 try (SilentCloseable c = Profiler.instance().profile("createBuilder")) {
291 skyframeBuilder =
292 (SkyframeBuilder)
293 createBuilder(request, actionCache, skyframeExecutor, modifiedOutputFiles);
294 }
295 try (SilentCloseable c = Profiler.instance().profile("configureActionExecutor")) {
296 skyframeExecutor.configureActionExecutor(
297 skyframeBuilder.getFileCache(), skyframeBuilder.getActionInputPrefetcher());
298 }
299 // TODO(b/199053098): Setup progress reporting objects in SkyframeActionExecutor.
300 try (SilentCloseable c =
301 Profiler.instance().profile("prepareSkyframeActionExecutorForExecution")) {
302 skyframeExecutor.prepareSkyframeActionExecutorForExecution(
303 env.getReporter(),
304 executor,
305 request,
306 skyframeBuilder.getActionCacheChecker(),
307 skyframeBuilder.getTopDownActionCache());
308 }
lebaf7b8b722021-11-16 06:09:08 -0800309
310 // Note that executionProgressReceiver accesses builtTargets concurrently (after wrapping in a
311 // synchronized collection), so unsynchronized access to this variable is unsafe while it runs.
312 // TODO(leba): count test actions
313 ExecutionProgressReceiver executionProgressReceiver =
314 new ExecutionProgressReceiver(
315 Preconditions.checkNotNull(builtTargets), Preconditions.checkNotNull(builtAspects), 0);
316 skyframeExecutor
317 .getEventBus()
318 .post(new ExecutionProgressReceiverAvailableEvent(executionProgressReceiver));
319
320 ActionExecutionStatusReporter statusReporter =
321 ActionExecutionStatusReporter.create(env.getReporter(), skyframeExecutor.getEventBus());
322 // TODO(leba): Add watchdog support.
323 skyframeExecutor.setActionExecutionProgressReportingObjects(
324 executionProgressReceiver, executionProgressReceiver, statusReporter);
325 skyframeExecutor.setExecutionProgressReceiver(executionProgressReceiver);
326
lebacac22462021-09-22 01:45:34 -0700327 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
328 try (SilentCloseable c =
329 Profiler.instance().profile(executorLifecycleListener + ".executionPhaseStarting")) {
330 executorLifecycleListener.executionPhaseStarting(null, () -> null);
331 }
332 }
333
334 try (SilentCloseable c = Profiler.instance().profile("configureResourceManager")) {
335 configureResourceManager(env.getLocalResourceManager(), request);
336 }
337 }
338
339 /**
janakrae323982017-09-29 21:11:53 +0200340 * Performs the execution phase (phase 3) of the build, in which the Builder is applied to the
341 * action graph to bring the targets up to date. (This function will return prior to
342 * execution-proper if --nobuild was specified.)
343 *
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000344 * @param buildId UUID of the build id
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100345 * @param analysisResult the analysis phase output
346 * @param buildResult the mutable build result
Lukacs Berki3ea4d442016-01-21 15:15:30 +0000347 * @param packageRoots package roots collected from loading phase and BuildConfigurationCollection
janakrae323982017-09-29 21:11:53 +0200348 * creation. May be empty if {@link
349 * SkyframeExecutor#getForcedSingleSourceRootIfNoExecrootSymlinkCreation} is false.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100350 */
janakrae323982017-09-29 21:11:53 +0200351 void executeBuild(
352 UUID buildId,
353 AnalysisResult analysisResult,
Laurent Le Brunf3cf98f2016-06-17 13:36:24 +0000354 BuildResult buildResult,
janakrae323982017-09-29 21:11:53 +0200355 PackageRoots packageRoots,
Googlerbfd4e242016-07-15 22:23:37 +0000356 TopLevelArtifactContext topLevelArtifactContext)
Nathan Harmataca06fa22015-07-27 19:54:14 +0000357 throws BuildFailedException, InterruptedException, TestExecException, AbruptExitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100358 Stopwatch timer = Stopwatch.createStarted();
ichern121933e2020-01-27 02:08:19 -0800359 prepare(packageRoots, analysisResult.getNonSymlinkedDirectoriesUnderExecRoot());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100360
361 ActionGraph actionGraph = analysisResult.getActionGraph();
362
Ulf Adams706b7f22015-10-20 09:06:45 +0000363 OutputService outputService = env.getOutputService();
Eric Fellheimerf3b43af2015-11-13 19:51:20 +0000364 ModifiedFileSet modifiedOutputFiles = ModifiedFileSet.EVERYTHING_MODIFIED;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100365 if (outputService != null) {
ulfjackef5b63d2018-06-15 07:19:11 -0700366 try (SilentCloseable c = Profiler.instance().profile("outputService.startBuild")) {
367 modifiedOutputFiles =
368 outputService.startBuild(
369 env.getReporter(), buildId, request.getBuildOptions().finalizeActions);
370 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100371 } else {
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000372 // TODO(bazel-team): this could be just another OutputService
ulfjackef5b63d2018-06-15 07:19:11 -0700373 try (SilentCloseable c = Profiler.instance().profile("startLocalOutputBuild")) {
374 startLocalOutputBuild();
375 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100376 }
377
buchgr7b515522019-03-29 04:42:17 -0700378 if (outputService == null || !outputService.actionFileSystemType().inMemoryFileSystem()) {
379 // Must be created after the output path is created above.
380 createActionLogDirectory();
381 }
janakr0049e962017-04-05 21:41:23 +0000382
Googler87636392019-12-30 12:57:56 -0800383 handleConvenienceSymlinks(analysisResult);
Lukacs Berki85c63c42016-01-22 09:25:20 +0000384
jhorvitz4d5f3542021-07-19 10:12:29 -0700385 BuildRequestOptions options = request.getBuildOptions();
386 ActionCache actionCache = null;
387 if (options.useActionCache) {
388 actionCache = getActionCache();
389 actionCache.resetStatistics();
390 }
Ulf Adams80613022015-09-16 09:11:33 +0000391 SkyframeExecutor skyframeExecutor = env.getSkyframeExecutor();
ulfjackef5b63d2018-06-15 07:19:11 -0700392 Builder builder;
393 try (SilentCloseable c = Profiler.instance().profile("createBuilder")) {
buchgr7b515522019-03-29 04:42:17 -0700394 builder = createBuilder(request, actionCache, skyframeExecutor, modifiedOutputFiles);
ulfjackef5b63d2018-06-15 07:19:11 -0700395 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100396
397 //
398 // Execution proper. All statements below are logically nested in
399 // begin/end pairs. No early returns or exceptions please!
400 //
401
402 Collection<ConfiguredTarget> configuredTargets = buildResult.getActualTargets();
ulfjackef5b63d2018-06-15 07:19:11 -0700403 try (SilentCloseable c = Profiler.instance().profile("ExecutionStartingEvent")) {
404 env.getEventBus().post(new ExecutionStartingEvent(configuredTargets));
405 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100406
407 getReporter().handle(Event.progress("Building..."));
408
409 // Conditionally record dependency-checker log:
410 ExplanationHandler explanationHandler =
buchgr7b515522019-03-29 04:42:17 -0700411 installExplanationHandler(
412 request.getBuildOptions().explanationPath, request.getOptionsDescription());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100413
cpeyser8e9b28f2018-06-04 08:05:13 -0700414 Set<ConfiguredTargetKey> builtTargets = new HashSet<>();
tomlu6ed4fd52018-04-03 10:01:10 -0700415 Set<AspectKey> builtAspects = new HashSet<>();
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000416
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000417 if (request.isRunningInEmacs()) {
418 // The syntax of this message is tightly constrained by lisp/progmodes/compile.el in emacs
Klaus Aehligad87c132017-08-14 12:20:39 +0200419 request
420 .getOutErr()
brandjon79712cb2019-12-04 10:01:17 -0800421 .printErrLn(runtime.getProductName() + ": Entering directory `" + getExecRoot() + "/'");
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000422 }
mschaller40379082019-02-01 14:14:47 -0800423
424 Throwable catastrophe = null;
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000425 boolean buildCompleted = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100426 try {
Googler594c32d2019-07-17 17:55:18 -0700427 if (request.getViewOptions().discardAnalysisCache
428 || !skyframeExecutor.tracksStateForIncrementality()) {
429 // Free memory by removing cache entries that aren't going to be needed.
430 try (SilentCloseable c = Profiler.instance().profile("clearAnalysisCache")) {
431 env.getSkyframeBuildView()
janakrf15d08d2020-04-22 12:53:03 -0700432 .clearAnalysisCache(
433 analysisResult.getTargetsToBuild(), analysisResult.getAspectsMap().keySet());
Googler594c32d2019-07-17 17:55:18 -0700434 }
435 }
436
schmittbe241a12020-01-16 13:30:55 -0800437 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
ulfjackef5b63d2018-06-15 07:19:11 -0700438 try (SilentCloseable c =
schmittbe241a12020-01-16 13:30:55 -0800439 Profiler.instance().profile(executorLifecycleListener + ".executionPhaseStarting")) {
440 executorLifecycleListener.executionPhaseStarting(
janakrccb74562018-07-30 10:56:57 -0700441 actionGraph,
Googler184b4542019-07-19 19:34:19 -0700442 // If this supplier is ever consumed by more than one ActionContextProvider, it can be
443 // pulled out of the loop and made a memoizing supplier.
jhorvitzcd477f22021-05-05 10:18:22 -0700444 () -> TopLevelArtifactHelper.findAllTopLevelArtifacts(analysisResult));
ulfjackef5b63d2018-06-15 07:19:11 -0700445 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100446 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100447 skyframeExecutor.drainChangedFiles();
448
ulfjackef5b63d2018-06-15 07:19:11 -0700449 try (SilentCloseable c = Profiler.instance().profile("configureResourceManager")) {
ulfjack985a34ad2019-08-09 01:51:15 -0700450 configureResourceManager(env.getLocalResourceManager(), request);
ulfjackef5b63d2018-06-15 07:19:11 -0700451 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100452
453 Profiler.instance().markPhase(ProfilePhase.EXECUTE);
steinman39c00d22020-03-20 15:23:10 -0700454 boolean shouldTrustRemoteArtifacts =
jhorvitzcd477f22021-05-05 10:18:22 -0700455 env.getOutputService() != null && env.getOutputService().shouldTrustRemoteArtifacts();
Dmitry Lomove2033b12015-08-19 16:57:49 +0000456 builder.buildArtifacts(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000457 env.getReporter(),
jhorvitzcd477f22021-05-05 10:18:22 -0700458 analysisResult.getArtifactsToBuild(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100459 analysisResult.getParallelTests(),
460 analysisResult.getExclusiveTests(),
461 analysisResult.getTargetsToBuild(),
gregce45ae0962017-07-22 00:11:13 +0200462 analysisResult.getTargetsToSkip(),
janakrf15d08d2020-04-22 12:53:03 -0700463 analysisResult.getAspectsMap().keySet(),
Dmitry Lomove2033b12015-08-19 16:57:49 +0000464 executor,
465 builtTargets,
tomlu6ed4fd52018-04-03 10:01:10 -0700466 builtAspects,
tomlu2661be82018-08-30 08:30:01 -0700467 request,
Googlerbfd4e242016-07-15 22:23:37 +0000468 env.getBlazeWorkspace().getLastExecutionTimeRange(),
steinman39c00d22020-03-20 15:23:10 -0700469 topLevelArtifactContext,
470 shouldTrustRemoteArtifacts);
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000471 buildCompleted = true;
472 } catch (BuildFailedException | TestExecException e) {
473 buildCompleted = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100474 throw e;
mschaller40379082019-02-01 14:14:47 -0800475 } catch (Error | RuntimeException e) {
476 catastrophe = e;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100477 } finally {
mschaller40379082019-02-01 14:14:47 -0800478 // These may flush logs, which may help if there is a catastrophic failure.
schmittbe241a12020-01-16 13:30:55 -0800479 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
480 executorLifecycleListener.executionPhaseEnding();
mschaller40379082019-02-01 14:14:47 -0800481 }
482
483 // Handlers process these events and others (e.g. CommandCompleteEvent), even in the event of
484 // a catastrophic failure. Posting these is consistent with other behavior.
janakrac58ca82019-02-14 09:34:20 -0800485 env.getEventBus().post(skyframeExecutor.createExecutionFinishedEvent());
mschaller40379082019-02-01 14:14:47 -0800486
487 env.getEventBus()
488 .post(new ExecutionPhaseCompleteEvent(timer.stop().elapsed(TimeUnit.MILLISECONDS)));
489
490 if (catastrophe != null) {
491 Throwables.throwIfUnchecked(catastrophe);
492 }
493 // NOTE: No finalization activities below will run in the event of a catastrophic error!
494
Ulf Adamsb5146102015-10-20 08:57:26 +0000495 env.recordLastExecutionTime();
mschaller40379082019-02-01 14:14:47 -0800496
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100497 if (request.isRunningInEmacs()) {
Klaus Aehligad87c132017-08-14 12:20:39 +0200498 request
499 .getOutErr()
brandjon79712cb2019-12-04 10:01:17 -0800500 .printErrLn(runtime.getProductName() + ": Leaving directory `" + getExecRoot() + "/'");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100501 }
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000502 if (buildCompleted) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100503 getReporter().handle(Event.progress("Building complete."));
504 }
505
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000506 if (buildCompleted) {
jmmv59787f12017-08-28 21:41:21 +0200507 saveActionCache(actionCache);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100508 }
509
ulfjack1fbe72e2018-06-14 04:46:27 -0700510 try (SilentCloseable c = Profiler.instance().profile("Show results")) {
Ulf Adams7a3fe522015-12-04 10:48:56 +0000511 buildResult.setSuccessfulTargets(
tomlu6ed4fd52018-04-03 10:01:10 -0700512 determineSuccessfulTargets(configuredTargets, builtTargets));
janakrf15d08d2020-04-22 12:53:03 -0700513 buildResult.setSuccessfulAspects(
514 determineSuccessfulAspects(analysisResult.getAspectsMap().keySet(), builtAspects));
gregce45ae0962017-07-22 00:11:13 +0200515 buildResult.setSkippedTargets(analysisResult.getTargetsToSkip());
Googler3ca7b782015-10-12 15:44:09 +0000516 BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env);
mschaller40379082019-02-01 14:14:47 -0800517 buildResultPrinter.showBuildResult(
518 request,
519 buildResult,
520 configuredTargets,
521 analysisResult.getTargetsToSkip(),
janakrf15d08d2020-04-22 12:53:03 -0700522 analysisResult.getAspectsMap());
Nathan Harmatad4803012015-09-08 20:03:22 +0000523 }
Googler3ca7b782015-10-12 15:44:09 +0000524
ulfjack1fbe72e2018-06-14 04:46:27 -0700525 try (SilentCloseable c = Profiler.instance().profile("Show artifacts")) {
Googler3ca7b782015-10-12 15:44:09 +0000526 if (request.getBuildOptions().showArtifacts) {
527 BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env);
janakrf15d08d2020-04-22 12:53:03 -0700528 buildResultPrinter.showArtifacts(
529 request, configuredTargets, analysisResult.getAspectsMap().values());
Googler3ca7b782015-10-12 15:44:09 +0000530 }
531 }
532
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100533 if (explanationHandler != null) {
534 uninstallExplanationHandler(explanationHandler);
laszlocsomor482235b2018-11-22 08:15:15 -0800535 try {
536 explanationHandler.close();
537 } catch (IOException _ignored) {
538 // Ignored
539 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100540 }
541 // Finalize output service last, so that if we do throw an exception, we know all the other
542 // code has already run.
Ulf Adams706b7f22015-10-20 09:06:45 +0000543 if (env.getOutputService() != null) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100544 boolean isBuildSuccessful =
545 buildResult.getSuccessfulTargets().size() == configuredTargets.size();
Ulf Adams706b7f22015-10-20 09:06:45 +0000546 env.getOutputService().finalizeBuild(isBuildSuccessful);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100547 }
548 }
549 }
550
ichern121933e2020-01-27 02:08:19 -0800551 private void prepare(
552 PackageRoots packageRoots, ImmutableSortedSet<String> nonSymlinkedDirectoriesUnderExecRoot)
553 throws AbruptExitException, InterruptedException {
tomluee6a6862018-01-17 14:36:26 -0800554 Optional<ImmutableMap<PackageIdentifier, Root>> packageRootMap =
janakrae323982017-09-29 21:11:53 +0200555 packageRoots.getPackageRootsMap();
arostovtsev20b056a2019-08-30 15:00:31 -0700556 if (packageRootMap.isPresent()) {
557 // Prepare for build.
558 Profiler.instance().markPhase(ProfilePhase.PREPARE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100559
arostovtsev20b056a2019-08-30 15:00:31 -0700560 // Plant the symlink forest.
561 try (SilentCloseable c = Profiler.instance().profile("plantSymlinkForest")) {
ichern121933e2020-01-27 02:08:19 -0800562 SymlinkForest symlinkForest =
563 new SymlinkForest(
564 packageRootMap.get(),
565 getExecRoot(),
566 runtime.getProductName(),
Jingwen Chen63605572020-02-13 13:47:00 -0800567 nonSymlinkedDirectoriesUnderExecRoot,
adonovan240bdea2020-09-03 15:24:12 -0700568 request.getOptions(BuildLanguageOptions.class).experimentalSiblingRepositoryLayout);
ichern121933e2020-01-27 02:08:19 -0800569 symlinkForest.plantSymlinkForest();
arostovtsev20b056a2019-08-30 15:00:31 -0700570 } catch (IOException e) {
mschallerb976a8b2020-05-11 11:00:14 -0700571 throw new AbruptExitException(
572 DetailedExitCode.of(
573 FailureDetail.newBuilder()
574 .setMessage("Source forest creation failed")
575 .setSymlinkForest(
576 FailureDetails.SymlinkForest.newBuilder()
577 .setCode(FailureDetails.SymlinkForest.Code.CREATION_FAILED))
578 .build()),
579 e);
arostovtsev20b056a2019-08-30 15:00:31 -0700580 }
Kristina Chodorow52bc57c2016-06-20 14:27:56 +0000581 }
arostovtsev20b056a2019-08-30 15:00:31 -0700582 env.getEventBus().post(new ExecRootPreparedEvent(packageRootMap));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100583 }
584
arostovtsev5b8c8c32020-06-23 11:31:06 -0700585 private static void logDeleteTreeFailure(
586 Path directory, String description, IOException deleteTreeFailure) {
587 logger.atWarning().withCause(deleteTreeFailure).log(
588 "Failed to delete %s '%s'", description, directory);
589 if (directory.exists()) {
590 try {
591 Collection<Path> entries = directory.getDirectoryEntries();
592 StringBuilder directoryDetails =
593 new StringBuilder("'")
594 .append(directory)
595 .append("' contains ")
596 .append(entries.size())
597 .append(" entries:");
598 for (Path entry : entries) {
599 directoryDetails.append(" '").append(entry.getBaseName()).append("'");
600 }
601 logger.atWarning().log(directoryDetails.toString());
602 } catch (IOException e) {
603 logger.atWarning().withCause(e).log("'%s' exists but could not be read", directory);
604 }
605 } else {
606 logger.atWarning().log("'%s' does not exist", directory);
607 }
608 }
609
mschallerb976a8b2020-05-11 11:00:14 -0700610 private void createActionLogDirectory() throws AbruptExitException {
jmmv88e22cd2019-09-15 09:59:49 -0700611 Path directory = env.getActionTempsDirectory();
arostovtsev702a1c62020-01-15 11:59:50 -0800612 if (directory.exists()) {
613 try {
jmmv5cc1f652019-03-20 09:34:08 -0700614 directory.deleteTree();
arostovtsev702a1c62020-01-15 11:59:50 -0800615 } catch (IOException e) {
arostovtsev5b8c8c32020-06-23 11:31:06 -0700616 // TODO(b/140567980): Remove when we determine the cause of occasional deleteTree() failure.
617 logDeleteTreeFailure(directory, "action output directory", e);
mschallerb976a8b2020-05-11 11:00:14 -0700618 throw createExitException(
619 "Couldn't delete action output directory",
mschaller05efa282020-06-24 12:54:16 -0700620 Code.TEMP_ACTION_OUTPUT_DIRECTORY_DELETION_FAILURE,
mschallerb976a8b2020-05-11 11:00:14 -0700621 e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100622 }
arostovtsev702a1c62020-01-15 11:59:50 -0800623 }
624
625 try {
ulfjackf20b33c2020-01-30 07:36:30 -0800626 directory.createDirectoryAndParents();
Nathan Harmataca06fa22015-07-27 19:54:14 +0000627 } catch (IOException e) {
mschallerb976a8b2020-05-11 11:00:14 -0700628 throw createExitException(
629 "Couldn't create action output directory",
mschaller05efa282020-06-24 12:54:16 -0700630 Code.TEMP_ACTION_OUTPUT_DIRECTORY_CREATION_FAILURE,
mschallerb976a8b2020-05-11 11:00:14 -0700631 e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100632 }
ulfjackf20b33c2020-01-30 07:36:30 -0800633
634 try {
635 env.getPersistentActionOutsDirectory().createDirectoryAndParents();
636 } catch (IOException e) {
mschallerb976a8b2020-05-11 11:00:14 -0700637 throw createExitException(
638 "Couldn't create persistent action output directory",
639 Code.PERSISTENT_ACTION_OUTPUT_DIRECTORY_CREATION_FAILURE,
640 e);
ulfjackf20b33c2020-01-30 07:36:30 -0800641 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100642 }
643
brandjon07cc56d2019-11-25 10:00:12 -0800644 /**
jhorvitz33f76482021-10-28 10:13:26 -0700645 * Obtains the {@link BuildConfigurationValue} for a given {@link BuildOptions} for the purpose of
brandjon7b5043f2019-11-25 12:30:22 -0800646 * symlink creation.
647 *
648 * <p>In the event of a {@link InvalidConfigurationException}, a warning is emitted and null is
649 * returned.
650 */
651 @Nullable
jhorvitz33f76482021-10-28 10:13:26 -0700652 private static BuildConfigurationValue getConfiguration(
brandjon7b5043f2019-11-25 12:30:22 -0800653 SkyframeExecutor executor, Reporter reporter, BuildOptions options) {
654 try {
655 return executor.getConfiguration(reporter, options, /*keepGoing=*/ false);
656 } catch (InvalidConfigurationException e) {
657 reporter.handle(
658 Event.warn(
659 "Couldn't get configuration for convenience symlink creation: " + e.getMessage()));
660 return null;
661 }
662 }
663
664 /**
Googler87636392019-12-30 12:57:56 -0800665 * Handles what action to perform on the convenience symlinks. If the the mode is {@link
jcater40b60742020-05-15 07:04:00 -0700666 * ConvenienceSymlinksMode#IGNORE}, then skip any creating or cleaning of convenience symlinks.
Googler87636392019-12-30 12:57:56 -0800667 * Otherwise, manage the convenience symlinks and then post a {@link
668 * ConvenienceSymlinksIdentifiedEvent} build event.
669 */
670 private void handleConvenienceSymlinks(AnalysisResult analysisResult) {
671 ImmutableList<ConvenienceSymlink> convenienceSymlinks = ImmutableList.of();
672 if (request.getBuildOptions().experimentalConvenienceSymlinks
673 != ConvenienceSymlinksMode.IGNORE) {
674 convenienceSymlinks = createConvenienceSymlinks(request.getBuildOptions(), analysisResult);
675 }
676 if (request.getBuildOptions().experimentalConvenienceSymlinksBepEvent) {
677 env.getEventBus().post(new ConvenienceSymlinksIdentifiedEvent(convenienceSymlinks));
678 }
679 }
680
681 /**
brandjon07cc56d2019-11-25 10:00:12 -0800682 * Creates convenience symlinks based on the target configurations.
683 *
684 * <p>Exactly what target configurations we consider depends on the value of {@code
685 * --use_top_level_targets_for_symlinks}. If this flag is false, we use the top-level target
686 * configuration as represented by the command line prior to processing any target. If the flag is
687 * true, we instead use the configurations OF the top-level targets -- meaning that we account for
688 * the effects of any rule transitions these targets may have.
689 *
690 * <p>For each type of convenience symlink, if all the considered configurations agree on what
691 * path the symlink should point to, it gets created; otherwise, the symlink is not created, and
692 * in fact gets removed if it was already present from a previous invocation.
693 */
Googler87636392019-12-30 12:57:56 -0800694 private ImmutableList<ConvenienceSymlink> createConvenienceSymlinks(
brandjon07cc56d2019-11-25 10:00:12 -0800695 BuildRequestOptions buildRequestOptions, AnalysisResult analysisResult) {
696 SkyframeExecutor executor = env.getSkyframeExecutor();
697 Reporter reporter = env.getReporter();
698
699 // Gather configurations to consider.
jhorvitz33f76482021-10-28 10:13:26 -0700700 Set<BuildConfigurationValue> targetConfigurations =
brandjon07cc56d2019-11-25 10:00:12 -0800701 buildRequestOptions.useTopLevelTargetsForSymlinks()
702 ? analysisResult.getTargetsToBuild().stream()
703 .map(ConfiguredTarget::getConfigurationKey)
jhorvitzcd477f22021-05-05 10:18:22 -0700704 .filter(Objects::nonNull)
brandjon07cc56d2019-11-25 10:00:12 -0800705 .distinct()
706 .map((key) -> executor.getConfiguration(reporter, key))
707 .collect(toImmutableSet())
708 : ImmutableSet.copyOf(
709 analysisResult.getConfigurationCollection().getTargetConfigurations());
710
711 String productName = runtime.getProductName();
brandjon07cc56d2019-11-25 10:00:12 -0800712 try (SilentCloseable c =
713 Profiler.instance().profile("OutputDirectoryLinksUtils.createOutputDirectoryLinks")) {
Googler87636392019-12-30 12:57:56 -0800714 return OutputDirectoryLinksUtils.createOutputDirectoryLinks(
brandjon8a603602019-12-04 10:40:38 -0800715 runtime.getRuleClassProvider().getSymlinkDefinitions(),
brandjon282958b2019-12-04 08:14:26 -0800716 buildRequestOptions,
Googler87636392019-12-30 12:57:56 -0800717 env.getWorkspaceName(),
brandjon07cc56d2019-11-25 10:00:12 -0800718 env.getWorkspace(),
Googler87636392019-12-30 12:57:56 -0800719 env.getDirectories(),
brandjon07cc56d2019-11-25 10:00:12 -0800720 getReporter(),
721 targetConfigurations,
brandjon7b5043f2019-11-25 12:30:22 -0800722 options -> getConfiguration(executor, reporter, options),
brandjon282958b2019-12-04 08:14:26 -0800723 productName);
brandjon07cc56d2019-11-25 10:00:12 -0800724 }
725 }
726
buchgr7b515522019-03-29 04:42:17 -0700727 /** Prepare for a local output build. */
mschallerb976a8b2020-05-11 11:00:14 -0700728 private void startLocalOutputBuild() throws AbruptExitException {
ulfjack1fbe72e2018-06-14 04:46:27 -0700729 try (SilentCloseable c = Profiler.instance().profile("Starting local output build")) {
kchodorow85ae1902017-04-22 15:07:22 -0400730 Path outputPath = env.getDirectories().getOutputPath(env.getWorkspaceName());
Ulf Adams94b72db2016-03-30 11:58:37 +0000731 Path localOutputPath = env.getDirectories().getLocalOutputPath();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100732
733 if (outputPath.isSymbolicLink()) {
Nathan Harmataca06fa22015-07-27 19:54:14 +0000734 try {
735 // Remove the existing symlink first.
736 outputPath.delete();
737 if (localOutputPath.exists()) {
738 // Pre-existing local output directory. Move to outputPath.
739 localOutputPath.renameTo(outputPath);
740 }
741 } catch (IOException e) {
mschallerb976a8b2020-05-11 11:00:14 -0700742 throw createExitException(
743 "Couldn't handle local output directory symlinks",
744 Code.LOCAL_OUTPUT_DIRECTORY_SYMLINK_FAILURE,
745 e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100746 }
747 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100748 }
749 }
750
751 /**
buchgr7b515522019-03-29 04:42:17 -0700752 * If a path is supplied, creates and installs an ExplanationHandler. Returns an instance on
753 * success. Reports an error and returns null otherwise.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100754 */
buchgr7b515522019-03-29 04:42:17 -0700755 private ExplanationHandler installExplanationHandler(
756 PathFragment explanationPath, String allOptions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100757 if (explanationPath == null) {
758 return null;
759 }
760 ExplanationHandler handler;
761 try {
buchgr7b515522019-03-29 04:42:17 -0700762 handler =
763 new ExplanationHandler(
764 getWorkspace().getRelative(explanationPath).getOutputStream(), allOptions);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100765 } catch (IOException e) {
buchgr7b515522019-03-29 04:42:17 -0700766 getReporter()
767 .handle(
768 Event.warn(
769 String.format(
770 "Cannot write explanation of rebuilds to file '%s': %s",
771 explanationPath, e.getMessage())));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100772 return null;
773 }
buchgr7b515522019-03-29 04:42:17 -0700774 getReporter()
775 .handle(Event.info("Writing explanation of rebuilds to '" + explanationPath + "'"));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100776 getReporter().addHandler(handler);
777 return handler;
778 }
779
buchgr7b515522019-03-29 04:42:17 -0700780 /** Uninstalls the specified ExplanationHandler (if any) and closes the log file. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100781 private void uninstallExplanationHandler(ExplanationHandler handler) {
782 if (handler != null) {
783 getReporter().removeHandler(handler);
784 handler.log.close();
785 }
786 }
787
788 /**
laszlocsomor482235b2018-11-22 08:15:15 -0800789 * An ErrorEventListener implementation that records DEPCHECKER events into a log file, iff the
790 * --explain flag is specified during a build.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100791 */
laszlocsomor482235b2018-11-22 08:15:15 -0800792 private static class ExplanationHandler implements EventHandler, AutoCloseable {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100793 private final PrintWriter log;
794
795 private ExplanationHandler(OutputStream log, String optionsDescription) {
lberki0d8d4cf2017-09-05 16:01:44 +0200796 this.log = new PrintWriter(new OutputStreamWriter(log, StandardCharsets.UTF_8));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100797 this.log.println("Build options: " + optionsDescription);
798 }
799
laszlocsomor482235b2018-11-22 08:15:15 -0800800 @Override
801 public void close() throws IOException {
802 this.log.close();
803 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100804
805 @Override
806 public void handle(Event event) {
807 if (event.getKind() == EventKind.DEPCHECKER) {
808 log.println(event.getMessage());
809 }
810 }
811 }
812
813 /**
tomlu6ed4fd52018-04-03 10:01:10 -0700814 * Computes the result of the build. Sets the list of successful (up-to-date) targets in the
815 * request object.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100816 *
tomlu6ed4fd52018-04-03 10:01:10 -0700817 * @param configuredTargets The configured targets whose artifacts are to be built.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100818 */
lebaf7b8b722021-11-16 06:09:08 -0800819 static ImmutableSet<ConfiguredTarget> determineSuccessfulTargets(
cpeyser8e9b28f2018-06-04 08:05:13 -0700820 Collection<ConfiguredTarget> configuredTargets, Set<ConfiguredTargetKey> builtTargets) {
lebaf7b8b722021-11-16 06:09:08 -0800821 // Maintain the ordering by copying builtTargets into an ImmutableSet.Builder in the same
822 // iteration order as configuredTargets.
823 ImmutableSet.Builder<ConfiguredTarget> successfulTargets = ImmutableSet.builder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100824 for (ConfiguredTarget target : configuredTargets) {
jcater83221e32020-05-28 11:37:39 -0700825 if (builtTargets.contains(
826 ConfiguredTargetKey.builder()
827 .setConfiguredTarget(target)
828 .setConfigurationKey(target.getConfigurationKey())
829 .build())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100830 successfulTargets.add(target);
831 }
832 }
lebaf7b8b722021-11-16 06:09:08 -0800833 return successfulTargets.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100834 }
835
lebaf7b8b722021-11-16 06:09:08 -0800836 static ImmutableSet<AspectKey> determineSuccessfulAspects(
janakrf15d08d2020-04-22 12:53:03 -0700837 ImmutableSet<AspectKey> aspects, Set<AspectKey> builtAspects) {
838 // Maintain the ordering.
839 return aspects.stream().filter(builtAspects::contains).collect(ImmutableSet.toImmutableSet());
tomlu6ed4fd52018-04-03 10:01:10 -0700840 }
841
ccalvarinb5fd7612017-12-14 12:21:48 -0800842 /** Get action cache if present or reload it from the on-disk cache. */
Googler2e1104e2020-05-08 06:51:08 -0700843 private ActionCache getActionCache() throws AbruptExitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100844 try {
jhorvitz4d5f3542021-07-19 10:12:29 -0700845 return env.getBlazeWorkspace().getOrLoadPersistentActionCache(getReporter());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100846 } catch (IOException e) {
Googler2e1104e2020-05-08 06:51:08 -0700847 String message =
848 String.format(
849 "Couldn't create action cache: %s. If error persists, use 'bazel clean'.",
850 e.getMessage());
mschallerb976a8b2020-05-11 11:00:14 -0700851 throw new AbruptExitException(
852 DetailedExitCode.of(
853 FailureDetail.newBuilder()
854 .setMessage(message)
855 .setActionCache(
856 FailureDetails.ActionCache.newBuilder()
857 .setCode(FailureDetails.ActionCache.Code.INITIALIZATION_FAILURE))
858 .build()),
Googler2e1104e2020-05-08 06:51:08 -0700859 e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100860 }
861 }
862
buchgr7b515522019-03-29 04:42:17 -0700863 private Builder createBuilder(
864 BuildRequest request,
jhorvitz4d5f3542021-07-19 10:12:29 -0700865 @Nullable ActionCache actionCache,
Eric Fellheimerf3b43af2015-11-13 19:51:20 +0000866 SkyframeExecutor skyframeExecutor,
Ulf Adams1ac1b992016-11-02 12:50:26 +0000867 ModifiedFileSet modifiedOutputFiles) {
janakr6b1b8a92017-11-10 23:20:22 +0100868 BuildRequestOptions options = request.getBuildOptions();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100869
ulfjackf20b33c2020-01-30 07:36:30 -0800870 skyframeExecutor.setActionOutputRoot(
871 env.getActionTempsDirectory(), env.getPersistentActionOutsDirectory());
872
buchgr7b515522019-03-29 04:42:17 -0700873 Predicate<Action> executionFilter =
874 CheckUpToDateFilter.fromOptions(request.getOptions(ExecutionOptions.class));
Ulf Adams3d67e002016-03-29 16:23:01 +0000875 ArtifactFactory artifactFactory = env.getSkyframeBuildView().getArtifactFactory();
Googler2f111922017-02-28 20:58:45 +0000876 return new SkyframeBuilder(
877 skyframeExecutor,
ulfjack985a34ad2019-08-09 01:51:15 -0700878 env.getLocalResourceManager(),
Googler2f111922017-02-28 20:58:45 +0000879 new ActionCacheChecker(
880 actionCache,
881 artifactFactory,
tomlu3d1a1942017-11-29 14:01:21 -0800882 skyframeExecutor.getActionKeyContext(),
Googler2f111922017-02-28 20:58:45 +0000883 executionFilter,
884 ActionCacheChecker.CacheConfig.builder()
885 .setEnabled(options.useActionCache)
886 .setVerboseExplanations(options.verboseExplanations)
Chi Wang4e290422021-08-03 17:56:19 -0700887 .setStoreOutputMetadata(options.actionCacheStoreOutputMetadata)
jhorvitz53f18992021-10-29 10:00:35 -0700888 .build()),
fellyc5c078c2019-07-31 12:05:24 -0700889 env.getTopDownActionCache(),
ajurkowskid74b0ec2020-04-13 10:58:21 -0700890 request.getPackageOptions().checkOutputFiles
Googler2f111922017-02-28 20:58:45 +0000891 ? modifiedOutputFiles
892 : ModifiedFileSet.NOTHING_MODIFIED,
schmitte6433402020-01-07 12:57:46 -0800893 env.getFileCache(),
janakr46e5efd2021-04-05 13:03:46 -0700894 prefetcher,
895 env.getRuntime().getBugReporter());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100896 }
897
steinman13a628a2019-01-09 08:39:32 -0800898 @VisibleForTesting
ulfjack985a34ad2019-08-09 01:51:15 -0700899 public static void configureResourceManager(ResourceManager resourceMgr, BuildRequest request) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100900 ExecutionOptions options = request.getOptions(ExecutionOptions.class);
larsrc8fa3ccb2021-10-26 08:27:34 -0700901 resourceMgr.setPrioritizeLocalActions(options.prioritizeLocalActions);
Josh Pieper7f3bddd2018-05-04 00:39:37 -0700902 resourceMgr.setUseLocalMemoryEstimate(options.localMemoryEstimate);
buchgr7b515522019-03-29 04:42:17 -0700903 resourceMgr.setAvailableResources(
904 ResourceSet.create(
larsrc8fa3ccb2021-10-26 08:27:34 -0700905 options.localRamResources,
906 options.localCpuResources,
907 options.usingLocalTestJobs() ? options.localTestJobs : Integer.MAX_VALUE));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100908 }
909
910 /**
jmmv59787f12017-08-28 21:41:21 +0200911 * Writes the action cache files to disk, reporting any errors that occurred during writing and
912 * capturing statistics.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100913 */
jhorvitz4d5f3542021-07-19 10:12:29 -0700914 private void saveActionCache(@Nullable ActionCache actionCache) {
jmmvccb43ee2017-08-30 22:07:10 +0200915 ActionCacheStatistics.Builder builder = ActionCacheStatistics.newBuilder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100916
jhorvitz4d5f3542021-07-19 10:12:29 -0700917 if (actionCache != null) {
918 actionCache.mergeIntoActionCacheStatistics(builder);
919
920 AutoProfiler p =
921 GoogleAutoProfilerUtils.profiledAndLogged("Saving action cache", ProfilerTask.INFO);
922 try {
923 builder.setSizeInBytes(actionCache.save());
924 } catch (IOException e) {
925 builder.setSizeInBytes(0);
926 getReporter().handle(Event.error("I/O error while writing action log: " + e.getMessage()));
927 } finally {
928 builder.setSaveTimeInMs(Duration.ofNanos(p.completeAndGetElapsedTimeNanos()).toMillis());
929 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100930 }
jmmv59787f12017-08-28 21:41:21 +0200931
932 env.getEventBus().post(builder.build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100933 }
934
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100935 private Reporter getReporter() {
Ulf Adams633f5392015-09-15 11:13:08 +0000936 return env.getReporter();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100937 }
938
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100939 private Path getWorkspace() {
Ulf Adams94b72db2016-03-30 11:58:37 +0000940 return env.getWorkspace();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100941 }
942
943 private Path getExecRoot() {
Ulf Adams94b72db2016-03-30 11:58:37 +0000944 return env.getExecRoot();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100945 }
mschallerb976a8b2020-05-11 11:00:14 -0700946
947 private static AbruptExitException createExitException(
948 String message, Code detailedCode, IOException e) {
949 return new AbruptExitException(
950 DetailedExitCode.of(
951 FailureDetail.newBuilder()
952 .setMessage(message)
953 .setExecution(Execution.newBuilder().setCode(detailedCode))
954 .build()),
955 e);
956 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100957}