blob: 2aff66330f893eac495efc5fbbafe6360ab7bf08 [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.actions;
16
tomlua155b532017-11-08 20:12:47 +010017import com.google.common.base.Preconditions;
kush2ce45a22018-05-02 14:15:37 -070018import com.google.common.collect.ImmutableList;
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000019import com.google.common.collect.ImmutableMap;
ulfjack77c9f5e2017-06-19 14:17:52 +020020import com.google.common.eventbus.EventBus;
Michael Thvedt434e68e2016-02-09 00:57:46 +000021import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010022import com.google.devtools.build.lib.actions.cache.MetadataHandler;
philwo3bcb9f62017-09-06 12:52:21 +020023import com.google.devtools.build.lib.clock.Clock;
ulfjack77c9f5e2017-06-19 14:17:52 +020024import com.google.devtools.build.lib.cmdline.Label;
25import com.google.devtools.build.lib.events.Event;
ulfjack77c9f5e2017-06-19 14:17:52 +020026import com.google.devtools.build.lib.events.EventKind;
Benjamin Peterson1bbeadc2018-04-26 05:27:10 -070027import com.google.devtools.build.lib.events.ExtendedEventHandler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028import com.google.devtools.build.lib.util.io.FileOutErr;
tomluf903eb52017-10-27 12:12:11 -040029import com.google.devtools.build.lib.vfs.FileSystem;
ulfjack77c9f5e2017-06-19 14:17:52 +020030import com.google.devtools.build.lib.vfs.Path;
kush2ce45a22018-05-02 14:15:37 -070031import com.google.devtools.build.lib.vfs.PathFragment;
shahanb1dd4e32018-05-09 08:23:31 -070032import com.google.devtools.build.lib.vfs.Root;
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +000033import com.google.devtools.build.skyframe.SkyFunction;
34import com.google.devtools.build.skyframe.SkyFunction.Environment;
ulfjack77c9f5e2017-06-19 14:17:52 +020035import com.google.devtools.common.options.OptionsClassProvider;
ulfjack1a328e32017-04-06 10:25:16 +000036import java.io.Closeable;
37import java.io.IOException;
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000038import java.util.Map;
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +000039import javax.annotation.Nullable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010040
41/**
42 * A class that groups services in the scope of the action. Like the FileOutErr object.
43 */
ulfjack1a328e32017-04-06 10:25:16 +000044public class ActionExecutionContext implements Closeable {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045
46 private final Executor executor;
shahan499503b2018-06-07 18:57:07 -070047 private final MetadataProvider actionInputFileCache;
ulfjack7599a4d2017-07-21 13:58:33 +020048 private final ActionInputPrefetcher actionInputPrefetcher;
tomlu3d1a1942017-11-29 14:01:21 -080049 private final ActionKeyContext actionKeyContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050 private final MetadataHandler metadataHandler;
51 private final FileOutErr fileOutErr;
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000052 private final ImmutableMap<String, String> clientEnv;
kush2ce45a22018-05-02 14:15:37 -070053 private final ImmutableMap<PathFragment, ImmutableList<FilesetOutputSymlink>>
54 inputFilesetMappings;
shahanb1dd4e32018-05-09 08:23:31 -070055 @Nullable private final ArtifactExpander artifactExpander;
56 @Nullable private final Environment env;
57
58 @Nullable private final FileSystem actionFileSystem;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010059
kush2ce45a22018-05-02 14:15:37 -070060 @Nullable private ImmutableList<FilesetOutputSymlink> outputSymlinks;
61
fellyd3d86442018-06-08 18:29:43 -070062 private final ArtifactPathResolver pathResolver;
63
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000064 private ActionExecutionContext(
65 Executor executor,
shahan499503b2018-06-07 18:57:07 -070066 MetadataProvider actionInputFileCache,
ulfjack7599a4d2017-07-21 13:58:33 +020067 ActionInputPrefetcher actionInputPrefetcher,
tomlu3d1a1942017-11-29 14:01:21 -080068 ActionKeyContext actionKeyContext,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000069 MetadataHandler metadataHandler,
70 FileOutErr fileOutErr,
71 Map<String, String> clientEnv,
kush2ce45a22018-05-02 14:15:37 -070072 ImmutableMap<PathFragment, ImmutableList<FilesetOutputSymlink>> inputFilesetMappings,
Michael Thvedt434e68e2016-02-09 00:57:46 +000073 @Nullable ArtifactExpander artifactExpander,
shahanb1dd4e32018-05-09 08:23:31 -070074 @Nullable SkyFunction.Environment env,
75 @Nullable FileSystem actionFileSystem) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076 this.actionInputFileCache = actionInputFileCache;
ulfjack7599a4d2017-07-21 13:58:33 +020077 this.actionInputPrefetcher = actionInputPrefetcher;
tomlu3d1a1942017-11-29 14:01:21 -080078 this.actionKeyContext = actionKeyContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079 this.metadataHandler = metadataHandler;
80 this.fileOutErr = fileOutErr;
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000081 this.clientEnv = ImmutableMap.copyOf(clientEnv);
kush2ce45a22018-05-02 14:15:37 -070082 this.inputFilesetMappings = inputFilesetMappings;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083 this.executor = executor;
Michael Thvedt434e68e2016-02-09 00:57:46 +000084 this.artifactExpander = artifactExpander;
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +000085 this.env = env;
shahanb1dd4e32018-05-09 08:23:31 -070086 this.actionFileSystem = actionFileSystem;
fellyd3d86442018-06-08 18:29:43 -070087 this.pathResolver = createPathResolver(actionFileSystem,
88 // executor is only ever null in testing.
89 executor == null ? null : executor.getExecRoot());
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +000090 }
91
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000092 public ActionExecutionContext(
93 Executor executor,
shahan499503b2018-06-07 18:57:07 -070094 MetadataProvider actionInputFileCache,
ulfjack7599a4d2017-07-21 13:58:33 +020095 ActionInputPrefetcher actionInputPrefetcher,
tomlu3d1a1942017-11-29 14:01:21 -080096 ActionKeyContext actionKeyContext,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +000097 MetadataHandler metadataHandler,
98 FileOutErr fileOutErr,
99 Map<String, String> clientEnv,
kush2ce45a22018-05-02 14:15:37 -0700100 ImmutableMap<PathFragment, ImmutableList<FilesetOutputSymlink>> inputFilesetMappings,
shahanb1dd4e32018-05-09 08:23:31 -0700101 ArtifactExpander artifactExpander,
102 @Nullable FileSystem actionFileSystem) {
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000103 this(
104 executor,
105 actionInputFileCache,
ulfjack7599a4d2017-07-21 13:58:33 +0200106 actionInputPrefetcher,
tomlu3d1a1942017-11-29 14:01:21 -0800107 actionKeyContext,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000108 metadataHandler,
109 fileOutErr,
110 clientEnv,
kush2ce45a22018-05-02 14:15:37 -0700111 inputFilesetMappings,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000112 artifactExpander,
shahanb1dd4e32018-05-09 08:23:31 -0700113 /*env=*/ null,
114 actionFileSystem);
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +0000115 }
116
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000117 public static ActionExecutionContext forInputDiscovery(
118 Executor executor,
shahan499503b2018-06-07 18:57:07 -0700119 MetadataProvider actionInputFileCache,
ulfjack7599a4d2017-07-21 13:58:33 +0200120 ActionInputPrefetcher actionInputPrefetcher,
tomlu3d1a1942017-11-29 14:01:21 -0800121 ActionKeyContext actionKeyContext,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000122 MetadataHandler metadataHandler,
123 FileOutErr fileOutErr,
124 Map<String, String> clientEnv,
shahanb1dd4e32018-05-09 08:23:31 -0700125 Environment env,
126 @Nullable FileSystem actionFileSystem) {
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000127 return new ActionExecutionContext(
ulfjack7599a4d2017-07-21 13:58:33 +0200128 executor,
129 actionInputFileCache,
130 actionInputPrefetcher,
tomlu3d1a1942017-11-29 14:01:21 -0800131 actionKeyContext,
ulfjack7599a4d2017-07-21 13:58:33 +0200132 metadataHandler,
133 fileOutErr,
134 clientEnv,
kush2ce45a22018-05-02 14:15:37 -0700135 ImmutableMap.of(),
shahanb1dd4e32018-05-09 08:23:31 -0700136 /*artifactExpander=*/ null,
137 env,
138 actionFileSystem);
ulfjack7599a4d2017-07-21 13:58:33 +0200139 }
140
141 public ActionInputPrefetcher getActionInputPrefetcher() {
142 return actionInputPrefetcher;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100143 }
144
shahan499503b2018-06-07 18:57:07 -0700145 public MetadataProvider getMetadataProvider() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100146 return actionInputFileCache;
147 }
148
149 public MetadataHandler getMetadataHandler() {
150 return metadataHandler;
151 }
152
tomluf903eb52017-10-27 12:12:11 -0400153 public FileSystem getFileSystem() {
felly7fd3b002018-05-24 15:03:40 -0700154 if (actionFileSystem != null) {
155 return actionFileSystem;
156 }
tomluf903eb52017-10-27 12:12:11 -0400157 return executor.getFileSystem();
158 }
159
ulfjack77c9f5e2017-06-19 14:17:52 +0200160 public Path getExecRoot() {
felly7fd3b002018-05-24 15:03:40 -0700161 return actionFileSystem != null
162 ? actionFileSystem.getPath(executor.getExecRoot().asFragment())
163 : executor.getExecRoot();
ulfjack77c9f5e2017-06-19 14:17:52 +0200164 }
165
166 /**
shahan18726b72018-03-15 14:18:46 -0700167 * Returns the path for an ActionInput.
168 *
169 * <p>Notably, in the future, we want any action-scoped artifacts to resolve paths using this
170 * method instead of {@link Artifact#getPath} because that does not allow filesystem injection.
171 *
shahanb1dd4e32018-05-09 08:23:31 -0700172 * <p>TODO(shahan): cleanup {@link Action}-scoped references to {@link Artifact.getPath} and
173 * {@link Artifact.getRoot}.
shahan18726b72018-03-15 14:18:46 -0700174 */
175 public Path getInputPath(ActionInput input) {
fellyd3d86442018-06-08 18:29:43 -0700176 return pathResolver.toPath(input);
shahan18726b72018-03-15 14:18:46 -0700177 }
178
shahanb1dd4e32018-05-09 08:23:31 -0700179 public Root getRoot(Artifact artifact) {
fellyd3d86442018-06-08 18:29:43 -0700180 return pathResolver.transformRoot(artifact.getRoot().getRoot());
181 }
182
183 private static ArtifactPathResolver createPathResolver(FileSystem actionFileSystem,
184 Path execRoot) {
185 if (actionFileSystem == null) {
186 return ArtifactPathResolver.forExecRoot(execRoot);
187 } else {
188 return ArtifactPathResolver.withTransformedFileSystem(
189 actionFileSystem.getPath(execRoot.asFragment()));
shahanb1dd4e32018-05-09 08:23:31 -0700190 }
fellyd3d86442018-06-08 18:29:43 -0700191 }
192
193 public ArtifactPathResolver getPathResolver() {
194 return pathResolver;
shahanb1dd4e32018-05-09 08:23:31 -0700195 }
196
shahan18726b72018-03-15 14:18:46 -0700197 /**
ulfjack77c9f5e2017-06-19 14:17:52 +0200198 * Returns whether failures should have verbose error messages.
199 */
200 public boolean getVerboseFailures() {
201 return executor.getVerboseFailures();
202 }
203
204 /**
205 * Returns the command line options of the Blaze command being executed.
206 */
207 public OptionsClassProvider getOptions() {
208 return executor.getOptions();
209 }
210
211 public Clock getClock() {
212 return executor.getClock();
213 }
214
215 public EventBus getEventBus() {
216 return executor.getEventBus();
217 }
218
Benjamin Peterson1bbeadc2018-04-26 05:27:10 -0700219 public ExtendedEventHandler getEventHandler() {
ulfjack77c9f5e2017-06-19 14:17:52 +0200220 return executor.getEventHandler();
221 }
222
kush2ce45a22018-05-02 14:15:37 -0700223 public ImmutableMap<PathFragment, ImmutableList<FilesetOutputSymlink>> getInputFilesetMappings() {
224 return inputFilesetMappings;
225 }
226
227 @Nullable
228 public ImmutableList<FilesetOutputSymlink> getOutputSymlinks() {
229 return outputSymlinks;
230 }
231
232 public void setOutputSymlinks(ImmutableList<FilesetOutputSymlink> outputSymlinks) {
233 Preconditions.checkState(
234 this.outputSymlinks == null,
235 "Unexpected reassignment of the outputSymlinks of a Fileset from\n:%s to:\n%s",
236 this.outputSymlinks,
237 outputSymlinks);
238 this.outputSymlinks = outputSymlinks;
239 }
240
ulfjack77c9f5e2017-06-19 14:17:52 +0200241 /**
242 * Looks up and returns an action context implementation of the given interface type.
243 */
244 public <T extends ActionContext> T getContext(Class<? extends T> type) {
245 return executor.getContext(type);
246 }
247
ulfjack77c9f5e2017-06-19 14:17:52 +0200248 /**
249 * Whether this Executor reports subcommands. If not, reportSubcommand has no effect.
250 * This is provided so the caller of reportSubcommand can avoid wastefully constructing the
251 * subcommand string.
252 */
253 public boolean reportsSubcommands() {
254 return executor.reportsSubcommands();
255 }
256
257 /**
258 * Report a subcommand event to this Executor's Reporter and, if action
259 * logging is enabled, post it on its EventBus.
260 */
261 public void reportSubcommand(Spawn spawn) {
262 String reason;
263 ActionOwner owner = spawn.getResourceOwner().getOwner();
264 if (owner == null) {
265 reason = spawn.getResourceOwner().prettyPrint();
266 } else {
267 reason = Label.print(owner.getLabel())
268 + " [" + spawn.getResourceOwner().prettyPrint() + "]";
269 }
270 String message = Spawns.asShellCommand(spawn, getExecRoot());
271 getEventHandler().handle(Event.of(EventKind.SUBCOMMAND, null, "# " + reason + "\n" + message));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100272 }
273
Klaus Aehlig4c10f3f2016-08-26 15:58:48 +0000274 public ImmutableMap<String, String> getClientEnv() {
275 return clientEnv;
276 }
277
Michael Thvedt434e68e2016-02-09 00:57:46 +0000278 public ArtifactExpander getArtifactExpander() {
279 return artifactExpander;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100280 }
281
282 /**
283 * Provide that {@code FileOutErr} that the action should use for redirecting the output and error
284 * stream.
285 */
286 public FileOutErr getFileOutErr() {
287 return fileOutErr;
288 }
289
shahand3702902018-05-11 12:14:32 -0700290 public boolean hasActionFileSystem() {
291 return actionFileSystem != null;
292 }
293
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100294 /**
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +0000295 * Provides a mechanism for the action to request values from Skyframe while it discovers inputs.
296 */
297 public Environment getEnvironmentForDiscoveringInputs() {
298 return Preconditions.checkNotNull(env);
299 }
300
tomlu3d1a1942017-11-29 14:01:21 -0800301 public ActionKeyContext getActionKeyContext() {
302 return actionKeyContext;
303 }
304
ulfjack1a328e32017-04-06 10:25:16 +0000305 @Override
306 public void close() throws IOException {
307 fileOutErr.close();
308 }
309
Janak Ramakrishnan29c5ab42015-05-14 19:38:12 +0000310 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100311 * Allows us to create a new context that overrides the FileOutErr with another one. This is
312 * useful for muting the output for example.
313 */
314 public ActionExecutionContext withFileOutErr(FileOutErr fileOutErr) {
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000315 return new ActionExecutionContext(
316 executor,
317 actionInputFileCache,
ulfjack7599a4d2017-07-21 13:58:33 +0200318 actionInputPrefetcher,
tomlu3d1a1942017-11-29 14:01:21 -0800319 actionKeyContext,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000320 metadataHandler,
321 fileOutErr,
322 clientEnv,
kush2ce45a22018-05-02 14:15:37 -0700323 inputFilesetMappings,
Klaus Aehligd2fcd9d2016-08-26 08:16:25 +0000324 artifactExpander,
shahanb1dd4e32018-05-09 08:23:31 -0700325 env,
326 actionFileSystem);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100327 }
328}