| // 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.actions; | |
| import com.google.common.annotations.VisibleForTesting; | |
| import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; | |
| import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; | |
| import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; | |
| import com.google.devtools.build.lib.util.Preconditions; | |
| import com.google.devtools.build.lib.vfs.Path; | |
| import com.google.devtools.build.lib.vfs.PathFragment; | |
| import java.io.Serializable; | |
| import java.util.Objects; | |
| import javax.annotation.Nullable; | |
| /** | |
| * A root for an artifact. The roots are the directories containing artifacts, and they are mapped | |
| * together into a single directory tree to form the execution environment. There are two kinds of | |
| * roots, source roots and derived roots. Source roots correspond to entries of the package path, | |
| * and they can be anywhere on disk. Derived roots correspond to output directories; there are | |
| * generally different output directories for different configurations, and different types of | |
| * output (bin, genfiles, includes, etc.). | |
| * | |
| * <p>When mapping the roots into a single directory tree, the source roots are merged, such that | |
| * each package is accessed in its entirety from a single source root. The package cache is | |
| * responsible for determining that mapping. The derived roots, on the other hand, have to be | |
| * distinct. (It is currently allowed to have a derived root that is the prefix of another one.) | |
| * | |
| * <p>The derived roots must have paths that point inside the exec root, i.e. below the directory | |
| * that is the root of the merged directory tree. | |
| */ | |
| @SkylarkModule(name = "root", | |
| category = SkylarkModuleCategory.BUILTIN, | |
| doc = "A root for files. The roots are the directories containing files, and they are mapped " | |
| + "together into a single directory tree to form the execution environment.") | |
| public final class Root implements Comparable<Root>, Serializable { | |
| /** | |
| * Returns the given path as a source root. The path may not be {@code null}. | |
| */ | |
| // TODO(kchodorow): remove once roots don't need to know if they're in the main repo. | |
| public static Root asSourceRoot(Path path, boolean isMainRepo) { | |
| return new Root(null, path, false, isMainRepo); | |
| } | |
| /** | |
| * testonly until {@link #asSourceRoot(Path, boolean)} is deleted. | |
| */ | |
| public static Root asSourceRoot(Path path) { | |
| return asSourceRoot(path, true); | |
| } | |
| /** | |
| * DO NOT USE IN PRODUCTION CODE! | |
| * | |
| * <p>Returns the given path as a derived root. This method only exists as a convenience for | |
| * tests, which don't need a proper Root object. | |
| */ | |
| @VisibleForTesting | |
| public static Root asDerivedRoot(Path path) { | |
| return new Root(path, path, true); | |
| } | |
| /** | |
| * Returns the given path as a derived root, relative to the given exec root. The root must be a | |
| * proper sub-directory of the exec root (i.e. not equal). Neither may be {@code null}. | |
| * | |
| * <p>Be careful with this method - all derived roots must be registered with the artifact factory | |
| * before the analysis phase. | |
| */ | |
| // TODO(kchodorow): remove once roots don't need to know if they're in the main repo. | |
| public static Root asDerivedRoot(Path execRoot, Path root, boolean isMainRepo) { | |
| Preconditions.checkArgument(root.startsWith(execRoot)); | |
| Preconditions.checkArgument(!root.equals(execRoot)); | |
| return new Root(execRoot, root, false, isMainRepo); | |
| } | |
| /** | |
| * testonly until {@link #asDerivedRoot(Path, Path, boolean)} is deleted. | |
| */ | |
| public static Root asDerivedRoot(Path execRoot, Path root) { | |
| return Root.asDerivedRoot(execRoot, root, true); | |
| } | |
| // TODO(kchodorow): remove once roots don't need to know if they're in the main repo. | |
| public static Root middlemanRoot(Path execRoot, Path outputDir, boolean isMainRepo) { | |
| Path root = outputDir.getRelative("internal"); | |
| Preconditions.checkArgument(root.startsWith(execRoot)); | |
| Preconditions.checkArgument(!root.equals(execRoot)); | |
| return new Root(execRoot, root, true, isMainRepo); | |
| } | |
| /** | |
| * testonly until {@link #middlemanRoot(Path, Path, boolean)} is deleted. | |
| */ | |
| public static Root middlemanRoot(Path execRoot, Path outputDir) { | |
| return Root.middlemanRoot(execRoot, outputDir, true); | |
| } | |
| /** | |
| * Returns the exec root as a derived root. The exec root should never be treated as a derived | |
| * root, but this is currently allowed. Do not add any further uses besides the ones that already | |
| * exist! | |
| */ | |
| // TODO(kchodorow): remove isMainRepo once roots don't need to know if they're in the main repo. | |
| static Root execRootAsDerivedRoot(Path execRoot, boolean isMainRepo) { | |
| return new Root(execRoot, execRoot, false, isMainRepo); | |
| } | |
| @Nullable private final Path execRoot; | |
| private final Path path; | |
| private final boolean isMiddlemanRoot; | |
| private final boolean isMainRepo; | |
| private final PathFragment execPath; | |
| private Root(@Nullable Path execRoot, Path path, boolean isMiddlemanRoot, boolean isMainRepo) { | |
| this.execRoot = execRoot; | |
| this.path = Preconditions.checkNotNull(path); | |
| this.isMiddlemanRoot = isMiddlemanRoot; | |
| this.isMainRepo = isMainRepo; | |
| this.execPath = isSourceRoot() ? PathFragment.EMPTY_FRAGMENT : path.relativeTo(execRoot); | |
| } | |
| private Root(@Nullable Path execRoot, Path path, boolean isMainRepo) { | |
| this(execRoot, path, false, isMainRepo); | |
| } | |
| public Path getPath() { | |
| return path; | |
| } | |
| /** | |
| * Returns the path fragment from the exec root to the actual root. For source roots, this returns | |
| * the empty fragment. | |
| */ | |
| public PathFragment getExecPath() { | |
| return execPath; | |
| } | |
| @SkylarkCallable(name = "path", structField = true, | |
| doc = "Returns the relative path from the exec root to the actual root.") | |
| public String getExecPathString() { | |
| return getExecPath().getPathString(); | |
| } | |
| @Nullable | |
| public Path getExecRoot() { | |
| return execRoot; | |
| } | |
| public boolean isSourceRoot() { | |
| return execRoot == null; | |
| } | |
| boolean isMiddlemanRoot() { | |
| return isMiddlemanRoot; | |
| } | |
| public boolean isMainRepo() { | |
| return isMainRepo; | |
| } | |
| @Override | |
| public int compareTo(Root o) { | |
| return path.compareTo(o.path); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return Objects.hash(execRoot, path.hashCode()); | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (o == this) { | |
| return true; | |
| } | |
| if (!(o instanceof Root)) { | |
| return false; | |
| } | |
| Root r = (Root) o; | |
| return path.equals(r.path) && Objects.equals(execRoot, r.execRoot); | |
| } | |
| @Override | |
| public String toString() { | |
| return path + (isSourceRoot() ? "[source]" : "[derived]"); | |
| } | |
| } |