Inceptum/launcher/src/main/java/io/gitlab/jfronny/inceptum/launcher/util/gitignore/IgnoringWalk.java

89 lines
3.0 KiB
Java

package io.gitlab.jfronny.inceptum.launcher.util.gitignore;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.*;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class IgnoringWalk implements Iterator<Path> {
public static Stream<Path> walk(Path repositoryRoot) throws IOException {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new IgnoringWalk(repositoryRoot), 0), false);
}
private static final String GITIGNORE = ".gitignore";
private static final String ICEIGNORE = ".iceignore";
private static final String GIT = ".git";
private final Path ref;
private final Queue<Path> toScan = new ArrayDeque<>(); // A queue of absolute Paths which must still be scanned/returned
private final Map<Path, Ignore> ignores = new HashMap<>();
private Path next;
private IgnoringWalk(Path repositoryRoot) throws IOException {
this.ref = repositoryRoot;
enqueueDirectory(repositoryRoot);
}
@Override
public Path next() {
if (!hasNext()) throw new NoSuchElementException();
Path ret = next;
next = null;
return ret;
}
@Override
public boolean hasNext() {
if (next != null) return true;
next = toScan.poll();
if (next == null) return false;
if (Files.isDirectory(next)) {
try {
enqueueDirectory(next);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
return true;
}
private void enqueueDirectory(Path directory) throws IOException {
Path gitignorePath = directory.resolve(GITIGNORE);
Path iceignorePath = directory.resolve(ICEIGNORE);
Ignore ignore = null;
if (Files.exists(gitignorePath)) {
if (ignore == null) ignore = new Ignore();
ignore.add(Files.readAllLines(gitignorePath));
}
if (Files.exists(iceignorePath)) {
if (ignore == null) ignore = new Ignore();
ignore.add(Files.readAllLines(iceignorePath));
}
if (ignore != null) ignores.put(directory, ignore);
try (DirectoryStream<Path> files = Files.newDirectoryStream(directory)) {
for (Path path : files) {
String fileName = path.getFileName().toString();
if (!fileName.equals(GITIGNORE)
&& !fileName.equals(ICEIGNORE)
&& !fileName.equals(GIT)
&& !isIgnored(ref.relativize(path))) {
toScan.add(path);
}
}
}
}
private boolean isIgnored(Path relativePath) {
Path constructed = ref;
for (Path segment : relativePath) {
Ignore ignore = ignores.get(constructed);
if (ignore != null && ignore.isIgnored(relativePath.toString()))
return true;
constructed = constructed.resolve(segment);
}
return false;
}
}