// 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.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.ExecutorInitException; 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.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.packages.NoSuchThingException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.PackageFactory; import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.skyframe.PrecomputedValue; import com.google.devtools.build.lib.util.AbruptExitException; 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.common.options.OptionsBase; import com.google.devtools.common.options.OptionsClassProvider; import com.google.devtools.common.options.OptionsProvider; import java.io.IOException; 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. * *

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. * *

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> 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(OptionsProvider 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. * *

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 */ public FileSystem getFileSystem(OptionsProvider startupOptions) throws AbruptExitException { 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 fileSystem * @param directories the install directory * @param clock the clock * @throws AbruptExitException to shut down the server immediately */ public void blazeStartup( OptionsProvider 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(OptionsProvider 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}). * *

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 OptionsProvider}. * * @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. * *

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. * *

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: * *

   * return "build".equals(command.name())
   *     ? ImmutableList.>of(MyOptions.class)
   *     : ImmutableList.>of();
   * 
* * Note that this example adds options to all commands that inherit from the build command. * *

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. * *

If you want to add options to all commands, override {@link #getCommonCommandOptions} * instead. * * @param command the command */ public Iterable> getCommandOptions(Command command) { return ImmutableList.of(); } /** * Returns extra options this module contributes to all commands. */ public Iterable> getCommonCommandOptions() { return ImmutableList.of(); } /** * Returns an instance of BuildOptions to be used to create {@link * BuildOptions.OptionsDiffForReconstruction} with. Only one installed Module should override * this. */ public BuildOptions getDefaultBuildOptions(BlazeRuntime runtime) { return null; } /** * 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 ExecutorInitException {} /** * Called after each command. */ public void afterCommand() { } /** * Called when Blaze shuts down. * *

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. * *

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() {} /** * Returns a helper that the {@link PackageFactory} will use during package loading. If the module * does not provide any helper, it should return null. Note that only one helper per Bazel/Blaze * runtime is allowed. */ public Package.Builder.Helper getPackageBuilderHelper(RuleClassProvider ruleClassProvider) { 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. * *

It is an error if multiple modules return non-null values. * * @param commandOptions the options for the current command */ @Nullable public CoverageReportActionFactory getCoverageReportFactory(OptionsClassProvider 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. */ Path getFileFromWorkspace(Label label) throws NoSuchThingException, InterruptedException, IOException; /** * Exits Blaze as early as possible by sending an interrupt to the command's main thread. */ void exit(AbruptExitException exception); } public ImmutableList getPrecomputedValues() { return ImmutableList.of(); } @Override public String toString() { return this.getClass().getSimpleName(); } }