提交 59880c2f 编写于 作者: M Matt Sicker

Add path filter support to PathRemover

This allows for simplifying FilePath to use PathRemover rather than duplicating logic.
Signed-off-by: NMatt Sicker <boards@gmail.com>
上级 301ba7af
......@@ -1271,7 +1271,7 @@ public final class FilePath implements Serializable {
private static final long serialVersionUID = 1L;
@Override
public Void invoke(File f, VirtualChannel channel) throws IOException {
Util.deleteRecursive(deleting(f));
Util.deleteRecursive(fileToPath(f), path -> deleting(path.toFile()).delete());
return null;
}
}
......@@ -1286,7 +1286,7 @@ public final class FilePath implements Serializable {
private static final long serialVersionUID = 1L;
@Override
public Void invoke(File f, VirtualChannel channel) throws IOException {
Util.deleteContentsRecursive(deleting(f));
Util.deleteContentsRecursive(fileToPath(f), path -> deleting(path.toFile()).delete());
return null;
}
}
......
......@@ -75,6 +75,7 @@ import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
......@@ -241,7 +242,18 @@ public class Util {
* if the operation fails.
*/
public static void deleteContentsRecursive(@Nonnull File file) throws IOException {
newPathRemover().forceRemoveDirectoryContents(fileToPath(file));
deleteContentsRecursive(fileToPath(file), path -> true);
}
/**
* Deletes the given directory contents (but not the directory itself) recursively using a filter.
* @param path a directory to delete
* @param pathFilter a predicate that when evaluated to true will delete that path; when false, will ignore that path
* @throws IOException if the operation fails
*/
@Restricted(NoExternalUse.class)
public static void deleteContentsRecursive(@Nonnull Path path, @Nonnull Predicate<Path> pathFilter) throws IOException {
newPathRemover(pathFilter).forceRemoveDirectoryContents(path);
}
/**
......@@ -252,7 +264,7 @@ public class Util {
* @throws IOException if it exists but could not be successfully deleted
*/
public static void deleteFile(@Nonnull File f) throws IOException {
newPathRemover().forceRemoveFile(fileToPath(f));
newPathRemover(path -> true).forceRemoveFile(fileToPath(f));
}
/**
......@@ -264,7 +276,18 @@ public class Util {
* if the operation fails.
*/
public static void deleteRecursive(@Nonnull File dir) throws IOException {
newPathRemover().forceRemoveRecursive(fileToPath(dir));
deleteRecursive(fileToPath(dir), path -> true);
}
/**
* Deletes the given directory and contents recursively using a filter.
* @param dir a directory to delete
* @param pathFilter a predicate that when evaluated to true will delete that path; when false, will ignore that path
* @throws IOException if the operation fails
*/
@Restricted(NoExternalUse.class)
public static void deleteRecursive(@Nonnull Path dir, @Nonnull Predicate<Path> pathFilter) throws IOException {
newPathRemover(pathFilter).forceRemoveRecursive(dir);
}
/*
......@@ -1560,8 +1583,8 @@ public class Util {
@Restricted(value = NoExternalUse.class)
static boolean GC_AFTER_FAILED_DELETE = SystemProperties.getBoolean(Util.class.getName() + ".performGCOnFailedDelete");
private static PathRemover newPathRemover() {
return PathRemover.newRobustRemover(DELETION_MAX - 1, GC_AFTER_FAILED_DELETE, WAIT_BETWEEN_DELETION_RETRIES);
private static PathRemover newPathRemover(@Nonnull Predicate<Path> pathFilter) {
return PathRemover.newFilteredRobustRemover(pathFilter, DELETION_MAX - 1, GC_AFTER_FAILED_DELETE, WAIT_BETWEEN_DELETION_RETRIES);
}
/**
......
......@@ -42,6 +42,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
......@@ -49,21 +50,23 @@ import java.util.stream.Stream;
public class PathRemover {
public static PathRemover newSimpleRemover() {
return new PathRemover(ignored -> false);
return new PathRemover(ignored -> false, ignored -> true);
}
public static PathRemover newRemoverWithStrategy(@Nonnull RetryStrategy retryStrategy) {
return new PathRemover(retryStrategy);
return new PathRemover(retryStrategy, ignored -> true);
}
public static PathRemover newRobustRemover(int maxRetries, boolean gcAfterFailedRemove, long waitBetweenRetries) {
return new PathRemover(new PausingGCRetryStrategy(maxRetries < 1 ? 1 : maxRetries, gcAfterFailedRemove, waitBetweenRetries));
public static PathRemover newFilteredRobustRemover(@Nonnull Predicate<Path> pathFilter, int maxRetries, boolean gcAfterFailedRemove, long waitBetweenRetries) {
return new PathRemover(new PausingGCRetryStrategy(maxRetries < 1 ? 1 : maxRetries, gcAfterFailedRemove, waitBetweenRetries), pathFilter);
}
private final RetryStrategy retryStrategy;
private final Predicate<Path> pathFilter;
private PathRemover(@Nonnull RetryStrategy retryStrategy) {
private PathRemover(@Nonnull RetryStrategy retryStrategy, @Nonnull Predicate<Path> pathFilter) {
this.retryStrategy = retryStrategy;
this.pathFilter = pathFilter;
}
public void forceRemoveFile(@Nonnull Path path) throws IOException {
......@@ -186,7 +189,7 @@ public class PathRemover {
}
}
private static Optional<IOException> tryRemoveFile(@Nonnull Path path) {
private Optional<IOException> tryRemoveFile(@Nonnull Path path) {
try {
removeOrMakeRemovableThenRemove(path.normalize());
return Optional.empty();
......@@ -195,7 +198,7 @@ public class PathRemover {
}
}
private static List<IOException> tryRemoveRecursive(@Nonnull Path path) {
private List<IOException> tryRemoveRecursive(@Nonnull Path path) {
Path normalized = path.normalize();
List<IOException> accumulatedErrors = Util.isSymlink(normalized) ? new ArrayList<>() :
tryRemoveDirectoryContents(normalized);
......@@ -203,7 +206,7 @@ public class PathRemover {
return accumulatedErrors;
}
private static List<IOException> tryRemoveDirectoryContents(@Nonnull Path path) {
private List<IOException> tryRemoveDirectoryContents(@Nonnull Path path) {
Path normalized = path.normalize();
List<IOException> accumulatedErrors = new ArrayList<>();
if (!Files.isDirectory(normalized)) return accumulatedErrors;
......@@ -217,7 +220,8 @@ public class PathRemover {
return accumulatedErrors;
}
private static void removeOrMakeRemovableThenRemove(@Nonnull Path path) throws IOException {
private void removeOrMakeRemovableThenRemove(@Nonnull Path path) throws IOException {
if (!pathFilter.test(path)) return;
try {
Files.deleteIfExists(path);
} catch (IOException e) {
......@@ -256,9 +260,9 @@ public class PathRemover {
$ rm x
rm: x not removed: Permission denied
*/
Path parent = path.getParent().normalize();
if (parent != null && !Files.isWritable(parent)) {
makeWritable(parent);
Optional<Path> maybeParent = Optional.ofNullable(path.getParent()).map(Path::normalize).filter(p -> !Files.isWritable(p));
if (maybeParent.isPresent()) {
makeWritable(maybeParent.get());
}
}
......
......@@ -91,6 +91,7 @@ public class PathRemoverTest {
given(path.toString()).willReturn(filename);
given(path.toFile()).willReturn(file);
given(path.getFileSystem()).willReturn(fs);
given(path.normalize()).willReturn(path);
given(fs.provider()).willReturn(fsProvider);
given(fsProvider.deleteIfExists(path)).willThrow(new FileSystemException(filename));
given(fsProvider.readAttributes(path, BasicFileAttributes.class)).willReturn(attributes);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册