aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar tomlu <tomlu@google.com>2018-01-18 10:29:11 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-01-18 10:31:11 -0800
commit4c9fafd8e7137ed117529e0a72ed4d9aefe6ec48 (patch)
tree323f9f1ba9aba622847f2da082f273b9c8e09ebf /src/main
parent4dce09cdc7914d76401a6f77fd78e0176d173dd1 (diff)
Add absolute root concept.
An absolute root accepts any absolute path fragments and simply returns it. This concept replaces the FileSystem root directory concept. PiperOrigin-RevId: 182400471
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/Artifact.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/ArtifactFactory.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java13
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/Root.java160
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/RootedPath.java15
8 files changed, 163 insertions, 45 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 82594e7d0e..72d26371ab 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -194,7 +194,9 @@ public class Artifact
throw new IllegalArgumentException(root + ": illegal root for " + path
+ " (execPath: " + execPath + ")");
}
- if (execPath == null || execPath.isAbsolute() || !path.asFragment().endsWith(execPath)) {
+ if (execPath == null
+ || execPath.isAbsolute() != root.getRoot().isAbsolute()
+ || !path.asFragment().endsWith(execPath)) {
throw new IllegalArgumentException(execPath + ": illegal execPath for " + path
+ " (root: " + root + ")");
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ArtifactFactory.java b/src/main/java/com/google/devtools/build/lib/actions/ArtifactFactory.java
index c6330d0808..5342a5db2b 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ArtifactFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ArtifactFactory.java
@@ -146,7 +146,8 @@ public class ArtifactFactory implements ArtifactResolver {
@Override
public Artifact getSourceArtifact(PathFragment execPath, ArtifactRoot root, ArtifactOwner owner) {
- Preconditions.checkArgument(!execPath.isAbsolute(), "%s %s %s", execPath, root, owner);
+ Preconditions.checkArgument(
+ execPath.isAbsolute() == root.getRoot().isAbsolute(), "%s %s %s", execPath, root, owner);
Preconditions.checkNotNull(owner, "%s %s", execPath, root);
execPath = execPath.normalize();
return getArtifact(root.getRoot().getRelative(execPath), root, execPath, owner, null);
@@ -159,7 +160,8 @@ public class ArtifactFactory implements ArtifactResolver {
private void validatePath(PathFragment rootRelativePath, ArtifactRoot root) {
Preconditions.checkArgument(!root.isSourceRoot());
- Preconditions.checkArgument(!rootRelativePath.isAbsolute(), rootRelativePath);
+ Preconditions.checkArgument(
+ rootRelativePath.isAbsolute() == root.getRoot().isAbsolute(), rootRelativePath);
Preconditions.checkArgument(rootRelativePath.isNormalized(), rootRelativePath);
Preconditions.checkArgument(
root.getRoot().asPath().startsWith(execRootParent), "%s %s", root, execRootParent);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java
index 6ad546cec3..ffde90d9b1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java
@@ -155,7 +155,7 @@ public interface IncludeScanner {
for (Artifact included : includes) {
// Check for absolute includes -- we assign the file system root as
// the root path for such includes
- if (included.getRoot().getRoot().isRootDirectory()) {
+ if (included.getRoot().getRoot().isAbsolute()) {
if (FileSystemUtils.startsWithAny(
included.getPath().asFragment(), absoluteBuiltInIncludeDirs)) {
// Skip include files found in absolute include directories.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
index 9021546d65..bcf15976f0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
@@ -57,7 +57,7 @@ public class NewLocalRepositoryFunction extends RepositoryFunction {
FileSystem fs = directories.getOutputBase().getFileSystem();
Path path = fs.getPath(pathFragment);
- RootedPath dirPath = RootedPath.toRootedPath(Root.fromFileSystemRoot(fs), path);
+ RootedPath dirPath = RootedPath.toRootedPath(Root.absoluteRoot(fs), path);
try {
FileValue dirFileValue =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
index 74980d251f..9cae797a5f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
@@ -120,9 +120,9 @@ public class FileFunction implements SkyFunction {
PathFragment relativePath = rootedPath.getRelativePath();
RootedPath realRootedPath = rootedPath;
FileValue parentFileValue = null;
- if (!relativePath.equals(PathFragment.EMPTY_FRAGMENT)) {
- RootedPath parentRootedPath = RootedPath.toRootedPath(rootedPath.getRoot(),
- relativePath.getParentDirectory());
+ PathFragment parentDirectory = relativePath.getParentDirectory();
+ if (parentDirectory != null) {
+ RootedPath parentRootedPath = RootedPath.toRootedPath(rootedPath.getRoot(), parentDirectory);
parentFileValue = (FileValue) env.getValue(FileValue.key(parentRootedPath));
if (parentFileValue == null) {
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
index a469f20a4d..aaaacd93d2 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
@@ -115,7 +115,7 @@ public abstract class FileSystem {
/** Lazy-initialized on first access, always use {@link FileSystem#getRootDirectory} */
private volatile Path rootPath;
- private volatile Root root;
+ private final Root absoluteRoot = new Root.AbsoluteRoot(this);
/** Returns filesystem-specific path factory. */
protected PathFactory getPathFactory() {
@@ -161,15 +161,8 @@ public abstract class FileSystem {
return rootPath;
}
- final Root getRoot() {
- if (root == null) {
- synchronized (this) {
- if (root == null) {
- root = new Root.PathRoot(getRootDirectory());
- }
- }
- }
- return root;
+ final Root getAbsoluteRoot() {
+ return absoluteRoot;
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Root.java b/src/main/java/com/google/devtools/build/lib/vfs/Root.java
index 41f65de8c9..6446fb1e0e 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/Root.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/Root.java
@@ -13,24 +13,28 @@
// limitations under the License.
package com.google.devtools.build.lib.vfs;
+import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
+import javax.annotation.Nullable;
/**
* A root path used in {@link RootedPath} and in artifact roots.
*
* <p>A typical root could be the exec path, a package root, or an output root specific to some
- * configuration.
+ * configuration. We also support absolute roots for non-hermetic paths outside the user workspace.
*/
public interface Root extends Comparable<Root>, Serializable {
- static ObjectCodec<Root> getCodec(PathCodec pathCodec) {
- return new RootCodec(pathCodec);
+ static ObjectCodec<Root> getCodec(FileSystem fileSystem, PathCodec pathCodec) {
+ return new RootCodec(fileSystem, pathCodec);
}
/** Constructs a root from a path. */
@@ -38,9 +42,9 @@ public interface Root extends Comparable<Root>, Serializable {
return new PathRoot(path);
}
- /** Returns a root from the file system's root directory. */
- static Root fromFileSystemRoot(FileSystem fileSystem) {
- return fileSystem.getRoot();
+ /** Returns an absolute root. Can only be used with absolute path fragments. */
+ static Root absoluteRoot(FileSystem fileSystem) {
+ return fileSystem.getAbsoluteRoot();
}
/** Returns a path by concatenating the root and the root-relative path. */
@@ -52,23 +56,24 @@ public interface Root extends Comparable<Root>, Serializable {
/** Returns the relative path between the root and the given path. */
PathFragment relativize(Path path);
- @Deprecated
- PathFragment relativize(PathFragment relativePath);
+ /** Returns the relative path between the root and the given absolute path fragment. */
+ PathFragment relativize(PathFragment pathFragment);
/** Returns whether the given path is under this root. */
boolean contains(Path path);
- @Deprecated
- boolean contains(PathFragment relativePath);
+ /** Returns whether the given absolute path fragment is under this root. */
+ boolean contains(PathFragment pathFragment);
/**
- * Returns the underlying path. Please avoid using this method. Roots may eventually not be
- * directly backed by paths.
+ * Returns the underlying path. Please avoid using this method.
+ *
+ * <p>Not all roots are backed by paths, so this may return null.
*/
+ @Nullable
Path asPath();
- @Deprecated
- boolean isRootDirectory();
+ boolean isAbsolute();
/** Implementation of Root that is backed by a {@link Path}. */
final class PathRoot implements Root {
@@ -115,8 +120,8 @@ public interface Root extends Comparable<Root>, Serializable {
}
@Override
- public boolean isRootDirectory() {
- return path.isRootDirectory();
+ public boolean isAbsolute() {
+ return false;
}
@Override
@@ -126,7 +131,13 @@ public interface Root extends Comparable<Root>, Serializable {
@Override
public int compareTo(Root o) {
- return path.compareTo(((PathRoot) o).path);
+ if (o instanceof AbsoluteRoot) {
+ return 1;
+ } else if (o instanceof PathRoot) {
+ return path.compareTo(((PathRoot) o).path);
+ } else {
+ throw new AssertionError("Unknown Root subclass: " + o.getClass().getName());
+ }
}
@Override
@@ -147,11 +158,111 @@ public interface Root extends Comparable<Root>, Serializable {
}
}
+ /** An absolute root of a file system. Can only resolve absolute path fragments. */
+ final class AbsoluteRoot implements Root {
+ private FileSystem fileSystem; // Non-final for serialization
+
+ AbsoluteRoot(FileSystem fileSystem) {
+ this.fileSystem = fileSystem;
+ }
+
+ @Override
+ public Path getRelative(PathFragment relativePath) {
+ Preconditions.checkArgument(relativePath.isAbsolute());
+ return fileSystem.getPath(relativePath);
+ }
+
+ @Override
+ public Path getRelative(String relativePath) {
+ return getRelative(PathFragment.create(relativePath));
+ }
+
+ @Override
+ public PathFragment relativize(Path path) {
+ return path.asFragment();
+ }
+
+ @Override
+ public PathFragment relativize(PathFragment pathFragment) {
+ Preconditions.checkArgument(pathFragment.isAbsolute());
+ return pathFragment;
+ }
+
+ @Override
+ public boolean contains(Path path) {
+ return true;
+ }
+
+ @Override
+ public boolean contains(PathFragment pathFragment) {
+ return pathFragment.isAbsolute();
+ }
+
+ @Override
+ public boolean isAbsolute() {
+ return true;
+ }
+
+ @Override
+ public Path asPath() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "<absolute root>";
+ }
+
+ @Override
+ public int compareTo(Root o) {
+ if (o instanceof AbsoluteRoot) {
+ return Integer.compare(fileSystem.hashCode(), ((AbsoluteRoot) o).fileSystem.hashCode());
+ } else if (o instanceof PathRoot) {
+ return -1;
+ } else {
+ throw new AssertionError("Unknown Root subclass: " + o.getClass().getName());
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ AbsoluteRoot that = (AbsoluteRoot) o;
+ return Objects.equal(fileSystem, that.fileSystem);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(fileSystem);
+ }
+
+ @SuppressWarnings("unused")
+ private void readObject(ObjectInputStream in) throws IOException {
+ fileSystem = Path.getFileSystemForSerialization();
+ }
+
+ @SuppressWarnings("unused")
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ Preconditions.checkState(
+ fileSystem == Path.getFileSystemForSerialization(),
+ "%s %s",
+ fileSystem,
+ Path.getFileSystemForSerialization());
+ }
+ }
+
/** Codec to serialize {@link Root}s. */
class RootCodec implements ObjectCodec<Root> {
+ private final FileSystem fileSystem;
private final PathCodec pathCodec;
- private RootCodec(PathCodec pathCodec) {
+ private RootCodec(FileSystem fileSystem, PathCodec pathCodec) {
+ this.fileSystem = fileSystem;
this.pathCodec = pathCodec;
}
@@ -164,7 +275,11 @@ public interface Root extends Comparable<Root>, Serializable {
public void serialize(Root obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
if (obj instanceof PathRoot) {
+ codedOut.writeBoolNoTag(false);
pathCodec.serialize(((PathRoot) obj).path, codedOut);
+ } else if (obj instanceof AbsoluteRoot) {
+ Preconditions.checkArgument(((AbsoluteRoot) obj).fileSystem == fileSystem);
+ codedOut.writeBoolNoTag(true);
} else {
throw new AssertionError("Unknown Root subclass: " + obj.getClass().getName());
}
@@ -172,8 +287,13 @@ public interface Root extends Comparable<Root>, Serializable {
@Override
public Root deserialize(CodedInputStream codedIn) throws SerializationException, IOException {
- Path path = pathCodec.deserialize(codedIn);
- return new PathRoot(path);
+ boolean isAbsolute = codedIn.readBool();
+ if (isAbsolute) {
+ return fileSystem.getAbsoluteRoot();
+ } else {
+ Path path = pathCodec.deserialize(codedIn);
+ return new PathRoot(path);
+ }
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/RootedPath.java b/src/main/java/com/google/devtools/build/lib/vfs/RootedPath.java
index 415e0ac80d..8deca0a95c 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/RootedPath.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/RootedPath.java
@@ -41,7 +41,10 @@ public class RootedPath implements Serializable {
/** Constructs a {@link RootedPath} from a {@link Root} and path fragment relative to the root. */
private RootedPath(Root root, PathFragment relativePath) {
- Preconditions.checkState(!relativePath.isAbsolute(), "relativePath: %s root: %s", relativePath,
+ Preconditions.checkState(
+ relativePath.isAbsolute() == root.isAbsolute(),
+ "relativePath: %s root: %s",
+ relativePath,
root);
this.root = root;
this.relativePath = relativePath.normalize();
@@ -51,10 +54,8 @@ public class RootedPath implements Serializable {
/** Returns a rooted path representing {@code relativePath} relative to {@code root}. */
public static RootedPath toRootedPath(Root root, PathFragment relativePath) {
if (relativePath.isAbsolute()) {
- if (root.isRootDirectory()) {
- return new RootedPath(
- Root.fromPath(root.getRelative(relativePath.windowsVolume())),
- relativePath.toRelative());
+ if (root.isAbsolute()) {
+ return new RootedPath(root, relativePath);
} else {
Preconditions.checkArgument(
root.contains(relativePath),
@@ -84,7 +85,7 @@ public class RootedPath implements Serializable {
return toRootedPath(root, path);
}
}
- return toRootedPath(Root.fromFileSystemRoot(path.getFileSystem()), path);
+ return toRootedPath(Root.absoluteRoot(path.getFileSystem()), path);
}
public Path asPath() {
@@ -135,7 +136,7 @@ public class RootedPath implements Serializable {
/** Create an instance which will deserialize RootedPaths on {@code fileSystem}. */
public RootedPathCodec(FileSystem fileSystem) {
- this.rootCodec = Root.getCodec(new PathCodec(fileSystem));
+ this.rootCodec = Root.getCodec(fileSystem, new PathCodec(fileSystem));
}
@Override