diff options
author | 2018-01-18 10:29:11 -0800 | |
---|---|---|
committer | 2018-01-18 10:31:11 -0800 | |
commit | 4c9fafd8e7137ed117529e0a72ed4d9aefe6ec48 (patch) | |
tree | 323f9f1ba9aba622847f2da082f273b9c8e09ebf /src/main | |
parent | 4dce09cdc7914d76401a6f77fd78e0176d173dd1 (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')
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 |