-
Notifications
You must be signed in to change notification settings - Fork 4k
/
BlazeModule.java
477 lines (436 loc) · 18 KB
/
BlazeModule.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.runtime;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.eventbus.SubscriberExceptionHandler;
import com.google.devtools.build.lib.analysis.AnalysisResult;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.ServerDirectories;
import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.test.CoverageReportActionFactory;
import com.google.devtools.build.lib.buildtool.BuildRequest;
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.exec.ExecutorBuilder;
import com.google.devtools.build.lib.exec.ModuleActionContextRegistry;
import com.google.devtools.build.lib.exec.SpawnStrategyRegistry;
import com.google.devtools.build.lib.packages.Package.Builder.PackageSettings;
import com.google.devtools.build.lib.packages.PackageLoadingListener;
import com.google.devtools.build.lib.packages.PackageOverheadEstimator;
import com.google.devtools.build.lib.packages.PackageValidator;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.io.OutErr;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.OutputService;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParsingResult;
import com.google.devtools.common.options.OptionsProvider;
import java.util.UUID;
import javax.annotation.Nullable;
/**
* A module Bazel can load at the beginning of its execution. Modules are supplied with extension
* points to augment the functionality at specific, well-defined places.
*
* <p>The constructors of individual Bazel modules should be empty. All work should be done in the
* methods (e.g. {@link #blazeStartup}).
*/
public abstract class BlazeModule {
/**
* Returns the extra startup options this module contributes.
*
* <p>This method will be called at the beginning of Blaze startup (before {@link #globalInit}).
* The startup options need to be parsed very early in the process, which requires this to be
* separate from {@link #serverInit}.
*/
public Iterable<Class<? extends OptionsBase>> getStartupOptions() {
return ImmutableList.of();
}
/**
* Called at the beginning of Bazel startup, before {@link #getFileSystem} and {@link
* #blazeStartup}.
*
* @param startupOptions the server's startup options
* @throws AbruptExitException to shut down the server immediately
*/
public void globalInit(OptionsParsingResult startupOptions) throws AbruptExitException {}
/**
* Returns the file system implementation used by Bazel. It is an error if more than one module
* returns a file system. If all return null, the default unix file system is used.
*
* <p>This method will be called at the beginning of Bazel startup (in-between {@link #globalInit}
* and {@link #blazeStartup}).
*
* @param startupOptions the server's startup options
* @param realExecRootBase absolute path fragment of the actual, underlying execution root
*/
public ModuleFileSystem getFileSystem(
OptionsParsingResult startupOptions, PathFragment realExecRootBase)
throws AbruptExitException {
return null;
}
@Nullable
public FileSystem getFileSystemForBuildArtifacts(FileSystem fileSystem) {
return null;
}
/** Tuple returned by {@link #getFileSystem}. */
@AutoValue
public abstract static class ModuleFileSystem {
public abstract FileSystem fileSystem();
/** Non-null if this filesystem virtualizes the execroot folder. */
@Nullable
abstract Path virtualExecRootBase();
public static ModuleFileSystem create(
FileSystem fileSystem, @Nullable Path virtualExecRootBase) {
return new AutoValue_BlazeModule_ModuleFileSystem(fileSystem, virtualExecRootBase);
}
public static ModuleFileSystem create(FileSystem fileSystem) {
return create(fileSystem, /*virtualExecRootBase=*/ null);
}
}
/**
* Returns handler for {@link com.google.common.eventbus.EventBus} subscriber and async thread
* exceptions. For async thread exceptions, {@link
* SubscriberExceptionHandler#handleException(Throwable,
* com.google.common.eventbus.SubscriberExceptionContext)} will be called with null {@link
* com.google.common.eventbus.SubscriberExceptionContext}. If all modules return null, a handler
* that crashes on all async exceptions and files bug reports for all EventBus subscriber
* exceptions will be used.
*/
public SubscriberExceptionHandler getEventBusAndAsyncExceptionHandler() {
return null;
}
/**
* Called when Bazel starts up after {@link #getStartupOptions}, {@link #globalInit}, and {@link
* #getFileSystem}.
*
* @param startupOptions the server's startup options
* @param versionInfo the Bazel version currently running
* @param instanceId the id of the current Bazel server
* @param directories the install directory
* @throws AbruptExitException to shut down the server immediately
*/
public void blazeStartup(
OptionsParsingResult startupOptions,
BlazeVersionInfo versionInfo,
UUID instanceId,
FileSystem fileSystem,
ServerDirectories directories,
Clock clock)
throws AbruptExitException {}
/**
* Called to initialize a new server ({@link BlazeRuntime}). Modules can override this method to
* affect how the server is configured. This is called after the startup options have been
* collected and parsed, and after the file system was setup.
*
* @param startupOptions the server startup options
* @param builder builder class that collects the server configuration
* @throws AbruptExitException to shut down the server immediately
*/
public void serverInit(OptionsParsingResult startupOptions, ServerBuilder builder)
throws AbruptExitException {}
/**
* Sets up the configured rule class provider, which contains the built-in rule classes, aspects,
* configuration fragments, and other things; called during Blaze startup (after {@link
* #blazeStartup}).
*
* <p>Bazel only creates one provider per server, so it is not possible to have different contents
* for different workspaces.
*
* @param builder the configured rule class provider builder
*/
public void initializeRuleClasses(ConfiguredRuleClassProvider.Builder builder) {}
/**
* Called when Bazel initializes a new workspace; this is only called after {@link #serverInit},
* and only if the server initialization was successful. Modules can override this method to
* affect how the workspace is configured.
*
* @param runtime the blaze runtime
* @param directories the workspace directories
* @param builder the workspace builder
*/
public void workspaceInit(
BlazeRuntime runtime, BlazeDirectories directories, WorkspaceBuilder builder) {}
/**
* Called to notify modules that the given command is about to be executed. This allows capturing
* the {@link com.google.common.eventbus.EventBus}, {@link Command}, or {@link
* OptionsParsingResult}.
*
* @param env the command
* @throws AbruptExitException modules can throw this exception to abort the command
*/
public void beforeCommand(CommandEnvironment env) throws AbruptExitException {}
/**
* Returns additional listeners to the console output stream. Called at the beginning of each
* command (after #beforeCommand).
*/
@SuppressWarnings("unused")
@Nullable
public OutErr getOutputListener() {
return null;
}
/**
* Returns the output service to be used. It is an error if more than one module returns an output
* service.
*
* <p>This method will be called at the beginning of each command (after #beforeCommand).
*/
@SuppressWarnings("unused")
public OutputService getOutputService() throws AbruptExitException {
return null;
}
/**
* Returns extra options this module contributes to a specific command. Note that option
* inheritance applies: if this method returns a non-empty list, then the returned options are
* added to every command that depends on this command.
*
* <p>This method may be called at any time, and the returned value may be cached. Implementations
* must be thread-safe and never return different lists for the same command object. Typical
* implementations look like this:
*
* <pre>
* return "build".equals(command.name())
* ? ImmutableList.<Class<? extends OptionsBase>>of(MyOptions.class)
* : ImmutableList.<Class<? extends OptionsBase>>of();
* </pre>
*
* Note that this example adds options to all commands that inherit from the build command.
*
* <p>This method is also used to generate command-line documentation; in order to avoid
* duplicated options descriptions, this method should never return the same options class for two
* different commands if one of them inherits the other.
*
* <p>If you want to add options to all commands, override {@link #getCommonCommandOptions}
* instead.
*
* @param command the command
*/
public Iterable<Class<? extends OptionsBase>> getCommandOptions(Command command) {
return ImmutableList.of();
}
/** Returns extra options this module contributes to all commands. */
public Iterable<Class<? extends OptionsBase>> getCommonCommandOptions() {
return ImmutableList.of();
}
/**
* Called after Bazel analyzes the build's top-level targets. This is called once per build if
* --analyze is enabled. Modules can override this to perform extra checks on analysis results.
*
* @param env the command environment
* @param request the build request
* @param buildOptions the build's top-level options
* @param analysisResult the build's analysis result
*/
public void afterAnalysis(
CommandEnvironment env,
BuildRequest request,
BuildOptions buildOptions,
AnalysisResult analysisResult)
throws InterruptedException, ViewCreationFailedException {}
/**
* Called when Bazel initializes the action execution subsystem. This is called once per build if
* action execution is enabled. Modules can override this method to affect how execution is
* performed.
*
* @param env the command environment
* @param request the build request
* @param builder the builder to add action context providers and consumers to
*/
public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder)
throws AbruptExitException {}
/**
* Registers any action contexts this module provides with the execution phase. They will be
* available for {@linkplain
* com.google.devtools.build.lib.actions.ActionContext.ActionContextRegistry#getContext querying}
* to actions and other action contexts.
*
* <p>This method is invoked before actions are executed but after {@link #executorInit}.
*
* @param registryBuilder builder with which to register action contexts
* @param env environment for the current command
* @param buildRequest the current build request
* @throws AbruptExitException if there are fatal issues creating or registering action contexts
*/
public void registerActionContexts(
ModuleActionContextRegistry.Builder registryBuilder,
CommandEnvironment env,
BuildRequest buildRequest)
throws AbruptExitException {}
/**
* Registers any spawn strategies this module provides with the execution phase.
*
* <p>This method is invoked before actions are executed but after {@link #executorInit}.
*
* @param registryBuilder builder with which to register strategies
* @param env environment for the current command
* @throws AbruptExitException if there are fatal issues creating or registering strategies
*/
public void registerSpawnStrategies(
SpawnStrategyRegistry.Builder registryBuilder, CommandEnvironment env)
throws AbruptExitException, InterruptedException {}
/**
* Called after each command.
*
* @throws AbruptExitException modules can throw this exception to modify the command exit code
*/
public void afterCommand() throws AbruptExitException {}
/**
* Called after {@link #afterCommand()}. This method can be used to close and cleanup resources
* specific to the command.
*
* <p>This method must not throw any exceptions, report any errors or generate any stdout/stderr.
* Any of the above will make Bazel crash occasionally. Please use {@link #afterCommand()}
* instead.
*/
public void commandComplete() {}
/**
* Called when Blaze shuts down.
*
* <p>If you are also implementing {@link #blazeShutdownOnCrash}, consider putting the common
* shutdown code in the latter and calling that other hook from here.
*/
public void blazeShutdown() {}
/**
* Called when Blaze shuts down due to a crash.
*
* <p>Modules may use this to flush pending state, but they must be careful to only do a minimal
* number of things. Keep in mind that we are crashing so who knows what state we are in. Modules
* rarely need to implement this.
*/
public void blazeShutdownOnCrash(DetailedExitCode exitCode) {}
/**
* Returns true if the module will arrange for a {@code BuildMetricsEvent} to be posted after the
* build completes.
*
* <p>The Blaze runtime ensures that it has exactly one module for which this method returns true,
* substituting its own module if none is supplied explicitly.
*
* <p>It is an error if multiple modules return true.
*/
public boolean postsBuildMetricsEvent() {
return false;
}
/**
* Returns a {@link QueryRuntimeHelper.Factory} that will be used by the query, cquery, and aquery
* commands.
*
* <p>It is an error if multiple modules return non-null values.
*/
public QueryRuntimeHelper.Factory getQueryRuntimeHelperFactory() {
return null;
}
/**
* Returns {@link PackageSettings} for creating packages.
*
* <p>Called once during server startup some time after {@link #serverInit}.
*
* <p>Note that only one helper per Bazel/Blaze runtime is allowed.
*/
@Nullable
public PackageSettings getPackageSettings() {
return null;
}
/**
* Returns a {@link PackageValidator} to be used to validate loaded packages, or null if the
* module does not provide any validator.
*
* <p>Called once during server startup some time after {@link #serverInit}.
*
* <p>Note that only one instance per Bazel/Blaze runtime is allowed.
*/
@Nullable
public PackageValidator getPackageValidator() {
return null;
}
/**
* Returns a {@link PackageOverheadEstimator} to be used to estimate the cost of loaded packages,
* or null if the module does not provide any such functionality.
*
* <p>Called once during server startup some time after {@link #serverInit}.
*
* <p>Note that only one instance per Bazel/Blaze runtime is allowed
*/
@Nullable
public PackageOverheadEstimator getPackageOverheadEstimator() {
return null;
}
/**
* Returns a {@link PackageLoadingListener} for observing successful package loading, or null if
* the module does not provide any validator.
*
* <p>Called once during server startup some time after {@link #serverInit}.
*/
@Nullable
public PackageLoadingListener getPackageLoadingListener(
PackageSettings packageSettings,
ConfiguredRuleClassProvider ruleClassProvider,
FileSystem fs) {
return null;
}
@Nullable
public String getSlowThreadInterruptMessageSuffix() {
return null;
}
/**
* Optionally returns a provider for project files that can be used to bundle targets and
* command-line options.
*/
@Nullable
public ProjectFile.Provider createProjectFileProvider() {
return null;
}
/**
* Optionally returns a factory to create coverage report actions; this is called once per build,
* such that it can be affected by command options.
*
* <p>It is an error if multiple modules return non-null values.
*
* @param commandOptions the options for the current command
*/
@Nullable
public CoverageReportActionFactory getCoverageReportFactory(OptionsProvider commandOptions) {
return null;
}
/** Services provided for Blaze modules via BlazeRuntime. */
public interface ModuleEnvironment {
/**
* Gets a file from the depot based on its label and returns the {@link Path} where it can be
* found.
*
* <p>Returns null when the package designated by the label does not exist.
*/
@Nullable
Path getFileFromWorkspace(Label label);
/** Exits Blaze as early as possible by sending an interrupt to the command's main thread. */
void exit(AbruptExitException exception);
}
/**
* Provides additional precomputed values to inject into the skyframe graph. Called on every
* command execution.
*/
public ImmutableList<PrecomputedValue.Injected> getPrecomputedValues() {
return ImmutableList.of();
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}