aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
new file mode 100644
index 0000000000..3fe6dbaa7f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
@@ -0,0 +1,134 @@
+// Copyright 2014 Google Inc. 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.skyframe;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.vfs.Dirent;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.util.Objects;
+
+/**
+ * A value that represents the list of files in a given directory under a given package path root.
+ * Anything in Skyframe that cares about the contents of a directory should have a dependency
+ * on the corresponding {@link DirectoryListingValue}.
+ *
+ * <p>This value only depends on the FileValue corresponding to the directory. In particular, note
+ * that it does not depend on any of its child entries.
+ *
+ * <p>Note that symlinks in dirents are <b>not</b> expanded. Dependents of the value are responsible
+ * for expanding the symlink entries by referring to FileValues that correspond to the symlinks.
+ * This is a little onerous, but correct: we do not need to reread the directory when a symlink
+ * inside it changes, therefore this value should not be invalidated in that case.
+ */
+@Immutable
+@ThreadSafe
+abstract class DirectoryListingValue implements SkyValue {
+
+ /**
+ * Returns the directory entries for this directory, in a stable order.
+ *
+ * <p>Symlinks are not expanded.
+ */
+ public abstract Iterable<Dirent> getDirents();
+
+ /**
+ * Returns a {@link SkyKey} for getting the directory entries of the given directory. The
+ * given path is assumed to be an existing directory (e.g. via {@link FileValue#isDirectory} or
+ * from a directory listing on its parent directory).
+ */
+ @ThreadSafe
+ static SkyKey key(RootedPath directoryUnderRoot) {
+ return new SkyKey(SkyFunctions.DIRECTORY_LISTING, directoryUnderRoot);
+ }
+
+ static DirectoryListingValue value(RootedPath dirRootedPath, FileValue dirFileValue,
+ DirectoryListingStateValue realDirectoryListingStateValue) {
+ return dirFileValue.realRootedPath().equals(dirRootedPath)
+ ? new RegularDirectoryListingValue(realDirectoryListingStateValue)
+ : new DifferentRealPathDirectoryListingValue(dirFileValue.realRootedPath(),
+ realDirectoryListingStateValue);
+ }
+
+ @ThreadSafe
+ private static final class RegularDirectoryListingValue extends DirectoryListingValue {
+
+ private final DirectoryListingStateValue directoryListingStateValue;
+
+ private RegularDirectoryListingValue(DirectoryListingStateValue directoryListingStateValue) {
+ this.directoryListingStateValue = directoryListingStateValue;
+ }
+
+ @Override
+ public Iterable<Dirent> getDirents() {
+ return directoryListingStateValue.getDirents();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof RegularDirectoryListingValue)) {
+ return false;
+ }
+ RegularDirectoryListingValue other = (RegularDirectoryListingValue) obj;
+ return directoryListingStateValue.equals(other.directoryListingStateValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return directoryListingStateValue.hashCode();
+ }
+ }
+
+ @ThreadSafe
+ private static final class DifferentRealPathDirectoryListingValue extends DirectoryListingValue {
+
+ private final RootedPath realDirRootedPath;
+ private final DirectoryListingStateValue directoryListingStateValue;
+
+ private DifferentRealPathDirectoryListingValue(RootedPath realDirRootedPath,
+ DirectoryListingStateValue directoryListingStateValue) {
+ this.realDirRootedPath = realDirRootedPath;
+ this.directoryListingStateValue = directoryListingStateValue;
+ }
+
+ @Override
+ public Iterable<Dirent> getDirents() {
+ return directoryListingStateValue.getDirents();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof DifferentRealPathDirectoryListingValue)) {
+ return false;
+ }
+ DifferentRealPathDirectoryListingValue other = (DifferentRealPathDirectoryListingValue) obj;
+ return realDirRootedPath.equals(other.realDirRootedPath)
+ && directoryListingStateValue.equals(other.directoryListingStateValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(realDirRootedPath, directoryListingStateValue);
+ }
+ }
+}