package com.sleekbyte.tailor.utils;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* Finds all files that match the specified pattern.
*/
public final class Finder extends SimpleFileVisitor<Path> {
private Set<String> fileNames = new TreeSet<>();
private Set<PathMatcher> includeMatcher;
private Set<PathMatcher> excludeMatcher;
private URI base;
private Map<Path, Boolean> isParentIncluded = new HashMap<>();
/**
* Finder constructor.
*
* @param includeSet file paths that should be analyzed
* @param excludeSet file paths that should be ignored
* @param base location of .tailor.yml file
*/
public Finder(Set<String> includeSet, Set<String> excludeSet, URI base) {
this.includeMatcher = includeSet
.stream()
.map(includePattern -> FileSystems.getDefault().getPathMatcher("glob:" + includePattern))
.collect(Collectors.toSet());
this.excludeMatcher = excludeSet
.stream()
.map(excludePattern -> FileSystems.getDefault().getPathMatcher("glob:" + excludePattern))
.collect(Collectors.toSet());
this.base = base;
}
public Set<String> getFileNames() {
return fileNames;
}
// Invoke the pattern matching method on each file.
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
Path relative = Paths.get(base.relativize(file.toUri()).getPath());
if (excludeMatcher.stream().anyMatch(pathMatcher -> pathMatcher.matches(relative))) {
return FileVisitResult.CONTINUE;
}
if ((isParentIncluded.getOrDefault(file.getParent(), false)
|| includeMatcher.stream().anyMatch(pathMatcher -> pathMatcher.matches(relative)))
&& (file.toFile().getCanonicalPath().endsWith(".swift") && file.toFile().canRead())) {
fileNames.add(file.toFile().getCanonicalPath());
}
return FileVisitResult.CONTINUE;
}
// Invoke the pattern matching method on each directory.
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attributes) {
Path relative = Paths.get(base.relativize(dir.toUri()).getPath());
if (excludeMatcher.stream().anyMatch(pathMatcher -> pathMatcher.matches(relative))) {
return FileVisitResult.SKIP_SUBTREE;
}
if (isParentIncluded.getOrDefault(dir.getParent(), false)
|| includeMatcher.stream().anyMatch(pathMatcher -> pathMatcher.matches(relative))) {
isParentIncluded.put(dir, true);
return FileVisitResult.CONTINUE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
isParentIncluded.put(dir, false);
return super.postVisitDirectory(dir, exc);
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
System.err.println(exc.getMessage());
return FileVisitResult.CONTINUE;
}
}