Refactor filesystem traversal failures
Only DanglingSymlinkException remains a subtype. It's the only one that
meaningfully appears in catch clauses and method throws lists.
This CL also equips SkyframeAwareAction exceptions with
DetailedExitCodes.
RELNOTES: None.
PiperOrigin-RevId: 315324370
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 c611700..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
@@ -73,34 +73,39 @@
private static final FileInfo NON_EXISTENT_FILE_INFO =
new FileInfo(FileType.NONEXISTENT, NON_EXISTENT_HAS_DIGEST, null, null);
- /** Base class for exceptions that {@link RecursiveFilesystemTraversalFunctionException} wraps. */
- public abstract static class RecursiveFilesystemTraversalException extends Exception {
- protected RecursiveFilesystemTraversalException(String message) {
- super(message);
- }
- }
+ /** The exception that {@link RecursiveFilesystemTraversalFunctionException} wraps. */
+ public static class RecursiveFilesystemTraversalException extends Exception {
- /** Thrown when a generated directory's root-relative path conflicts with a package's path. */
- public static final class GeneratedPathConflictException extends
- RecursiveFilesystemTraversalException {
- GeneratedPathConflictException(TraversalRequest traversal) {
- super(
- String.format(
- "Generated directory %s conflicts with package under the same path. "
- + "Additional info: %s",
- traversal.root.asRootedPath().getRootRelativePath().getPathString(),
- traversal.errorInfo != null ? traversal.errorInfo : traversal.toString()));
- }
- }
+ /**
+ * Categories of errors that prevent normal {@link RecursiveFilesystemTraversalFunction}
+ * evaluation.
+ */
+ public enum Type {
+ /**
+ * The traversal encountered a subdirectory with a BUILD file but is not allowed to recurse
+ * into it. See {@code PackageBoundaryMode#REPORT_ERROR}.
+ */
+ CANNOT_CROSS_PACKAGE_BOUNDARY,
- /**
- * Thrown when the traversal encounters a subdirectory with a BUILD file but is not allowed to
- * recurse into it. See {@code PackageBoundaryMode#REPORT_ERROR}.
- */
- public static final class CannotCrossPackageBoundaryException extends
- RecursiveFilesystemTraversalException {
- CannotCrossPackageBoundaryException(String message) {
+ /** A dangling symlink was dereferenced. */
+ DANGLING_SYMLINK,
+
+ /** A file operation failed. */
+ FILE_OPERATION_FAILURE,
+
+ /** A generated directory's root-relative path conflicts with a package's path. */
+ GENERATED_PATH_CONFLICT,
+ }
+
+ private final Type type;
+
+ RecursiveFilesystemTraversalException(String message, Type type) {
super(message);
+ this.type = type;
+ }
+
+ public Type getType() {
+ return type;
}
}
@@ -111,29 +116,14 @@
* and it's not easy to merge the two because of the dependency structure. The other one will
* probably be removed along with the rest of the legacy Fileset code.
*/
- public static final class DanglingSymlinkException extends RecursiveFilesystemTraversalException {
- public final String path;
- public final String unresolvedLink;
-
- public DanglingSymlinkException(String path, String unresolvedLink) {
+ static final class DanglingSymlinkException extends RecursiveFilesystemTraversalException {
+ DanglingSymlinkException(String path, String unresolvedLink) {
super(
String.format(
- "Found dangling symlink: %s, unresolved path: \"%s\"", path, unresolvedLink));
+ "Found dangling symlink: %s, unresolved path: \"%s\"", path, unresolvedLink),
+ Type.DANGLING_SYMLINK);
Preconditions.checkArgument(path != null && !path.isEmpty());
Preconditions.checkArgument(unresolvedLink != null && !unresolvedLink.isEmpty());
- this.path = path;
- this.unresolvedLink = unresolvedLink;
- }
-
- public String getPath() {
- return path;
- }
- }
-
- /** Thrown when we encounter errors from underlying File operations */
- public static final class FileOperationException extends RecursiveFilesystemTraversalException {
- public FileOperationException(String message) {
- super(message);
}
}
@@ -189,8 +179,7 @@
if (pkgLookupResult.isConflicting()) {
// The traversal was requested for an output directory whose root-relative path conflicts
// with a source package. We can't handle that, bail out.
- throw new RecursiveFilesystemTraversalFunctionException(
- new GeneratedPathConflictException(traversal));
+ throw createGeneratedPathConflictException(traversal);
} else if (pkgLookupResult.isPackage() && !traversal.skipTestingForSubpackage) {
// The traversal was requested for a directory that defines a package.
String msg =
@@ -208,7 +197,8 @@
case REPORT_ERROR:
// We cannot traverse the subpackage and should complain loudly (display an error).
throw new RecursiveFilesystemTraversalFunctionException(
- new CannotCrossPackageBoundaryException(msg));
+ new RecursiveFilesystemTraversalException(
+ msg, RecursiveFilesystemTraversalException.Type.CANNOT_CROSS_PACKAGE_BOUNDARY));
default:
throw new IllegalStateException(traversal.toString());
}
@@ -221,13 +211,28 @@
rootInfo,
traverseChildren(env, dependentKeys, /*inline=*/ traversal.isRootGenerated));
} catch (IOException e) {
+ String message = "Error while traversing fileset: " + e.getMessage();
throw new RecursiveFilesystemTraversalFunctionException(
- new FileOperationException("Error while traversing fileset: " + e.getMessage()));
+ new RecursiveFilesystemTraversalException(
+ message, RecursiveFilesystemTraversalException.Type.FILE_OPERATION_FAILURE));
} catch (MissingDepException e) {
return null;
}
}
+ private static RecursiveFilesystemTraversalFunctionException createGeneratedPathConflictException(
+ TraversalRequest traversal) {
+ String message =
+ String.format(
+ "Generated directory %s conflicts with package under the same path. "
+ + "Additional info: %s",
+ traversal.root.asRootedPath().getRootRelativePath().getPathString(),
+ traversal.errorInfo != null ? traversal.errorInfo : traversal.toString());
+ return new RecursiveFilesystemTraversalFunctionException(
+ new RecursiveFilesystemTraversalException(
+ message, RecursiveFilesystemTraversalException.Type.GENERATED_PATH_CONFLICT));
+ }
+
@Override
public String extractTag(SkyKey skyKey) {
return null;