aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/BlazeDirectories.java
blob: 2764375a1b890bf368e6c58fd0d22dd8dd185448 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// 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.analysis;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.devtools.build.lib.Constants;
import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.util.StringCanonicalizer;
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.
 *
 * <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>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
 * workspace directory as its working directory, the client process may have a different working
 * directory, typically a subdirectory.
 *
 * <p>Do not put shortcuts to specific files here!
 */
@Immutable
public final class BlazeDirectories {

  // Output directory name, relative to the execRoot.
  // TODO(bazel-team): (2011) make this private?
  public static final String RELATIVE_OUTPUT_PATH = StringCanonicalizer.intern(
      Constants.PRODUCT_NAME + "-out");

  // Include directory name, relative to execRoot/blaze-out/configuration.
  public static final String RELATIVE_INCLUDE_DIR = StringCanonicalizer.intern("include");
  @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

  // 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, @Nullable Path workspace,
                          @Nullable String installMD5) {
    this.installBase = installBase;
    this.workspace = workspace;
    this.outputBase = outputBase;
    this.installMD5 = installMD5 == null ? null : checkMD5(HashCode.fromString(installMD5));
    boolean useDefaultExecRootName = this.workspace == null || this.workspace.isRootDirectory();
    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.
      this.execRoot = outputBase.getChild(DEFAULT_EXEC_ROOT);
    } else {
      this.execRoot = outputBase.getChild(workspace.getBaseName());
    }
    this.outputPath = execRoot.getRelative(RELATIVE_OUTPUT_PATH);
    Preconditions.checkState(useDefaultExecRootName || outputPath.asFragment().equals(
        outputPathFromOutputBase(outputBase.asFragment(), workspace.asFragment())));

    this.localOutputPath = outputBase.getRelative(BlazeDirectories.RELATIVE_OUTPUT_PATH);
  }

  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(Path installBase, Path outputBase, @Nullable Path workspace) {
    this(installBase, outputBase, workspace, null);
  }

  /**
   * 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 workspace directory, which is also the working dir of the server.
   */
  public Path getWorkspace() {
    return workspace;
  }

  /**
   * Returns if the workspace directory is a valid workspace.
   */
  public boolean inWorkspace() {
    return this.workspace != null;
  }

  /**
   * 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 execution root. This is the directory underneath which Blaze builds the source
   * symlink forest, to represent the merged view of different workspaces specified
   * with --package_path.
   */
  public Path getExecRoot() {
    return execRoot;
  }

  /**
   * Returns the output path used by this Blaze instance.
   */
  public Path getOutputPath() {
    return outputPath;
  }

  /**
   * @param outputBase the outputBase as a path fragment.
   * @param workspace the workspace as a path fragment.
   * @return the outputPath as a path fragment, given the outputBase.
   */
  public static PathFragment outputPathFromOutputBase(
      PathFragment outputBase, PathFragment workspace) {
    if (workspace.equals(PathFragment.EMPTY_FRAGMENT)) {
      return outputBase;
    }
    return outputBase.getRelative(workspace.getBaseName() + "/" + RELATIVE_OUTPUT_PATH);
  }

  /**
   * Returns the local output path used by this Blaze instance.
   */
  public Path getLocalOutputPath() {
    return localOutputPath;
  }

  /**
   * Returns the directory where the stdout/stderr for actions can be stored
   * temporarily for a build. If the directory already exists, the directory
   * is cleaned.
   */
  public Path getActionConsoleOutputDirectory() {
    return getOutputBase().getRelative("action_outs");
  }

  /**
   * Returns the installed embedded binaries directory, under the shared
   * installBase location.
   */
  public Path getEmbeddedBinariesRoot() {
    return installBase.getChild("_embedded_binaries");
  }

  /**
   * Returns the configuration-independent root where the build-data should be placed, given the
   * {@link BlazeDirectories} of this server instance. Nothing else should be placed here.
   */
  public Root getBuildDataDirectory() {
    return Root.asDerivedRoot(getExecRoot(), getOutputPath());
  }

 /**
  * 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;
  }
}