Automated rollback of commit 006b4972b433bda280e6982d297da6071b84b88d.
*** Reason for rollback ***
Breaks a number of targets in the nightly.
*** Original change description ***
Make Bazel not raise an error when a symlink points to its own ancestor.
This is only an error when the symlink is to be traversed recursively. E.g. `a/a/a/b` is perfectly acceptable if `a/a` is a symlink to `.`, except if we want to recursively traverse into it during a glob or recursive target pattern expansion.
RELNOTES: Blaze now allows symbolic links that point to their own ancestor unless they are traversed recursively by e.g. a //... recursive target pattern or a recursive glob.
PiperOrigin-RevId: 334579512
diff --git a/src/main/java/com/google/devtools/build/lib/actions/FileValue.java b/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
index 55c5ab4..7c2f416 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
@@ -102,18 +102,6 @@
public abstract ImmutableList<RootedPath> logicalChainDuringResolution();
/**
- * If a symlink pointing back to its own ancestor was encountered during the resolution of this
- * {@link FileValue}, returns the path to it. Otherwise, returns null.
- */
- public abstract ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain();
-
- /**
- * If a symlink pointing back to its own ancestor was encountered during the resolution of this
- * {@link FileValue}, returns the symlinks in the cycle. Otherwise, returns null.
- */
- public abstract ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain();
-
- /**
* Returns the real rooted path of the file, taking ancestor symlinks into account. For example,
* the rooted path ['root']/['a/b'] is really ['root']/['c/b'] if 'a' is a symlink to 'c'. Note
* that ancestor symlinks outside the root boundary are not taken into consideration.
@@ -177,8 +165,6 @@
*/
public static FileValue value(
ImmutableList<RootedPath> logicalChainDuringResolution,
- ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain,
- ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain,
RootedPath originalRootedPath,
FileStateValue fileStateValueFromAncestors,
RootedPath realRootedPath,
@@ -219,36 +205,17 @@
if (fileStateValueFromAncestors.getType() == FileStateType.SYMLINK) {
PathFragment symlinkTarget = fileStateValueFromAncestors.getSymlinkTarget();
- if (pathToUnboundedAncestorSymlinkExpansionChain != null) {
- return new SymlinkFileValueWithSymlinkCycle(
- realRootedPath,
- realFileStateValue,
- logicalChainDuringResolution,
- symlinkTarget,
- pathToUnboundedAncestorSymlinkExpansionChain,
- unboundedAncestorSymlinkExpansionChain);
- } else if (shouldStoreChain) {
- return new SymlinkFileValueWithStoredChain(
- realRootedPath, realFileStateValue, logicalChainDuringResolution, symlinkTarget);
- } else {
- return new SymlinkFileValueWithoutStoredChain(
- realRootedPath, realFileStateValue, symlinkTarget);
- }
- } else {
- if (pathToUnboundedAncestorSymlinkExpansionChain != null) {
- return new DifferentRealPathFileValueWithSymlinkCycle(
- realRootedPath,
- realFileStateValue,
- logicalChainDuringResolution,
- pathToUnboundedAncestorSymlinkExpansionChain,
- unboundedAncestorSymlinkExpansionChain);
- } else if (shouldStoreChain) {
- return new DifferentRealPathFileValueWithStoredChain(
- realRootedPath, realFileStateValue, logicalChainDuringResolution);
- } else {
- return new DifferentRealPathFileValueWithoutStoredChain(realRootedPath, realFileStateValue);
- }
+ return shouldStoreChain
+ ? new SymlinkFileValueWithStoredChain(
+ realRootedPath, realFileStateValue, logicalChainDuringResolution, symlinkTarget)
+ : new SymlinkFileValueWithoutStoredChain(
+ realRootedPath, realFileStateValue, symlinkTarget);
}
+
+ return shouldStoreChain
+ ? new DifferentRealPathFileValueWithStoredChain(
+ realRootedPath, realFileStateValue, logicalChainDuringResolution)
+ : new DifferentRealPathFileValueWithoutStoredChain(realRootedPath, realFileStateValue);
}
/**
@@ -274,16 +241,6 @@
}
@Override
- public ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain() {
- return null;
- }
-
- @Override
- public ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain() {
- return null;
- }
-
- @Override
public RootedPath realRootedPath() {
return rootedPath;
}
@@ -317,84 +274,6 @@
}
/**
- * A {@link FileValue} whose resolution required traversing a symlink chain caused by a symlink
- * pointing to its own ancestor but which eventually points to a real file.
- */
- @AutoCodec.VisibleForSerialization
- @AutoCodec
- public static class DifferentRealPathFileValueWithSymlinkCycle
- extends DifferentRealPathFileValueWithStoredChain {
- // We can't store an exception here because this needs to be serialized, AutoCodec chokes on
- // object cycles and FilesystemInfiniteSymlinkCycleException somehow sets its cause to itself
- protected final ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain;
- protected final ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain;
-
- public DifferentRealPathFileValueWithSymlinkCycle(
- RootedPath realRootedPath,
- FileStateValue realFileStateValue,
- ImmutableList<RootedPath> logicalChainDuringResolution,
- ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain,
- ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain) {
- super(realRootedPath, realFileStateValue, logicalChainDuringResolution);
- this.pathToUnboundedAncestorSymlinkExpansionChain =
- pathToUnboundedAncestorSymlinkExpansionChain;
- this.unboundedAncestorSymlinkExpansionChain = unboundedAncestorSymlinkExpansionChain;
- }
-
- @Override
- public ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain() {
- return pathToUnboundedAncestorSymlinkExpansionChain;
- }
-
- @Override
- public ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain() {
- return unboundedAncestorSymlinkExpansionChain;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- realRootedPath,
- realFileStateValue,
- logicalChainDuringResolution,
- pathToUnboundedAncestorSymlinkExpansionChain,
- unboundedAncestorSymlinkExpansionChain);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
-
- if (obj.getClass() != DifferentRealPathFileValueWithSymlinkCycle.class) {
- return false;
- }
-
- DifferentRealPathFileValueWithSymlinkCycle other =
- (DifferentRealPathFileValueWithSymlinkCycle) obj;
- return realRootedPath.equals(other.realRootedPath)
- && realFileStateValue.equals(other.realFileStateValue)
- && logicalChainDuringResolution.equals(other.logicalChainDuringResolution)
- && pathToUnboundedAncestorSymlinkExpansionChain.equals(
- other.pathToUnboundedAncestorSymlinkExpansionChain)
- && unboundedAncestorSymlinkExpansionChain.equals(
- other.unboundedAncestorSymlinkExpansionChain);
- }
-
- @Override
- public String toString() {
- return String.format(
- "symlink ancestor (real_path=%s, real_state=%s, chain=%s, path=%s, cycle=%s)",
- realRootedPath,
- realFileStateValue,
- logicalChainDuringResolution,
- pathToUnboundedAncestorSymlinkExpansionChain,
- unboundedAncestorSymlinkExpansionChain);
- }
- }
-
- /**
* Implementation of {@link FileValue} for paths whose fully resolved path is different than the
* requested path, but the path itself is not a symlink. For example, this is the case for the
* path "foo/bar/baz" if at least one of {'foo', 'foo/bar'} is a symlink but 'foo/bar/baz' not.
@@ -431,16 +310,6 @@
}
@Override
- public ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain() {
- return null;
- }
-
- @Override
- public ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain() {
- return null;
- }
-
- @Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
@@ -501,16 +370,6 @@
}
@Override
- public ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain() {
- return null;
- }
-
- @Override
- public ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain() {
- return null;
- }
-
- @Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
@@ -537,93 +396,12 @@
}
}
- /**
- * A {@link FileValue} whose resolution required traversing a symlink chain caused by a symlink
- * pointing to its own ancestor and which eventually points to a symlink.
- */
- @AutoCodec.VisibleForSerialization
- @AutoCodec
- public static final class SymlinkFileValueWithSymlinkCycle
- extends SymlinkFileValueWithStoredChain {
- // We can't store an exception here because this needs to be serialized, AutoCodec chokes on
- // object cycles and FilesystemInfiniteSymlinkCycleException somehow sets its cause to itself
- private final ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain;
- private final ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain;
-
- public SymlinkFileValueWithSymlinkCycle(
- RootedPath realRootedPath,
- FileStateValue realFileStateValue,
- ImmutableList<RootedPath> logicalChainDuringResolution,
- PathFragment linkTarget,
- ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain,
- ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain) {
- super(realRootedPath, realFileStateValue, logicalChainDuringResolution, linkTarget);
- this.pathToUnboundedAncestorSymlinkExpansionChain =
- pathToUnboundedAncestorSymlinkExpansionChain;
- this.unboundedAncestorSymlinkExpansionChain = unboundedAncestorSymlinkExpansionChain;
- }
-
- @Override
- public ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain() {
- return pathToUnboundedAncestorSymlinkExpansionChain;
- }
-
- @Override
- public ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain() {
- return unboundedAncestorSymlinkExpansionChain;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- realRootedPath,
- realFileStateValue,
- logicalChainDuringResolution,
- linkTarget,
- pathToUnboundedAncestorSymlinkExpansionChain,
- unboundedAncestorSymlinkExpansionChain);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
-
- if (obj.getClass() != SymlinkFileValueWithSymlinkCycle.class) {
- return false;
- }
-
- SymlinkFileValueWithSymlinkCycle other = (SymlinkFileValueWithSymlinkCycle) obj;
- return realRootedPath.equals(other.realRootedPath)
- && realFileStateValue.equals(other.realFileStateValue)
- && logicalChainDuringResolution.equals(other.logicalChainDuringResolution)
- && linkTarget.equals(other.linkTarget)
- && pathToUnboundedAncestorSymlinkExpansionChain.equals(
- other.pathToUnboundedAncestorSymlinkExpansionChain)
- && unboundedAncestorSymlinkExpansionChain.equals(
- other.unboundedAncestorSymlinkExpansionChain);
- }
-
- @Override
- public String toString() {
- return String.format(
- "symlink ancestor (real_path=%s, real_state=%s, target=%s, chain=%s, path=%s, cycle=%s)",
- realRootedPath,
- realFileStateValue,
- linkTarget,
- logicalChainDuringResolution,
- pathToUnboundedAncestorSymlinkExpansionChain,
- unboundedAncestorSymlinkExpansionChain);
- }
- }
-
/** Implementation of {@link FileValue} for paths that are themselves symlinks. */
@AutoCodec.VisibleForSerialization
@AutoCodec
- public static class SymlinkFileValueWithStoredChain
+ public static final class SymlinkFileValueWithStoredChain
extends DifferentRealPathFileValueWithStoredChain {
- protected final PathFragment linkTarget;
+ private final PathFragment linkTarget;
@VisibleForTesting
public SymlinkFileValueWithStoredChain(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index 8062c16..fa674c4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -1057,7 +1057,6 @@
name = "collect_packages_under_directory_function",
srcs = ["CollectPackagesUnderDirectoryFunction.java"],
deps = [
- "process_package_directory",
":collect_packages_under_directory_value",
":recursive_directory_traversal_function",
":recursive_pkg_key",
@@ -1525,8 +1524,6 @@
srcs = ["GlobFunction.java"],
deps = [
":directory_listing_value",
- ":file_symlink_infinite_expansion_exception",
- ":file_symlink_infinite_expansion_uniqueness_function",
":glob_descriptor",
":glob_value",
":ignored_package_prefixes_value",
@@ -2023,8 +2020,6 @@
":directory_listing_value",
":dirents",
":file_symlink_exception",
- ":file_symlink_infinite_expansion_exception",
- ":file_symlink_infinite_expansion_uniqueness_function",
":package_lookup_value",
":process_package_directory_result",
"//src/main/java/com/google/devtools/build/lib/actions:file_metadata",
@@ -2100,8 +2095,6 @@
deps = [
":action_execution_value",
":directory_listing_value",
- ":file_symlink_infinite_expansion_exception",
- ":file_symlink_infinite_expansion_uniqueness_function",
":package_lookup_value",
":sky_functions",
":tree_artifact_value",
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 7e0668a..bae2c18 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
@@ -66,7 +66,11 @@
this.nonexistentFileReceiver = nonexistentFileReceiver;
}
- private static class SymlinkResolutionState {
+ @Override
+ public FileValue compute(SkyKey skyKey, Environment env)
+ throws FileFunctionException, InterruptedException {
+ RootedPath rootedPath = (RootedPath) skyKey.argument();
+
// Suppose we have a path p. One of the goals of FileFunction is to resolve the "real path", if
// any, of p. The basic algorithm is to use the fully resolved path of p's parent directory to
// determine the fully resolved path of p. This is complicated when symlinks are involved, and
@@ -87,18 +91,6 @@
// See the usage in checkPathSeenDuringPartialResolutionInternal.
TreeSet<Path> sortedLogicalChain = Sets.newTreeSet();
- ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain = null;
- ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain = null;
-
- private SymlinkResolutionState() {}
- }
-
- @Override
- public FileValue compute(SkyKey skyKey, Environment env)
- throws FileFunctionException, InterruptedException {
- RootedPath rootedPath = (RootedPath) skyKey.argument();
- SymlinkResolutionState symlinkResolutionState = new SymlinkResolutionState();
-
// Fully resolve the path of the parent directory, but only if the current file is not the
// filesystem root (has no parent) or a package path root (treated opaquely and handled by
// skyframe's DiffAwareness interface).
@@ -107,7 +99,7 @@
// an ancestor is part of a symlink cycle, we want to detect that quickly as it gives a more
// informative error message than we'd get doing bogus filesystem operations.
PartialResolutionResult resolveFromAncestorsResult =
- resolveFromAncestors(rootedPath, symlinkResolutionState, env);
+ resolveFromAncestors(rootedPath, sortedLogicalChain, logicalChain, env);
if (resolveFromAncestorsResult == null) {
return null;
}
@@ -115,9 +107,7 @@
FileStateValue fileStateValueFromAncestors = resolveFromAncestorsResult.fileStateValue;
if (fileStateValueFromAncestors.getType() == FileStateType.NONEXISTENT) {
return FileValue.value(
- ImmutableList.copyOf(symlinkResolutionState.logicalChain),
- symlinkResolutionState.pathToUnboundedAncestorSymlinkExpansionChain,
- symlinkResolutionState.unboundedAncestorSymlinkExpansionChain,
+ ImmutableList.copyOf(logicalChain),
rootedPath,
FileStateValue.NONEXISTENT_FILE_STATE_NODE,
rootedPathFromAncestors,
@@ -130,7 +120,11 @@
while (realFileStateValue.getType().isSymlink()) {
PartialResolutionResult getSymlinkTargetRootedPathResult =
getSymlinkTargetRootedPath(
- realRootedPath, realFileStateValue.getSymlinkTarget(), symlinkResolutionState, env);
+ realRootedPath,
+ realFileStateValue.getSymlinkTarget(),
+ sortedLogicalChain,
+ logicalChain,
+ env);
if (getSymlinkTargetRootedPathResult == null) {
return null;
}
@@ -139,9 +133,7 @@
}
return FileValue.value(
- ImmutableList.copyOf(symlinkResolutionState.logicalChain),
- symlinkResolutionState.pathToUnboundedAncestorSymlinkExpansionChain,
- symlinkResolutionState.unboundedAncestorSymlinkExpansionChain,
+ ImmutableList.copyOf(logicalChain),
rootedPath,
// TODO(b/123922036): This is a bug. Should be 'fileStateValueFromAncestors'.
fileStateValueFromAncestors,
@@ -164,19 +156,24 @@
*/
@Nullable
private PartialResolutionResult resolveFromAncestors(
- RootedPath rootedPath, SymlinkResolutionState symlinkResolutionState, Environment env)
+ RootedPath rootedPath,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
+ Environment env)
throws InterruptedException, FileFunctionException {
RootedPath parentRootedPath = rootedPath.getParentDirectory();
return parentRootedPath != null
- ? resolveFromAncestorsWithParent(rootedPath, parentRootedPath, symlinkResolutionState, env)
- : resolveFromAncestorsNoParent(rootedPath, symlinkResolutionState, env);
+ ? resolveFromAncestorsWithParent(
+ rootedPath, parentRootedPath, sortedLogicalChain, logicalChain, env)
+ : resolveFromAncestorsNoParent(rootedPath, sortedLogicalChain, logicalChain, env);
}
@Nullable
private PartialResolutionResult resolveFromAncestorsWithParent(
RootedPath rootedPath,
RootedPath parentRootedPath,
- SymlinkResolutionState symlinkResolutionState,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
Environment env)
throws InterruptedException, FileFunctionException {
PathFragment relativePath = rootedPath.getRootRelativePath();
@@ -200,7 +197,7 @@
for (RootedPath parentPartialRootedPath : parentFileValue.logicalChainDuringResolution()) {
checkAndNotePathSeenDuringPartialResolution(
- getChild(parentPartialRootedPath, baseName), symlinkResolutionState, env);
+ getChild(parentPartialRootedPath, baseName), sortedLogicalChain, logicalChain, env);
if (env.valuesMissing()) {
return null;
}
@@ -217,9 +214,12 @@
@Nullable
private PartialResolutionResult resolveFromAncestorsNoParent(
- RootedPath rootedPath, SymlinkResolutionState symlinkResolutionState, Environment env)
+ RootedPath rootedPath,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
+ Environment env)
throws InterruptedException, FileFunctionException {
- checkAndNotePathSeenDuringPartialResolution(rootedPath, symlinkResolutionState, env);
+ checkAndNotePathSeenDuringPartialResolution(rootedPath, sortedLogicalChain, logicalChain, env);
if (env.valuesMissing()) {
return null;
}
@@ -249,7 +249,8 @@
private PartialResolutionResult getSymlinkTargetRootedPath(
RootedPath rootedPath,
PathFragment symlinkTarget,
- SymlinkResolutionState symlinkResolutionState,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
Environment env)
throws FileFunctionException, InterruptedException {
Path path = rootedPath.asPath();
@@ -264,35 +265,44 @@
: path.getRelative(symlinkTarget);
}
RootedPath symlinkTargetRootedPath = toRootedPath(symlinkTargetPath);
- checkPathSeenDuringPartialResolution(symlinkTargetRootedPath, symlinkResolutionState, env);
+ checkPathSeenDuringPartialResolution(
+ symlinkTargetRootedPath, sortedLogicalChain, logicalChain, env);
if (env.valuesMissing()) {
return null;
}
// The symlink target could have a different parent directory, which itself could be a directory
// symlink (or have an ancestor directory symlink)!
- return resolveFromAncestors(symlinkTargetRootedPath, symlinkResolutionState, env);
+ return resolveFromAncestors(symlinkTargetRootedPath, sortedLogicalChain, logicalChain, env);
}
private void checkAndNotePathSeenDuringPartialResolution(
- RootedPath rootedPath, SymlinkResolutionState symlinkResolutionState, Environment env)
+ RootedPath rootedPath,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
+ Environment env)
throws FileFunctionException, InterruptedException {
Path path = rootedPath.asPath();
- checkPathSeenDuringPartialResolutionInternal(rootedPath, path, symlinkResolutionState, env);
- symlinkResolutionState.sortedLogicalChain.add(path);
- symlinkResolutionState.logicalChain.add(rootedPath);
+ checkPathSeenDuringPartialResolutionInternal(
+ rootedPath, path, sortedLogicalChain, logicalChain, env);
+ sortedLogicalChain.add(path);
+ logicalChain.add(rootedPath);
}
private void checkPathSeenDuringPartialResolution(
- RootedPath rootedPath, SymlinkResolutionState symlinkResolutionState, Environment env)
+ RootedPath rootedPath,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
+ Environment env)
throws FileFunctionException, InterruptedException {
checkPathSeenDuringPartialResolutionInternal(
- rootedPath, rootedPath.asPath(), symlinkResolutionState, env);
+ rootedPath, rootedPath.asPath(), sortedLogicalChain, logicalChain, env);
}
private void checkPathSeenDuringPartialResolutionInternal(
RootedPath rootedPath,
Path path,
- SymlinkResolutionState symlinkResolutionState,
+ TreeSet<Path> sortedLogicalChain,
+ ArrayList<RootedPath> logicalChain,
Environment env)
throws FileFunctionException, InterruptedException {
// We are about to perform another step of partial real path resolution. 'logicalChain' is the
@@ -319,13 +329,12 @@
// candidate p for (ii) and (iii).
SkyKey uniquenessKey = null;
FileSymlinkException fse = null;
- Path seenFloorPath = symlinkResolutionState.sortedLogicalChain.floor(path);
- Path seenCeilingPath = symlinkResolutionState.sortedLogicalChain.ceiling(path);
- if (symlinkResolutionState.sortedLogicalChain.contains(path)) {
+ Path seenFloorPath = sortedLogicalChain.floor(path);
+ Path seenCeilingPath = sortedLogicalChain.ceiling(path);
+ if (sortedLogicalChain.contains(path)) {
// 'rootedPath' is [transitively] a symlink to a previous element in the symlink chain (i).
Pair<ImmutableList<RootedPath>, ImmutableList<RootedPath>> pathAndChain =
- CycleUtils.splitIntoPathAndChain(
- isPathPredicate(path), symlinkResolutionState.logicalChain);
+ CycleUtils.splitIntoPathAndChain(isPathPredicate(path), logicalChain);
FileSymlinkCycleException fsce =
new FileSymlinkCycleException(pathAndChain.getFirst(), pathAndChain.getSecond());
uniquenessKey = FileSymlinkCycleUniquenessFunction.key(fsce.getCycle());
@@ -336,26 +345,21 @@
Pair<ImmutableList<RootedPath>, ImmutableList<RootedPath>> pathAndChain =
CycleUtils.splitIntoPathAndChain(
isPathPredicate(seenFloorPath),
- ImmutableList.copyOf(
- Iterables.concat(
- symlinkResolutionState.logicalChain, ImmutableList.of(rootedPath))));
+ ImmutableList.copyOf(Iterables.concat(logicalChain, ImmutableList.of(rootedPath))));
uniquenessKey = FileSymlinkInfiniteExpansionUniquenessFunction.key(pathAndChain.getSecond());
fse = new FileSymlinkInfiniteExpansionException(
pathAndChain.getFirst(), pathAndChain.getSecond());
} else if (seenCeilingPath != null && seenCeilingPath.startsWith(path)) {
// 'rootedPath' is [transitively] a symlink to an ancestor of a previous element in the
// symlink chain (iii).
- if (symlinkResolutionState.unboundedAncestorSymlinkExpansionChain == null) {
- Pair<ImmutableList<RootedPath>, ImmutableList<RootedPath>> pathAndChain =
- CycleUtils.splitIntoPathAndChain(
- isPathPredicate(seenCeilingPath),
- ImmutableList.copyOf(
- Iterables.concat(
- symlinkResolutionState.logicalChain, ImmutableList.of(rootedPath))));
- symlinkResolutionState.pathToUnboundedAncestorSymlinkExpansionChain =
- pathAndChain.getFirst();
- symlinkResolutionState.unboundedAncestorSymlinkExpansionChain = pathAndChain.getSecond();
- }
+ Pair<ImmutableList<RootedPath>, ImmutableList<RootedPath>> pathAndChain =
+ CycleUtils.splitIntoPathAndChain(
+ isPathPredicate(seenCeilingPath),
+ ImmutableList.copyOf(Iterables.concat(logicalChain, ImmutableList.of(rootedPath))));
+ uniquenessKey = FileSymlinkInfiniteExpansionUniquenessFunction.key(pathAndChain.getSecond());
+ fse =
+ new FileSymlinkInfiniteExpansionException(
+ pathAndChain.getFirst(), pathAndChain.getSecond());
}
if (uniquenessKey != null) {
// Note that this dependency is merely to ensure that each unique symlink error gets
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java
index 8aee295..b832485 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GlobFunction.java
@@ -235,28 +235,6 @@
if (!symlinkFileValue.exists()) {
continue;
}
-
- // This check is more strict than necessary: we raise an error if globbing traverses into
- // a directory for any reason, even though it's only necessary if that reason was the
- // resolution of a recursive glob ("**"). Fixing this would require plumbing the ancestor
- // symlink information through DirectoryListingValue.
- if (symlinkFileValue.isDirectory()
- && symlinkFileValue.unboundedAncestorSymlinkExpansionChain() != null) {
- SkyKey uniquenessKey =
- FileSymlinkInfiniteExpansionUniquenessFunction.key(
- symlinkFileValue.unboundedAncestorSymlinkExpansionChain());
- env.getValue(uniquenessKey);
- if (env.valuesMissing()) {
- return null;
- }
-
- FileSymlinkInfiniteExpansionException symlinkException =
- new FileSymlinkInfiniteExpansionException(
- symlinkFileValue.pathToUnboundedAncestorSymlinkExpansionChain(),
- symlinkFileValue.unboundedAncestorSymlinkExpansionChain());
- throw new GlobFunctionException(symlinkException, Transience.PERSISTENT);
- }
-
Dirent dirent = symlinkFileMap.get(lookedUpKeyAndValue.getKey());
String fileName = dirent.getName();
if (symlinkFileValue.isDirectory()) {
@@ -436,9 +414,5 @@
public GlobFunctionException(InconsistentFilesystemException e, Transience transience) {
super(e, transience);
}
-
- public GlobFunctionException(FileSymlinkInfiniteExpansionException e, Transience transience) {
- super(e, transience);
- }
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java
index c614c18..0b93eea 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ProcessPackageDirectory.java
@@ -96,23 +96,6 @@
return ProcessPackageDirectoryResult.EMPTY_RESULT;
}
- if (fileValue.unboundedAncestorSymlinkExpansionChain() != null) {
- SkyKey uniquenessKey =
- FileSymlinkInfiniteExpansionUniquenessFunction.key(
- fileValue.unboundedAncestorSymlinkExpansionChain());
- env.getValue(uniquenessKey);
- if (env.valuesMissing()) {
- return null;
- }
-
- FileSymlinkInfiniteExpansionException symlinkException =
- new FileSymlinkInfiniteExpansionException(
- fileValue.pathToUnboundedAncestorSymlinkExpansionChain(),
- fileValue.unboundedAncestorSymlinkExpansionChain());
- return reportErrorAndReturn(
- symlinkException.getMessage(), symlinkException, rootRelativePath, env.getListener());
- }
-
PackageIdentifier packageId = PackageIdentifier.create(repositoryName, rootRelativePath);
if ((packageId.getRepository().isDefault() || packageId.getRepository().isMain())
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
index 3bba228..8b27387 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
@@ -338,19 +338,6 @@
if (env.valuesMissing()) {
throw new MissingDepException();
}
- if (fileValue.unboundedAncestorSymlinkExpansionChain() != null) {
- SkyKey uniquenessKey =
- FileSymlinkInfiniteExpansionUniquenessFunction.key(
- fileValue.unboundedAncestorSymlinkExpansionChain());
- env.getValue(uniquenessKey);
- if (env.valuesMissing()) {
- throw new MissingDepException();
- }
-
- throw new FileSymlinkInfiniteExpansionException(
- fileValue.pathToUnboundedAncestorSymlinkExpansionChain(),
- fileValue.unboundedAncestorSymlinkExpansionChain());
- }
if (fileValue.exists()) {
// If it exists, it may either be a symlink or a file/directory.
PathFragment unresolvedLinkTarget = null;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
index 4e0ac4c..dc8113f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FileFunctionTest.java
@@ -459,16 +459,7 @@
@Test
public void testRecursiveNestingSymlink() throws Exception {
symlink("a/a", "../a");
- file("b");
- assertNoError("a/a/a/a/b");
- }
-
- @Test
- public void testSimpleUnboundedAncestorSymlinkExpansionChainReported() throws Exception {
- symlink("a/a", "../a");
- FileValue v = valueForPath(path("a/a"));
- assertThat(v.unboundedAncestorSymlinkExpansionChain())
- .containsExactly(rootedPath("a/a"), rootedPath("a"));
+ assertError("a/a/b");
}
@Test
@@ -1112,7 +1103,7 @@
public void testSymlinkToPackagePathBoundary() throws Exception {
Path path = path("this/is/a/path");
FileSystemUtils.ensureSymbolicLink(path, pkgRoot.asPath());
- assertNoError("this/is/a/path");
+ assertError("this/is/a/path");
}
private void runTestSimpleInfiniteSymlinkExpansion(
@@ -1173,24 +1164,20 @@
.setEventHandler(eventHandler)
.build();
EvaluationResult<FileValue> result = driver.evaluate(keys, evaluationContext);
- if (symlinkToAncestor) {
- assertThat(result.hasError()).isFalse();
- } else {
- assertThat(result.hasError()).isTrue();
- for (SkyKey key : errorKeys) {
- ErrorInfo errorInfo = result.getError(key);
- // FileFunction detects infinite symlink expansion explicitly.
- assertThat(errorInfo.getCycleInfo()).isEmpty();
- FileSymlinkInfiniteExpansionException fsiee =
- (FileSymlinkInfiniteExpansionException) errorInfo.getException();
- assertThat(fsiee).hasMessageThat().contains("Infinite symlink expansion");
- assertThat(fsiee.getChain()).containsExactlyElementsIn(expectedChain).inOrder();
- }
- // Check that the unique symlink expansion error was reported exactly once.
- assertThat(eventHandler.getEvents()).hasSize(1);
- assertThat(Iterables.getOnlyElement(eventHandler.getEvents()).getMessage())
- .contains("infinite symlink expansion detected");
+ assertThat(result.hasError()).isTrue();
+ for (SkyKey key : errorKeys) {
+ ErrorInfo errorInfo = result.getError(key);
+ // FileFunction detects infinite symlink expansion explicitly.
+ assertThat(errorInfo.getCycleInfo()).isEmpty();
+ FileSymlinkInfiniteExpansionException fsiee =
+ (FileSymlinkInfiniteExpansionException) errorInfo.getException();
+ assertThat(fsiee).hasMessageThat().contains("Infinite symlink expansion");
+ assertThat(fsiee.getChain()).containsExactlyElementsIn(expectedChain).inOrder();
}
+ // Check that the unique symlink expansion error was reported exactly once.
+ assertThat(eventHandler.getEvents()).hasSize(1);
+ assertThat(Iterables.getOnlyElement(eventHandler.getEvents()).getMessage())
+ .contains("infinite symlink expansion detected");
}
@Test
@@ -1219,13 +1206,15 @@
@Test
public void testInfiniteSymlinkExpansion_symlinkToReferrerToAncestor() throws Exception {
symlink("d", "a");
- directory("a/b");
+ Path abPath = directory("a/b");
+ Path abcPath = abPath.getChild("c");
symlink("a/b/c", "../../d/b");
- symlink("e", "a/b/c");
- Path fPath = symlink("f", "e");
- RootedPath rootedPathF = RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(fPath));
- SkyKey keyF = FileValue.key(rootedPathF);
+ RootedPath rootedPathABC = RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(abcPath));
+ RootedPath rootedPathAB = RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(abPath));
+ RootedPath rootedPathDB = RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(path("d/b")));
+
+ SkyKey keyABC = FileValue.key(rootedPathABC);
StoredEventHandler eventHandler = new StoredEventHandler();
SequentialBuildDriver driver = makeDriver();
@@ -1235,16 +1224,25 @@
.setNumThreads(DEFAULT_THREAD_COUNT)
.setEventHandler(eventHandler)
.build();
- EvaluationResult<FileValue> result = driver.evaluate(ImmutableList.of(keyF), evaluationContext);
+ EvaluationResult<FileValue> result =
+ driver.evaluate(ImmutableList.of(keyABC), evaluationContext);
- assertThatEvaluationResult(result).hasNoError();
- FileValue e = result.get(keyF);
- assertThat(e.pathToUnboundedAncestorSymlinkExpansionChain())
- .containsExactly(rootedPath("f"), rootedPath("e"))
+ assertThatEvaluationResult(result).hasErrorEntryForKeyThat(keyABC).isNotTransient();
+ assertThatEvaluationResult(result)
+ .hasErrorEntryForKeyThat(keyABC)
+ .hasExceptionThat()
+ .isInstanceOf(FileSymlinkInfiniteExpansionException.class);
+ FileSymlinkInfiniteExpansionException fiee =
+ (FileSymlinkInfiniteExpansionException) result.getError(keyABC).getException();
+ assertThat(fiee).hasMessageThat().contains("Infinite symlink expansion");
+ assertThat(fiee.getPathToChain()).isEmpty();
+ assertThat(fiee.getChain())
+ .containsExactly(rootedPathABC, rootedPathDB, rootedPathAB)
.inOrder();
- assertThat(e.unboundedAncestorSymlinkExpansionChain())
- .containsExactly(rootedPath("a/b/c"), rootedPath("d/b"), rootedPath("a/b"))
- .inOrder();
+
+ assertThat(eventHandler.getEvents()).hasSize(1);
+ assertThat(Iterables.getOnlyElement(eventHandler.getEvents()).getMessage())
+ .contains("infinite symlink expansion detected");
}
@Test
@@ -1255,6 +1253,10 @@
RootedPath rootedPathDir1AB =
RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(path("dir1/a/b")));
+ RootedPath rootedPathDir2B =
+ RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(path("dir2/b")));
+ RootedPath rootedPathDir1 = RootedPath.toRootedPath(pkgRoot, pkgRoot.relativize(path("dir1")));
+
SkyKey keyDir1AB = FileValue.key(rootedPathDir1AB);
StoredEventHandler eventHandler = new StoredEventHandler();
@@ -1268,7 +1270,22 @@
EvaluationResult<FileValue> result =
driver.evaluate(ImmutableList.of(keyDir1AB), evaluationContext);
- assertThatEvaluationResult(result).hasNoError();
+ assertThatEvaluationResult(result).hasErrorEntryForKeyThat(keyDir1AB).isNotTransient();
+ assertThatEvaluationResult(result)
+ .hasErrorEntryForKeyThat(keyDir1AB)
+ .hasExceptionThat()
+ .isInstanceOf(FileSymlinkInfiniteExpansionException.class);
+ FileSymlinkInfiniteExpansionException fiee =
+ (FileSymlinkInfiniteExpansionException) result.getError(keyDir1AB).getException();
+ assertThat(fiee).hasMessageThat().contains("Infinite symlink expansion");
+ assertThat(fiee.getPathToChain()).isEmpty();
+ assertThat(fiee.getChain())
+ .containsExactly(rootedPathDir1AB, rootedPathDir2B, rootedPathDir1)
+ .inOrder();
+
+ assertThat(eventHandler.getEvents()).hasSize(1);
+ assertThat(Iterables.getOnlyElement(eventHandler.getEvents()).getMessage())
+ .contains("infinite symlink expansion detected");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
index 9a93bd31..1978e0f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/GlobFunctionTest.java
@@ -684,8 +684,6 @@
FileValue pkgDirValue =
FileValue.value(
ImmutableList.of(pkgRootedPath),
- null,
- null,
pkgRootedPath,
pkgDirFileStateValue,
pkgRootedPath,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoaderTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoaderTest.java
index 0aa644e..f082350 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoaderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoaderTest.java
@@ -226,7 +226,7 @@
@Test
public void testNonPackageEventsReported() throws Exception {
path("foo").createDirectoryAndParents();
- symlink("foo/infinitesymlinkpkg", path("foo/infinitesymlinkpkg/subdir"));
+ symlink("foo/infinitesymlinkpkg", path("foo"));
PackageIdentifier pkgId = PackageIdentifier.createInMainRepo("foo/infinitesymlinkpkg");
PackageLoader.Result result;
try (PackageLoader pkgLoader = newPackageLoader()) {
diff --git a/src/test/shell/bazel/bazelignore_test.sh b/src/test/shell/bazel/bazelignore_test.sh
index 6113c30..83b6727 100755
--- a/src/test/shell/bazel/bazelignore_test.sh
+++ b/src/test/shell/bazel/bazelignore_test.sh
@@ -98,22 +98,18 @@
|| fail "directory mentioned in .bazelignore not ignored as it should"
}
-test_symlink_cycle_ignored() {
+test_symlink_loop_ignored() {
rm -rf work && mkdir work && cd work
create_workspace_with_default_repos WORKSPACE
mkdir -p ignoreme/deep
(cd ignoreme/deep && ln -s . loop)
touch BUILD
-
- # This should really fail, but it does not:
- # https://github.com/bazelbuild/bazel/issues/12148
- bazel build ... >& $TEST_log || fail "Expected success"
- expect_log "Infinite symlink expansion"
+ bazel build ... && fail "Expected failure" || :
echo; echo
echo ignoreme > .bazelignore
- bazel build ... >& $TEST_log || fail "Expected success"
- expect_not_log "Infinite symlink expansion"
+ bazel build ... \
+ || fail "directory mentioned in .bazelignore not ignored as it should"
}
test_build_specific_target() {