package com.github.sormuras.bach.internal;

import java.nio.file.Files;
import java.nio.file.Path;

/** Internal {@link Path}-related utilities. */
public class Paths {

  public static Path createDirectories(Path directory) {
    try {
      return Files.createDirectories(directory);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public static boolean deleteIfExists(Path path) {
    try {
      return Files.deleteIfExists(path);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public static boolean isViewSupported(Path file, String view) {
    return file.getFileSystem().supportedFileAttributeViews().contains(view);
  }

  public static boolean isVisible(Path path) {
    try {
      for (int endIndex = 1; endIndex <= path.getNameCount(); endIndex++) {
        var subpath = path.subpath(0, endIndex);
        // work around https://bugs.openjdk.java.net/browse/JDK-8255576
        var probe = subpath.toString().isEmpty() ? path.toAbsolutePath() : subpath;
        if (Files.isHidden(probe)) return false;
      }
      return true;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public static String slashed(Path path) {
    return path.toString().replace('\\', '/');
  }

  /** Hidden default constructor. */
  private Paths() {}
}

@@ -62,40 +62,126 @@
 ile.
-Files;%0Aimport java.nio.file.Path
+DirectoryNotEmptyException;%0Aimport java.nio.file.Files;%0Aimport java.nio.file.Path;%0Aimport java.util.function.Predicate
 ;%0A%0A/
@@ -461,59 +461,1129 @@
 tic 
-boolean deleteIfExists(Path path) %7B%0A    try %7B%0A     
+Path deleteDirectories(Path directory) %7B%0A    return deleteDirectories(directory, __ -%3E true);%0A  %7D%0A%0A  public static Path deleteDirectories(Path directory, Predicate%3CPath%3E filter) %7B%0A    // trivial case: delete existing empty directory or single file%0A    try %7B%0A      Files.deleteIfExists(directory);%0A      return directory;%0A    %7D catch (DirectoryNotEmptyException ignored) %7B%0A      // fall-through%0A    %7D catch (Exception e) %7B%0A      throw new RuntimeException(%22Delete directories failed: %22 + directory, e);%0A    %7D%0A    // default case: walk the tree...%0A    try (var stream = Files.walk(directory)) %7B%0A      var selected = stream.filter(filter).sorted((p, q) -%3E -p.compareTo(q));%0A      for (var path : selected.toArray(Path%5B%5D::new)) Files.deleteIfExists(path);%0A    %7D catch (Exception e) %7B%0A      throw new RuntimeException(%22Delete directories failed: %22 + directory, e);%0A    %7D%0A    return directory;%0A  %7D%0A%0A  public static boolean deleteIfExists(Path path) %7B%0A    if (Files.notExists(path)) return false;%0A    try %7B%0A      if (Files.isDirectory(path)) %7B%0A        Paths.deleteDirectories(path, __ -%3E true);%0A        return true;%0A      %7D else
  ret

Add delete directory tree support