From e8d9c4cb9b7ce0a41cde67622997a86be876ede9 Mon Sep 17 00:00:00 2001 From: Ulf Adams Date: Tue, 5 Jul 2016 08:13:41 +0000 Subject: Rewrite workspace creation to use a builder class. An instance of the builder is passed to all modules, which can each add / set things on the builder. This reduces the BlazeModule API surface, while also being more flexible for future changes. -- MOS_MIGRATED_REVID=126613981 --- .../build/lib/bazel/BazelDiffAwarenessModule.java | 10 +- .../build/lib/bazel/BazelRepositoryModule.java | 23 +-- .../lib/bazel/BazelWorkspaceStatusModule.java | 6 +- .../build/lib/bazel/rules/BazelRulesModule.java | 14 +- .../devtools/build/lib/runtime/BlazeModule.java | 95 +-------- .../devtools/build/lib/runtime/BlazeRuntime.java | 112 +---------- .../build/lib/runtime/WorkspaceBuilder.java | 215 +++++++++++++++++++++ 7 files changed, 244 insertions(+), 231 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java (limited to 'src/main/java/com/google/devtools') diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelDiffAwarenessModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelDiffAwarenessModule.java index aabf86c440..4140a7d5e7 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/BazelDiffAwarenessModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelDiffAwarenessModule.java @@ -14,7 +14,9 @@ package com.google.devtools.build.lib.bazel; import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.runtime.BlazeModule; +import com.google.devtools.build.lib.runtime.WorkspaceBuilder; import com.google.devtools.build.lib.skyframe.DiffAwareness; import com.google.devtools.build.lib.skyframe.LocalDiffAwareness; @@ -23,11 +25,9 @@ import com.google.devtools.build.lib.skyframe.LocalDiffAwareness; */ public class BazelDiffAwarenessModule extends BlazeModule { @Override - public Iterable getDiffAwarenessFactories(boolean watchFS) { - ImmutableList.Builder builder = ImmutableList.builder(); - if (watchFS) { - builder.add(new LocalDiffAwareness.Factory(ImmutableList.of())); + public void workspaceInit(BlazeDirectories directories, WorkspaceBuilder builder) { + if (builder.enableWatchFs()) { + builder.addDiffAwarenessFactory(new LocalDiffAwareness.Factory(ImmutableList.of())); } - return builder.build(); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java index 3c51885c60..12c4bd208e 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java @@ -56,12 +56,11 @@ import com.google.devtools.build.lib.runtime.BlazeCommand; import com.google.devtools.build.lib.runtime.BlazeModule; import com.google.devtools.build.lib.runtime.Command; import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.runtime.WorkspaceBuilder; import com.google.devtools.build.lib.skyframe.SkyFunctions; import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker; import com.google.devtools.build.lib.util.AbruptExitException; import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; -import com.google.devtools.build.skyframe.SkyFunction; -import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import com.google.devtools.common.options.OptionsProvider; @@ -133,8 +132,12 @@ public class BazelRepositoryModule extends BlazeModule { }; @Override - public Iterable getCustomDirtinessCheckers() { - return ImmutableList.of(REPOSITORY_VALUE_CHECKER); + public void workspaceInit(BlazeDirectories directories, WorkspaceBuilder builder) { + builder.addCustomDirtinessChecker(REPOSITORY_VALUE_CHECKER); + // Create the repository function everything flows through. + builder.addSkyFunction(SkyFunctions.REPOSITORY, new RepositoryLoaderFunction()); + builder.addSkyFunction(SkyFunctions.REPOSITORY_DIRECTORY, delegator); + builder.addSkyFunction(MavenServerFunction.NAME, new MavenServerFunction()); } @Override @@ -163,18 +166,6 @@ public class BazelRepositoryModule extends BlazeModule { isFetch.set(pkgOptions != null && pkgOptions.fetch); } - @Override - public ImmutableMap getSkyFunctions(BlazeDirectories directories) { - ImmutableMap.Builder builder = ImmutableMap.builder(); - - // Create the repository function everything flows through. - builder.put(SkyFunctions.REPOSITORY, new RepositoryLoaderFunction()); - - builder.put(SkyFunctions.REPOSITORY_DIRECTORY, delegator); - builder.put(MavenServerFunction.NAME, new MavenServerFunction()); - return builder.build(); - } - @Override public void beforeCommand(Command command, CommandEnvironment env) throws AbruptExitException { delegator.setClientEnvironment(env.getClientEnv()); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelWorkspaceStatusModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelWorkspaceStatusModule.java index 4704497d4f..894a27c1d4 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/BazelWorkspaceStatusModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelWorkspaceStatusModule.java @@ -32,6 +32,7 @@ import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.ResourceSet; import com.google.devtools.build.lib.actions.Root; import com.google.devtools.build.lib.actions.SimpleActionContextProvider; +import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.BuildInfo; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction.Key; @@ -41,6 +42,7 @@ import com.google.devtools.build.lib.runtime.BlazeModule; import com.google.devtools.build.lib.runtime.Command; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.runtime.GotOptionsEvent; +import com.google.devtools.build.lib.runtime.WorkspaceBuilder; import com.google.devtools.build.lib.shell.CommandException; import com.google.devtools.build.lib.shell.CommandResult; import com.google.devtools.build.lib.util.CommandBuilder; @@ -286,7 +288,7 @@ public class BazelWorkspaceStatusModule extends BlazeModule { } @Override - public WorkspaceStatusAction.Factory getWorkspaceStatusActionFactory() { - return new BazelStatusActionFactory(); + public void workspaceInit(BlazeDirectories directories, WorkspaceBuilder builder) { + builder.setWorkspaceStatusActionFactory(new BazelStatusActionFactory()); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java index e5fb01ad7c..a169f0c5a0 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java @@ -40,10 +40,9 @@ import com.google.devtools.build.lib.runtime.BlazeModule; import com.google.devtools.build.lib.runtime.Command; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.runtime.GotOptionsEvent; +import com.google.devtools.build.lib.runtime.WorkspaceBuilder; import com.google.devtools.build.lib.skyframe.PrecomputedValue; import com.google.devtools.build.lib.util.ResourceFileLoader; -import com.google.devtools.build.skyframe.SkyFunction; -import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.common.options.Converters.AssignmentConverter; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionsBase; @@ -190,8 +189,9 @@ public class BazelRulesModule extends BlazeModule { } @Override - public Iterable getPrecomputedSkyframeValues() { - return ImmutableList.of(PrecomputedValue.injected( + public void workspaceInit(BlazeDirectories directories, WorkspaceBuilder builder) { + builder.addSkyFunction(FdoSupportValue.SKYFUNCTION, new FdoSupportFunction()); + builder.addPrecomputedValue(PrecomputedValue.injected( GenQuery.QUERY_OUTPUT_FORMATTERS, new Supplier>() { @Override @@ -200,10 +200,4 @@ public class BazelRulesModule extends BlazeModule { } })); } - - @Override - public ImmutableMap getSkyFunctions(BlazeDirectories directories) { - return ImmutableMap.of( - FdoSupportValue.SKYFUNCTION, new FdoSupportFunction()); - } } diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java index 79d0c935c8..03580b2c3a 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java @@ -14,7 +14,6 @@ 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; @@ -23,14 +22,12 @@ 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; @@ -40,18 +37,11 @@ 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; @@ -110,17 +100,10 @@ public abstract class BlazeModule { } /** - * 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). + * Called when Blaze initializes a new workspace. */ - public Preprocessor.Factory.Supplier getPreprocessorFactorySupplier() { - return null; + @SuppressWarnings("unused") + public void workspaceInit(BlazeDirectories directories, WorkspaceBuilder builder) { } /** @@ -150,26 +133,6 @@ public abstract class BlazeModule { 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 @@ -189,10 +152,6 @@ public abstract class BlazeModule { return ImmutableMap.of(); } - public Iterable getCustomDirtinessCheckers() { - return ImmutableList.of(); - } - @Nullable protected Function getAttributeContainerSupplier() { return null; @@ -340,13 +299,6 @@ public abstract class BlazeModule { 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. */ @@ -387,47 +339,6 @@ public abstract class BlazeModule { 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: - *

    - *
  • Create a public static final variable of type - * {@link com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed} - *
  • Set its value by adding an {@link Injected} in this method (it can be created using the - * aforementioned variable and the value or a supplier of the value) - *
  • Reference the value in Skyframe functions by calling get {@code get} method on the - * {@link com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed} variable. This - * will never return null, because its value will have been injected before most of the Skyframe - * values are computed. - *
- */ - public Iterable getPrecomputedSkyframeValues() { - return ImmutableList.of(); - } - /** * Optionally returns a provider for project files that can be used to bundle targets and * command-line options. diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java index f95aecd3e3..ec7c7a0a6c 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java @@ -16,7 +16,6 @@ package com.google.devtools.build.lib.runtime; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; -import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -30,7 +29,6 @@ import com.google.common.util.concurrent.Uninterruptibles; 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.analysis.config.BinTools; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.ConfigurationFactory; @@ -40,7 +38,6 @@ import com.google.devtools.build.lib.flags.CommandNameCache; import com.google.devtools.build.lib.packages.AttributeContainer; 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.profiler.AutoProfiler; @@ -74,12 +71,6 @@ import com.google.devtools.build.lib.server.signal.InterruptSignalHandler; import com.google.devtools.build.lib.shell.JavaSubprocessFactory; import com.google.devtools.build.lib.shell.Subprocess; import com.google.devtools.build.lib.shell.SubprocessBuilder; -import com.google.devtools.build.lib.skyframe.DiffAwareness; -import com.google.devtools.build.lib.skyframe.PrecomputedValue; -import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutorFactory; -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.BlazeClock; import com.google.devtools.build.lib.util.Clock; @@ -97,8 +88,6 @@ import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.UnixFileSystem; import com.google.devtools.build.lib.vfs.WindowsFileSystem; import com.google.devtools.build.lib.windows.WindowsSubprocessFactory; -import com.google.devtools.build.skyframe.SkyFunction; -import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionPriority; import com.google.devtools.common.options.OptionsBase; @@ -218,103 +207,14 @@ public final class BlazeRuntime { public void initWorkspace(BlazeDirectories directories, BinTools binTools) throws AbruptExitException { - SkyframeExecutorFactory skyframeExecutorFactory = null; + boolean watchFS = startupOptionsProvider != null + && startupOptionsProvider.getOptions(BlazeServerStartupOptions.class).watchFS; + WorkspaceBuilder builder = new WorkspaceBuilder(directories, binTools, watchFS); for (BlazeModule module : blazeModules) { - SkyframeExecutorFactory skyFactory = module.getSkyframeExecutorFactory(directories); - if (skyFactory != null) { - Preconditions.checkState(skyframeExecutorFactory == null, - "At most one Skyframe factory supported. But found two: %s and %s", skyFactory, - skyframeExecutorFactory); - skyframeExecutorFactory = skyFactory; - } - } - if (skyframeExecutorFactory == null) { - skyframeExecutorFactory = new SequencedSkyframeExecutorFactory(); - } - - WorkspaceStatusAction.Factory workspaceStatusActionFactory = null; - for (BlazeModule module : blazeModules) { - WorkspaceStatusAction.Factory candidate = module.getWorkspaceStatusActionFactory(); - if (candidate != null) { - Preconditions.checkState(workspaceStatusActionFactory == null, - "more than one module defines a workspace status action factory"); - workspaceStatusActionFactory = candidate; - } - } - - Iterable diffAwarenessFactories; - { - ImmutableList.Builder builder = new ImmutableList.Builder<>(); - boolean watchFS = startupOptionsProvider != null - && startupOptionsProvider.getOptions(BlazeServerStartupOptions.class).watchFS; - for (BlazeModule module : blazeModules) { - builder.addAll(module.getDiffAwarenessFactories(watchFS)); - } - diffAwarenessFactories = builder.build(); - } - - // Merge filters from Blaze modules that allow some action inputs to be missing. - Predicate allowedMissingInputs = null; - for (BlazeModule module : blazeModules) { - Predicate modulePredicate = module.getAllowedMissingInputs(); - if (modulePredicate != null) { - Preconditions.checkArgument(allowedMissingInputs == null, - "More than one Blaze module allows missing inputs."); - allowedMissingInputs = modulePredicate; - } - } - if (allowedMissingInputs == null) { - allowedMissingInputs = Predicates.alwaysFalse(); + module.workspaceInit(directories, builder); } - - Preprocessor.Factory.Supplier preprocessorFactorySupplier = null; - for (BlazeModule module : blazeModules) { - Preprocessor.Factory.Supplier modulePreprocessorFactorySupplier = - module.getPreprocessorFactorySupplier(); - if (modulePreprocessorFactorySupplier != null) { - Preconditions.checkState(preprocessorFactorySupplier == null, - "more than one module defines a preprocessor factory supplier"); - preprocessorFactorySupplier = modulePreprocessorFactorySupplier; - } - } - if (preprocessorFactorySupplier == null) { - preprocessorFactorySupplier = Preprocessor.Factory.Supplier.NullSupplier.INSTANCE; - } - - // We use an immutable map builder for the nice side effect that it throws if a duplicate key - // is inserted. - ImmutableMap.Builder skyFunctions = ImmutableMap.builder(); - for (BlazeModule module : blazeModules) { - skyFunctions.putAll(module.getSkyFunctions(directories)); - } - - ImmutableList.Builder precomputedValues = ImmutableList.builder(); - for (BlazeModule module : blazeModules) { - precomputedValues.addAll(module.getPrecomputedSkyframeValues()); - } - - ImmutableList.Builder customDirtinessCheckers = - ImmutableList.builder(); - for (BlazeModule module : blazeModules) { - customDirtinessCheckers.addAll(module.getCustomDirtinessCheckers()); - } - - SkyframeExecutor skyframeExecutor = skyframeExecutorFactory.create( - packageFactory, - directories, - binTools, - workspaceStatusActionFactory, - ruleClassProvider.getBuildInfoFactories(), - diffAwarenessFactories, - allowedMissingInputs, - preprocessorFactorySupplier, - skyFunctions.build(), - precomputedValues.build(), - customDirtinessCheckers.build(), - getProductName()); - this.workspace = new BlazeWorkspace( - this, directories, skyframeExecutor, eventBusExceptionHandler, workspaceStatusActionFactory, - binTools); + this.workspace = builder.build( + this, packageFactory, ruleClassProvider, getProductName(), eventBusExceptionHandler); } @Nullable public CoverageReportActionFactory getCoverageReportActionFactory() { diff --git a/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java b/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java new file mode 100644 index 0000000000..d7f0bfd2f2 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java @@ -0,0 +1,215 @@ +// Copyright 2016 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.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.eventbus.SubscriberExceptionHandler; +import com.google.devtools.build.lib.analysis.BlazeDirectories; +import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; +import com.google.devtools.build.lib.analysis.WorkspaceStatusAction; +import com.google.devtools.build.lib.analysis.config.BinTools; +import com.google.devtools.build.lib.packages.PackageFactory; +import com.google.devtools.build.lib.packages.Preprocessor; +import com.google.devtools.build.lib.skyframe.DiffAwareness; +import com.google.devtools.build.lib.skyframe.PrecomputedValue; +import com.google.devtools.build.lib.skyframe.PrecomputedValue.Injected; +import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutorFactory; +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.Preconditions; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyFunctionName; + +import java.util.Map; + +/** + * Builder class to create a {@link BlazeWorkspace} instance. This class is part of the module API, + * which allows modules to affect how the workspace is initialized. + */ +public final class WorkspaceBuilder { + private final BlazeDirectories directories; + private final BinTools binTools; + private final boolean watchFs; + + private SkyframeExecutorFactory skyframeExecutorFactory; + private WorkspaceStatusAction.Factory workspaceStatusActionFactory; + private final ImmutableList.Builder diffAwarenessFactories = + ImmutableList.builder(); + private Predicate allowedMissingInputs; + private Preprocessor.Factory.Supplier preprocessorFactorySupplier; + // We use an immutable map builder for the nice side effect that it throws if a duplicate key + // is inserted. + private final ImmutableMap.Builder skyFunctions = + ImmutableMap.builder(); + private final ImmutableList.Builder precomputedValues = + ImmutableList.builder(); + private final ImmutableList.Builder customDirtinessCheckers = + ImmutableList.builder(); + + WorkspaceBuilder(BlazeDirectories directories, BinTools binTools, boolean watchFs) { + this.directories = directories; + this.binTools = binTools; + this.watchFs = watchFs; + } + + BlazeWorkspace build( + BlazeRuntime runtime, + PackageFactory packageFactory, + ConfiguredRuleClassProvider ruleClassProvider, + String productName, + SubscriberExceptionHandler eventBusExceptionHandler) throws AbruptExitException { + // Set default values if none are set. + if (skyframeExecutorFactory == null) { + skyframeExecutorFactory = new SequencedSkyframeExecutorFactory(); + } + if (allowedMissingInputs == null) { + allowedMissingInputs = Predicates.alwaysFalse(); + } + if (preprocessorFactorySupplier == null) { + preprocessorFactorySupplier = Preprocessor.Factory.Supplier.NullSupplier.INSTANCE; + } + + SkyframeExecutor skyframeExecutor = skyframeExecutorFactory.create( + packageFactory, + directories, + binTools, + workspaceStatusActionFactory, + ruleClassProvider.getBuildInfoFactories(), + diffAwarenessFactories.build(), + allowedMissingInputs, + preprocessorFactorySupplier, + skyFunctions.build(), + precomputedValues.build(), + customDirtinessCheckers.build(), + productName); + return new BlazeWorkspace( + runtime, directories, skyframeExecutor, eventBusExceptionHandler, + workspaceStatusActionFactory, binTools); + } + + public boolean enableWatchFs() { + return watchFs; + } + + /** + * Sets a factory for creating {@link SkyframeExecutor} objects. Note that only one factory per + * workspace is allowed. + */ + public WorkspaceBuilder setSkyframeExecutorFactory( + SkyframeExecutorFactory skyframeExecutorFactory) { + Preconditions.checkState(this.skyframeExecutorFactory == null, + "At most one Skyframe factory supported. But found two: %s and %s", + this.skyframeExecutorFactory, skyframeExecutorFactory); + this.skyframeExecutorFactory = Preconditions.checkNotNull(skyframeExecutorFactory); + return this; + } + + /** + * Sets the workspace status action factory contributed by this module. Only one factory per + * workspace is allowed. + */ + public WorkspaceBuilder setWorkspaceStatusActionFactory( + WorkspaceStatusAction.Factory workspaceStatusActionFactory) { + Preconditions.checkState(this.workspaceStatusActionFactory == null, + "At most one workspace status action factory supported. But found two: %s and %s", + this.workspaceStatusActionFactory, workspaceStatusActionFactory); + this.workspaceStatusActionFactory = Preconditions.checkNotNull(workspaceStatusActionFactory); + return this; + } + + /** + * Add a {@link DiffAwareness} factory. These will be used to determine which files, if any, + * changed between Blaze commands. + */ + public WorkspaceBuilder addDiffAwarenessFactory(DiffAwareness.Factory factory) { + this.diffAwarenessFactories.add(Preconditions.checkNotNull(factory)); + return this; + } + + /** + * Action inputs are allowed to be missing for all inputs where this predicate returns true. Only + * one predicate may be set per workspace. + */ + public WorkspaceBuilder setAllowedMissingInputs(Predicate allowedMissingInputs) { + Preconditions.checkArgument(this.allowedMissingInputs == null, + "At most one module may set allowed missing inputs. But found two: %s and %s", + this.allowedMissingInputs, allowedMissingInputs); + this.allowedMissingInputs = Preconditions.checkNotNull(allowedMissingInputs); + return this; + } + + /** + * Sets a supplier that provides factories for the Preprocessor to apply. Only one factory per + * workspace is allowed. + * + *

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. + */ + public WorkspaceBuilder setPreprocessorFactorySupplier( + Preprocessor.Factory.Supplier preprocessorFactorySupplier) { + Preconditions.checkState(this.preprocessorFactorySupplier == null, + "At most one module defines a preprocessor factory supplier. But found two: %s and %s", + this.preprocessorFactorySupplier, preprocessorFactorySupplier); + this.preprocessorFactorySupplier = Preconditions.checkNotNull(preprocessorFactorySupplier); + return this; + } + + /** Add an "extra" SkyFunction for SkyValues. */ + public WorkspaceBuilder addSkyFunction(SkyFunctionName name, SkyFunction skyFunction) { + Preconditions.checkNotNull(name); + Preconditions.checkNotNull(skyFunction); + this.skyFunctions.put(name, skyFunction); + return this; + } + + /** Add "extra" SkyFunctions for SkyValues. */ + public WorkspaceBuilder addSkyFunctions(Map skyFunctions) { + this.skyFunctions.putAll(Preconditions.checkNotNull(skyFunctions)); + return this; + } + + /** + * Adds an extra precomputed value to Skyframe. + * + *

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

    + *
  • Create a public static final variable of type + * {@link com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed}. + *
  • Set its value by adding an {@link Injected} via this method (it can be created using the + * aforementioned variable and the value or a supplier of the value). + *
  • Reference the value in Skyframe functions by calling the {@code get} method on the + * {@link com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed} variable. + *
+ */ + public WorkspaceBuilder addPrecomputedValue(PrecomputedValue.Injected precomputedValue) { + this.precomputedValues.add(Preconditions.checkNotNull(precomputedValue)); + return this; + } + + public WorkspaceBuilder addCustomDirtinessChecker( + SkyValueDirtinessChecker customDirtinessChecker) { + this.customDirtinessCheckers.add(Preconditions.checkNotNull(customDirtinessChecker)); + return this; + } +} \ No newline at end of file -- cgit v1.2.3