// 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.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.ActionContextConsumer; import com.google.devtools.build.lib.actions.ActionContextProvider; import com.google.devtools.build.lib.actions.ActionInputFileCache; 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.WorkspaceStatusAction; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.exec.OutputService; import com.google.devtools.build.lib.packages.AttributeContainer; 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.Preprocessor; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.query2.AbstractBlazeQueryEnvironment; import com.google.devtools.build.lib.query2.QueryEnvironmentFactory; import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction; import com.google.devtools.build.lib.query2.output.OutputFormatter; import com.google.devtools.build.lib.rules.test.CoverageReportActionFactory; import com.google.devtools.build.lib.runtime.commands.InfoItem; import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy; import com.google.devtools.build.lib.skyframe.DiffAwareness; import com.google.devtools.build.lib.skyframe.PrecomputedValue.Injected; import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker; import com.google.devtools.build.lib.skyframe.SkyframeExecutor; import com.google.devtools.build.lib.skyframe.SkyframeExecutorFactory; import com.google.devtools.build.lib.util.AbruptExitException; import com.google.devtools.build.lib.util.Clock; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.common.options.OptionsBase; import com.google.devtools.common.options.OptionsProvider; import java.io.IOException; import java.util.Map; import java.util.UUID; import javax.annotation.Nullable; /** * A module Blaze 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 Blaze 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 #blazeStartup). */ public Iterable> getStartupOptions() { return ImmutableList.of(); } /** * Called before {@link #getFileSystem} and {@link #blazeStartup}. * *

This method will be called at the beginning of Blaze startup. */ @SuppressWarnings("unused") public void globalInit(OptionsProvider startupOptions) throws AbruptExitException { } /** * Returns the file system implementation used by Blaze. 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 Blaze startup (in-between #globalInit and * #blazeStartup). */ @SuppressWarnings("unused") public FileSystem getFileSystem(OptionsProvider startupOptions, PathFragment outputPath) { return null; } /** * Called when Blaze starts up. */ @SuppressWarnings("unused") public void blazeStartup(OptionsProvider startupOptions, BlazeVersionInfo versionInfo, UUID instanceId, BlazeDirectories directories, Clock clock) throws AbruptExitException { } /** * May yield a supplier that provides factories for the Preprocessor to apply. Only one of the * configured modules may return non-null. * *

The factory yielded by the supplier will be checked with * {@link Preprocessor.Factory#isStillValid} at the beginning of each incremental build. This * allows modules to have preprocessors customizable by flags. * *

This method will be called during Blaze startup (after #blazeStartup). */ public Preprocessor.Factory.Supplier getPreprocessorFactorySupplier() { return null; } /** * Adds the rule classes supported by this module. * *

This method will be called during Blaze startup (after #blazeStartup). */ @SuppressWarnings("unused") public void initializeRuleClasses(ConfiguredRuleClassProvider.Builder builder) { } /** * Returns the list of commands this module contributes to Blaze. * *

This method will be called during Blaze startup (after #blazeStartup). */ public Iterable getCommands() { return ImmutableList.of(); } /** * Returns the list of query output formatters this module provides. * *

This method will be called during Blaze startup (after #blazeStartup). */ public Iterable getQueryOutputFormatters() { return ImmutableList.of(); } /** * Returns the {@link DiffAwareness} strategies this module contributes. These will be used to * determine which files, if any, changed between Blaze commands. * *

This method will be called during Blaze startup (after #blazeStartup). */ @SuppressWarnings("unused") public Iterable getDiffAwarenessFactories(boolean watchFS) { return ImmutableList.of(); } /** * Returns the workspace status action factory contributed by this module. * *

There should always be exactly one of these in a Blaze instance. */ public WorkspaceStatusAction.Factory getWorkspaceStatusActionFactory() { return null; } /** * PlatformSet is a group of platforms characterized by a regular expression. For example, the * entry "oldlinux": "i[34]86-libc[345]-linux" might define a set of platforms representing * certain older linux releases. * *

Platform-set names are used in BUILD files in the third argument to vardef, to * define per-platform tweaks to variables such as CFLAGS. * *

vardef is a legacy mechanism: it needs explicit support in the rule implementations, * and cannot express conditional dependencies, only conditional attribute values. This * mechanism will be supplanted by configuration dependent attributes, and its effect can * usually also be achieved with select(). * *

This method will be called during Blaze startup (after #blazeStartup). */ public Map getPlatformSetRegexps() { return ImmutableMap.of(); } public Iterable getCustomDirtinessCheckers() { return ImmutableList.of(); } @Nullable protected Function getAttributeContainerSupplier() { 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. This is currently a hack and should only be called in * event handlers for {@code BuildStartingEvent}, {@code GotOptionsEvent} and * {@code LoadingPhaseCompleteEvent}. */ void exit(AbruptExitException exception); } /** * Called before each command. */ @SuppressWarnings("unused") public void beforeCommand(Command command, CommandEnvironment env) throws AbruptExitException { } /** * 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; } /** * Does any handling of options needed by the command. * *

This method will be called at the beginning of each command (after #beforeCommand). */ @SuppressWarnings("unused") public void handleOptions(OptionsProvider optionsProvider) { } /** * 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 a map of option categories to descriptive strings. This is used by {@code HelpCommand} * to show a more readable list of flags. */ public Map getOptionCategories() { return ImmutableMap.of(); } /** * Returns the additional information this module provides to "blaze info". * *

This method will be called at the beginning of each "blaze info" command (after * #beforeCommand). */ public Iterable getInfoItems() { return ImmutableList.of(); } /** * Returns the list of query functions this module provides to "blaze query". * *

This method will be called at the beginning of each "blaze query" command (after * #beforeCommand). */ public Iterable getQueryFunctions() { return ImmutableList.of(); } /** * Returns the action context providers the module contributes to Blaze, if any. * *

This method will be called at the beginning of the execution phase, e.g. of the * "blaze build" command. */ public Iterable getActionContextProviders() { return ImmutableList.of(); } /** * Returns the action context consumers that pulls in action contexts required by this module, * if any. * *

This method will be called at the beginning of the execution phase, e.g. of the * "blaze build" command. */ public Iterable getActionContextConsumers() { return ImmutableList.of(); } /** * Called after each command. */ public void afterCommand() { } /** * Called when Blaze shuts down. */ public void blazeShutdown() { } /** * Action inputs are allowed to be missing for all inputs where this predicate returns true. */ public Predicate getAllowedMissingInputs() { return null; } /** * Perform module specific check of current command environment. */ public void checkEnvironment(CommandEnvironment env) { } /** * Optionally specializes the cache that ensures source files are looked at just once during * a build. Only one module may do so. */ public ActionInputFileCache createActionInputCache(String cwd, FileSystem fs) { return null; } /** * Returns the extensions this module contributes to the global namespace of the BUILD language. */ public PackageFactory.EnvironmentExtension getPackageEnvironmentExtension() { return new PackageFactory.EmptyEnvironmentExtension(); } /** * 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, FileSystem fs) { return null; } /** * Returns a factory for creating {@link AbstractBlazeQueryEnvironment} objects. * If the module does not provide any {@link QueryEnvironmentFactory}, it should return null. Note * that only one factory per Bazel/Blaze runtime is allowed. */ public QueryEnvironmentFactory getQueryEnvironmentFactory() { return null; } /** * Returns a factory for creating {@link SkyframeExecutor} objects. If the module does not * provide any SkyframeExecutorFactory, it returns null. Note that only one factory per * Bazel/Blaze runtime is allowed. * * @param directories the workspace directories */ public SkyframeExecutorFactory getSkyframeExecutorFactory(BlazeDirectories directories) { return null; } /** Returns a map of "extra" SkyFunctions for SkyValues that this module may want to build. */ public ImmutableMap getSkyFunctions(BlazeDirectories directories) { return ImmutableMap.of(); } /** * Returns the extra precomputed values that the module makes available in Skyframe. * *

This method is called once per Blaze instance at the very beginning of its life. * If it creates the injected values by using a {@code com.google.common.base.Supplier}, * that supplier is asked for the value it contains just before the loading phase begins. This * functionality can be used to implement precomputed values that are not constant during the * lifetime of a Blaze instance (naturally, they must be constant over the course of a build) * *

The following things must be done in order to define a new precomputed values: *

*/ public Iterable getPrecomputedSkyframeValues() { return ImmutableList.of(); } /** * 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. */ @Nullable public CoverageReportActionFactory getCoverageReportFactory() { return null; } /** * Optionally returns the invocation policy to override options in blaze. */ @Nullable public InvocationPolicy getInvocationPolicy() { return null; } }