diff options
author | 2016-08-09 11:46:00 +0000 | |
---|---|---|
committer | 2016-08-09 13:45:43 +0000 | |
commit | 15a23b96750d423d1b403a45ae58804e88d0acfc (patch) | |
tree | ed32749df1da81469e9dbb26cb9266dba3f43b32 | |
parent | b9610d6a0154ca94255d76b8056d1286d8f89458 (diff) |
Split BlazeDirectories into two classes.
This is done in preparation for allowing multiple workspaces / commands in a
single server. That requires changes to the module API, which currently
hard-codes a 1:1 correspondence between workspaces and servers. Note how
BlazeDirectories exists even when it runs outside a workspace.
It's not ideal that the output base is in ServerDirectories, and the
BlazeRuntime creation also still requires a BlazeDirectories instance.
--
MOS_MIGRATED_REVID=129736613
5 files changed, 159 insertions, 48 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BlazeDirectories.java b/src/main/java/com/google/devtools/build/lib/analysis/BlazeDirectories.java index 374c9e684c..c7474f2854 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BlazeDirectories.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/BlazeDirectories.java @@ -15,9 +15,7 @@ package com.google.devtools.build.lib.analysis; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Strings; import com.google.common.hash.HashCode; -import com.google.common.hash.Hashing; import com.google.devtools.build.lib.actions.Root; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.util.Preconditions; @@ -26,21 +24,20 @@ 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 javax.annotation.Nullable; - /** - * Encapsulation of all of the interesting top-level directories in any Blaze application. + * Encapsulates the directories related to a workspace. + * + * <p>The <code>workspace</code> is the top-level directory in the user's client (possibly + * read-only). The <code>execRoot</code> is the working directory for all spawned tools, which is + * generally below the <code>outputBase</code>. * - * <p>The <code>installBase</code> is the directory where the Blaze binary has been installed.The - * <code>workspace</code> is the top-level directory in the user's client (possibly read-only).The - * <code>outputBase</code> is the directory below which Blaze puts all its state. The - * <code>execRoot</code> is the working directory for all spawned tools, which is generally below - * <code>outputBase</code>. + * <p>Care must be taken to avoid multiple Bazel instances trying to write to the same output + * directory. At this time, this is enforced by requiring a 1:1 correspondence between a running + * Bazel instance and an output base directory, though this requirement may be softened in the + * future. * - * <p>There is a 1:1 correspondence between a running Blaze instance and an output base directory; - * however, multiple Blaze instances may compile code that's in the same workspace, even on the same - * machine. If the user does not qualify an output base directory, the startup code will derive it - * deterministically from the workspace. Note also that while the Blaze server process runs with the + * <p>If the user does not qualify an output base directory, the startup code will derive it + * deterministically from the workspace. Note also that while the Bazel server process runs with the * workspace directory as its working directory, the client process may have a different working * directory, typically a subdirectory. * @@ -54,27 +51,27 @@ public final class BlazeDirectories { @VisibleForTesting static final String DEFAULT_EXEC_ROOT = "default-exec-root"; - private final Path installBase; // Where Blaze gets unpacked - private final HashCode installMD5; // The content hash of everything in installBase - private final Path workspace; // Workspace root and server CWD - private final Path outputBase; // The root of the temp and output trees - private final Path execRoot; // the root of all build actions + private final ServerDirectories serverDirectories; + /** Workspace root and server CWD. */ + private final Path workspace; + /** The root of all build actions. */ + private final Path execRoot; // These two are kept to avoid creating new objects every time they are accessed. This showed up // in a profiler. private final Path outputPath; private final Path localOutputPath; - public BlazeDirectories(Path installBase, Path outputBase, Path workspace, - boolean deepExecRoot, @Nullable String installMD5, String productName) { - this.installBase = installBase; + public BlazeDirectories( + ServerDirectories serverDirectories, + Path workspace, + boolean deepExecRoot, + String productName) { + this.serverDirectories = serverDirectories; this.workspace = workspace; - this.outputBase = outputBase; - this.installMD5 = - Strings.isNullOrEmpty(installMD5) ? null : checkMD5(HashCode.fromString(installMD5)); boolean useDefaultExecRootName = this.workspace == null || this.workspace.isRootDirectory(); - Path execRootBase = deepExecRoot - ? outputBase.getChild("execroot") : outputBase; + Path outputBase = serverDirectories.getOutputBase(); + Path execRootBase = deepExecRoot ? outputBase.getChild("execroot") : outputBase; if (useDefaultExecRootName) { // TODO(bazel-team): if workspace is null execRoot should be null, but at the moment there is // a lot of code that depends on it being non-null. @@ -91,15 +88,14 @@ public final class BlazeDirectories { this.localOutputPath = outputBase.getRelative(relativeOutputPath); } - private static HashCode checkMD5(HashCode hash) { - Preconditions.checkArgument(hash.bits() == Hashing.md5().bits(), - "Hash '%s' has %s bits", hash, hash.bits()); - return hash; + @VisibleForTesting + public BlazeDirectories(ServerDirectories serverDirectories, Path workspace, String productName) { + this(serverDirectories, workspace, false, productName); } @VisibleForTesting public BlazeDirectories(Path installBase, Path outputBase, Path workspace, String productName) { - this(installBase, outputBase, workspace, false, null, productName); + this(new ServerDirectories(installBase, outputBase), workspace, false, productName); } /** @@ -107,14 +103,19 @@ public final class BlazeDirectories { * resolving absolute paths. */ public FileSystem getFileSystem() { - return installBase.getFileSystem(); + return serverDirectories.getFileSystem(); + } + + public ServerDirectories getServerDirectories() { + return serverDirectories; } /** - * Returns the installation base directory. Currently used by info command only. + * Returns the base of the output tree, which hosts all build and scratch + * output for a user and workspace. */ public Path getInstallBase() { - return installBase; + return serverDirectories.getInstallBase(); } /** @@ -136,7 +137,7 @@ public final class BlazeDirectories { * output for a user and workspace. */ public Path getOutputBase() { - return outputBase; + return serverDirectories.getOutputBase(); } /** @@ -191,7 +192,7 @@ public final class BlazeDirectories { * installBase location. */ public Path getEmbeddedBinariesRoot() { - return installBase.getChild("_embedded_binaries"); + return serverDirectories.getEmbeddedBinariesRoot(); } /** @@ -207,7 +208,7 @@ public final class BlazeDirectories { * anything else that ends up in the install_base). */ public HashCode getInstallMD5() { - return installMD5; + return serverDirectories.getInstallMD5(); } /** @@ -217,5 +218,4 @@ public final class BlazeDirectories { public static String getRelativeOutputPath(String productName) { return StringCanonicalizer.intern(productName + "-out"); } - } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ServerDirectories.java b/src/main/java/com/google/devtools/build/lib/analysis/ServerDirectories.java new file mode 100644 index 0000000000..4c57ae6496 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/ServerDirectories.java @@ -0,0 +1,98 @@ +// 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.analysis; + +import com.google.common.base.Strings; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hashing; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.util.Preconditions; +import com.google.devtools.build.lib.vfs.FileSystem; +import com.google.devtools.build.lib.vfs.Path; + +import javax.annotation.Nullable; + +/** + * Represents the server install directory, which contains the Bazel installation and embedded + * binaries. + * + * <p>The <code>installBase</code> is the directory where the Blaze binary has been installed. The + * <code>outputBase</code> is the directory below which Blaze puts all its state. + */ +@Immutable +public final class ServerDirectories { + /** Where Blaze gets unpacked. */ + private final Path installBase; + /** The content hash of everything in installBase. */ + private final HashCode installMD5; + /** The root of the temp and output trees. */ + private final Path outputBase; + + public ServerDirectories(Path installBase, Path outputBase, @Nullable String installMD5) { + this.installBase = installBase; + this.outputBase = outputBase; + this.installMD5 = + Strings.isNullOrEmpty(installMD5) ? null : checkMD5(HashCode.fromString(installMD5)); + } + + public ServerDirectories(Path installBase, Path outputBase) { + this(installBase, outputBase, null); + } + + private static HashCode checkMD5(HashCode hash) { + Preconditions.checkArgument(hash.bits() == Hashing.md5().bits(), + "Hash '%s' has %s bits", hash, hash.bits()); + return hash; + } + + /** + * Returns the Filesystem that all of our directories belong to. Handy for + * resolving absolute paths. + */ + public FileSystem getFileSystem() { + return installBase.getFileSystem(); + } + + /** + * Returns the installation base directory. Currently used by info command only. + */ + public Path getInstallBase() { + return installBase; + } + + /** + * Returns the base of the output tree, which hosts all build and scratch + * output for a user and workspace. + */ + public Path getOutputBase() { + return outputBase; + } + + /** + * Returns the installed embedded binaries directory, under the shared + * installBase location. + */ + public Path getEmbeddedBinariesRoot() { + return installBase.getChild("_embedded_binaries"); + } + + /** + * Returns the MD5 content hash of the blaze binary (includes deploy JAR, embedded binaries, and + * anything else that ends up in the install_base). + */ + public HashCode getInstallMD5() { + return installMD5; + } +}
\ No newline at end of file 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 9879ab05cf..077cf5c55c 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 @@ -21,6 +21,7 @@ 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.ServerDirectories; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.exec.OutputService; import com.google.devtools.build.lib.packages.NoSuchThingException; @@ -91,7 +92,7 @@ public abstract class BlazeModule { */ @SuppressWarnings("unused") public void blazeStartup(OptionsProvider startupOptions, - BlazeVersionInfo versionInfo, UUID instanceId, BlazeDirectories directories, + BlazeVersionInfo versionInfo, UUID instanceId, ServerDirectories directories, Clock clock) throws AbruptExitException { } 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 f896545fd2..bdc8652973 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 @@ -28,6 +28,7 @@ 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.ServerDirectories; 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; @@ -916,10 +917,11 @@ public final class BlazeRuntime { Predicates.notNull())); } + ServerDirectories serverDirectories = + new ServerDirectories(installBasePath, outputBasePath, startupOptions.installMD5); BlazeDirectories directories = - new BlazeDirectories(installBasePath, outputBasePath, workspaceDirectoryPath, - startupOptions.deepExecRoot, startupOptions.installMD5, - productName); + new BlazeDirectories( + serverDirectories, workspaceDirectoryPath, startupOptions.deepExecRoot, productName); Clock clock = BlazeClock.instance(); @@ -934,6 +936,7 @@ public final class BlazeRuntime { BlazeRuntime.Builder runtimeBuilder = new BlazeRuntime.Builder() .setProductName(productName) + .setServerDirectories(serverDirectories) .setDirectories(directories) .setStartupOptionsProvider(options) .setBinTools(binTools) @@ -1027,6 +1030,7 @@ public final class BlazeRuntime { * an exception. Please plan appropriately. */ public static class Builder { + private ServerDirectories serverDirectories; private BlazeDirectories directories; private Clock clock; private OptionsProvider startupOptionsProvider; @@ -1038,6 +1042,7 @@ public final class BlazeRuntime { public BlazeRuntime build() throws AbruptExitException { Preconditions.checkNotNull(productName); + Preconditions.checkNotNull(serverDirectories); Preconditions.checkNotNull(directories); Preconditions.checkNotNull(startupOptionsProvider); Clock clock = (this.clock == null) ? BlazeClock.instance() : this.clock; @@ -1047,7 +1052,7 @@ public final class BlazeRuntime { for (BlazeModule module : blazeModules) { module.blazeStartup(startupOptionsProvider, - BlazeVersionInfo.instance(), instanceId, directories, clock); + BlazeVersionInfo.instance(), instanceId, serverDirectories, clock); } ServerBuilder serverBuilder = new ServerBuilder(); for (BlazeModule module : blazeModules) { @@ -1070,7 +1075,7 @@ public final class BlazeRuntime { Package.Builder.Helper packageBuilderHelper = null; for (BlazeModule module : blazeModules) { Package.Builder.Helper candidateHelper = - module.getPackageBuilderHelper(ruleClassProvider, directories.getFileSystem()); + module.getPackageBuilderHelper(ruleClassProvider, serverDirectories.getFileSystem()); if (candidateHelper != null) { Preconditions.checkState(packageBuilderHelper == null, "more than one module defines a package builder helper"); @@ -1133,6 +1138,11 @@ public final class BlazeRuntime { return this; } + public Builder setServerDirectories(ServerDirectories serverDirectories) { + this.serverDirectories = serverDirectories; + return this; + } + public Builder setDirectories(BlazeDirectories directories) { this.directories = directories; return this; diff --git a/src/test/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcherRcoptionsTest.java b/src/test/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcherRcoptionsTest.java index dad3d2de0e..eff79d93bf 100644 --- a/src/test/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcherRcoptionsTest.java +++ b/src/test/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcherRcoptionsTest.java @@ -24,6 +24,7 @@ import com.google.common.collect.Lists; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.ConfigurationCollectionFactory; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; +import com.google.devtools.build.lib.analysis.ServerDirectories; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.FragmentOptions; import com.google.devtools.build.lib.cmdline.Label; @@ -128,13 +129,14 @@ public class BlazeCommandDispatcherRcoptionsTest { @Before public final void initializeRuntime() throws Exception { String productName = TestConstants.PRODUCT_NAME; + ServerDirectories serverDirectories = + new ServerDirectories(scratch.dir("install_base"), scratch.dir("output_base")); BlazeDirectories directories = - new BlazeDirectories( - scratch.dir("install_base"), scratch.dir("output_base"), scratch.dir("pkg"), - productName); + new BlazeDirectories(serverDirectories, scratch.dir("pkg"), productName); this.runtime = new BlazeRuntime.Builder() .setProductName(productName) + .setServerDirectories(serverDirectories) .setDirectories(directories) .setStartupOptionsProvider( OptionsParser.newOptionsParser(BlazeServerStartupOptions.class)) |