/*
 * Bach - Java Shell Builder
 * Copyright (C) 2019 Christian Stein
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.sormuras.bach.util;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/** {@link Path}-related helpers. */
public class Paths {
  private Paths() {}

  /** Convenient short-cut to {@code "user.home"} as a path. */
  public static final Path USER_HOME = Path.of(System.getProperty("user.home"));

  public static Path createDirectories(Path directory) {
    try {
      Files.createDirectories(directory);
    } catch (Exception e) {
      throw new RuntimeException("Create directories failed: " + directory, e);
    }
    return directory;
  }

  public static List<Path> filter(List<Path> paths, Predicate<Path> filter) {
    return paths.stream().filter(filter).collect(Collectors.toList());
  }

  public static List<Path> filterExisting(List<Path> paths) {
    return filter(paths, Files::exists);
  }

  public static String join(List<Path> paths) {
    return paths.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator));
  }

  public static List<Path> list(Path directory, Predicate<Path> filter) {
    try (var stream = Files.list(directory)) {
      return stream.filter(filter).sorted().collect(Collectors.toList());
    } catch (Exception e) {
      throw new RuntimeException("List directory failed: " + directory, e);
    }
  }

  public static List<Path> list(Path directory, String glob) {
    try (var items = Files.newDirectoryStream(directory, glob)) {
      return StreamSupport.stream(items.spliterator(), false).sorted().collect(Collectors.toList());
    } catch (Exception e) {
      throw new RuntimeException("List directory using glob failed: " + directory, e);
    }
  }

  public static String readString(Path path) {
    try {
      return Files.readString(path);
    } catch (Exception e) {
      throw new RuntimeException("Read all content from file failed: " + path, e);
    }
  }
}

@@ -752,19 +752,74 @@
 va.util.
-Lis
+Collection;%0Aimport java.util.List;%0Aimport java.util.TreeSe
 t;%0Aimpor
@@ -1610,32 +1610,32 @@
 %3CPath%3E paths) %7B%0A
-
     return filte
@@ -1656,32 +1656,1110 @@
 ::exists);%0A  %7D%0A%0A
+  /** Walk all trees to find matching paths the given filter starting at given root paths. */%0A  public static List%3CPath%3E find(Collection%3CPath%3E roots, Predicate%3CPath%3E filter) %7B%0A    var files = new TreeSet%3CPath%3E();%0A    for (var root : roots) %7B%0A      try (var stream = Files.walk(root)) %7B%0A        stream.filter(filter).forEach(files::add);%0A      %7D catch (Exception e) %7B%0A        throw new Error(%22Walking directory '%22 + root + %22' failed: %22 + e, e);%0A      %7D%0A    %7D%0A    return List.copyOf(files);%0A  %7D%0A%0A  /** Test supplied path for pointing to a Java source compilation unit. */%0A  public static boolean isJavaFile(Path path) %7B%0A    if (Files.isRegularFile(path)) %7B%0A      var name = path.getFileName().toString();%0A      if (name.endsWith(%22.java%22)) %7B%0A        return name.indexOf('.') == name.length() - 5; // single dot in filename%0A      %7D%0A    %7D%0A    return false;%0A  %7D%0A%0A  /** Test supplied path for pointing to a %7B@code J%7Dava %7B@code AR%7Dchive file. */%0A  public static boolean isJarFile(Path path) %7B%0A    return Files.isRegularFile(path) && path.getFileName().toString().endsWith(%22.jar%22);%0A  %7D%0A%0A
   public static 

Extend Paths with tree walker helper