+ private static boolean anyContainsHeadState(List<Path> paths) {
+ for (Path p : paths)
+ if (Files.exists(p.resolve(HeadState.HEAD_STATE)))
+ return true;
+ return false;
+ }
+
+ @SafeVarargs
+ private static List<Path> listRevisionDirs(Path directory, boolean descending, Predicate<Path>... filters) throws IOException {
+ int coef = descending ? -1 : 1;
+ try (Stream<Path> s = Files.walk(directory, 1)) {
+ Stream<Path> fs = s.filter(p -> !p.equals(directory));
+ for (Predicate<Path> p : filters)
+ fs = fs.filter(p);
+ return fs.filter(Files::isDirectory)
+ .sorted((p1, p2) -> coef * Integer.compare(Integer.parseInt(p1.getFileName().toString()),
+ Integer.parseInt(p2.getFileName().toString())))
+ .collect(Collectors.toList());
+ }
+ }
+
+ private static void deleteAll(Path dir) throws IOException {
+ Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ private static final DateTimeFormatter RECOVERY_DIR_FORMAT = DateTimeFormatter.ofPattern("yyyy-M-d_HH-mm-ss");
+
+ private static Path getRecoveryFolder(Path directory) {
+ return findNonexistentDir(
+ directory.resolve("recovery"),
+ RECOVERY_DIR_FORMAT.format(ZonedDateTime.now()));
+ }
+
+ private static Path findNonexistentDir(Path inDirectory, String prefix) {
+ for (int i = 0;; ++i) {
+ Path dir = inDirectory.resolve(i == 0 ? prefix : prefix + "-" + i);
+ if (Files.notExists(dir))
+ return dir;