aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ulf Adams <ulfjack@google.com>2016-08-09 11:46:00 +0000
committerGravatar Yue Gan <yueg@google.com>2016-08-09 13:45:43 +0000
commit15a23b96750d423d1b403a45ae58804e88d0acfc (patch)
treeed32749df1da81469e9dbb26cb9266dba3f43b32
parentb9610d6a0154ca94255d76b8056d1286d8f89458 (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
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/BlazeDirectories.java78
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ServerDirectories.java98
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java20
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcherRcoptionsTest.java8
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))