Replace path implementation.
Path and PathFragment have been replaced with String-based implementations. They are pretty similar, but each method is dissimilar enough that I did not feel sharing code was appropriate.
A summary of changes:
PATH
====
* Subsumes LocalPath (deleted, its tests repurposed)
* Use a simple string to back Path
* Path instances are no longer interned; Reference equality will no longer work
* Always normalized (same as before)
* Some operations will now be slower, like instance compares (which were previously just a reference check)
* Multiple identical paths will now consume more memory since they are not interned
PATH FRAGMENT
=============
* Use a simple string to back PathFragment
* No more segment arrays with interned strings
* Always normalized
* Remove isNormalized
* Replace some isNormalizied uses with containsUpLevelReferences() to check if path fragments try to escape their scope
* To check if user input is normalized, supply static methods on PathFragment to validate the string before constructing a PathFragment
* Because PathFragments are always normalized, we have to replace checks for literal "." from PathFragment#getPathString to PathFragment#getSafePathString. The latter returns "." for the empty string.
* The previous implementation supported efficient segment semantics (segment count, iterating over segments). This is now expensive since we do longer have a segment array.
ARTIFACT
========
* Remove Path instance. It is instead dynamically constructed on request. This is necessary to avoid this CL becoming a memory regression.
RELNOTES: None
PiperOrigin-RevId: 185062932
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 aaaacd9..38da81c 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
@@ -23,7 +23,6 @@
import com.google.common.io.CharStreams;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.vfs.Dirent.Type;
-import com.google.devtools.build.lib.vfs.Path.PathFactory;
import com.google.devtools.common.options.EnumConverter;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -84,25 +83,6 @@
return digestFunction;
}
- private enum UnixPathFactory implements PathFactory {
- INSTANCE {
- @Override
- public Path createRootPath(FileSystem filesystem) {
- return new Path(filesystem, PathFragment.ROOT_DIR, null);
- }
-
- @Override
- public Path createChildPath(Path parent, String childName) {
- return new Path(parent.getFileSystem(), childName, parent);
- }
-
- @Override
- public Path getCachedChildPathInternal(Path path, String childName) {
- return Path.getCachedChildPathInternal(path, childName, /*cacheable=*/ true);
- }
- };
- }
-
/**
* An exception thrown when attempting to resolve an ordinary file as a symlink.
*/
@@ -112,53 +92,23 @@
}
}
- /** Lazy-initialized on first access, always use {@link FileSystem#getRootDirectory} */
- private volatile Path rootPath;
-
private final Root absoluteRoot = new Root.AbsoluteRoot(this);
- /** Returns filesystem-specific path factory. */
- protected PathFactory getPathFactory() {
- return UnixPathFactory.INSTANCE;
+ /**
+ * Returns an absolute path instance, given an absolute path name, without double slashes, .., or
+ * . segments. While this method will normalize the path representation by creating a
+ * structured/parsed representation, it will not cause any IO. (e.g., it will not resolve symbolic
+ * links if it's a Unix file system.
+ */
+ public Path getPath(String path) {
+ return Path.create(path, this);
}
- /**
- * Returns an absolute path instance, given an absolute path name, without
- * double slashes, .., or . segments. While this method will normalize the
- * path representation by creating a structured/parsed representation, it will
- * not cause any IO. (e.g., it will not resolve symbolic links if it's a Unix
- * file system.
- */
- public Path getPath(String pathName) {
- return getPath(PathFragment.create(pathName));
- }
-
- /**
- * Returns an absolute path instance, given an absolute path name, without
- * double slashes, .., or . segments. While this method will normalize the
- * path representation by creating a structured/parsed representation, it will
- * not cause any IO. (e.g., it will not resolve symbolic links if it's a Unix
- * file system.
- */
- public Path getPath(PathFragment pathName) {
- if (!pathName.isAbsolute()) {
- throw new IllegalArgumentException(pathName.getPathString() + " (not an absolute path)");
- }
- return getRootDirectory().getRelative(pathName);
- }
-
- /**
- * Returns a path representing the root directory of the current file system.
- */
- public final Path getRootDirectory() {
- if (rootPath == null) {
- synchronized (this) {
- if (rootPath == null) {
- rootPath = getPathFactory().createRootPath(this);
- }
- }
- }
- return rootPath;
+ /** Returns an absolute path instance, given an absolute path fragment. */
+ public Path getPath(PathFragment pathFragment) {
+ Preconditions.checkArgument(pathFragment.isAbsolute());
+ return Path.createAlreadyNormalized(
+ pathFragment.getPathString(), pathFragment.getDriveStrLength(), this);
}
final Root getAbsoluteRoot() {
@@ -401,7 +351,7 @@
throw new IOException(naive + " (Too many levels of symbolic links)");
}
if (linkTarget.isAbsolute()) {
- dir = getRootDirectory();
+ dir = getPath(linkTarget.getDriveStr());
}
for (String name : linkTarget.segments()) {
if (name.equals(".") || name.isEmpty()) {