/**
*
*/
package xhail.core;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author stefano
*
*/
public class Finder {
private static class Walker implements FileVisitor<Path> {
private static final EnumSet<FileVisitOption> OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
private final Map<String, PathMatcher> matchers;
private Map<String, Path> results;
private final String version;
private Walker(String version, String... apps) {
if (null == version || (version = version.trim()).isEmpty())
throw new IllegalArgumentException("Illegal 'version' argument in Finder.Walker(String, String...): " + version);
if (null == apps)
throw new IllegalArgumentException("Illegal 'apps' argument in Finder.Walker(String, String...): " + apps);
this.matchers = new HashMap<>();
for (String app : apps)
this.matchers.put(app, FileSystems.getDefault().getPathMatcher("glob:{" + app + "," + app + ".exe}"));
this.results = new HashMap<>();
this.version = version;
}
private boolean recurse;
public boolean find(Path path, boolean recurse) {
try {
this.recurse = recurse;
Files.walkFileTree(path, OPTIONS, Integer.MAX_VALUE, this);
return results.size() == matchers.size();
} catch (IOException e) {
// System.err.println(e);
return false;
}
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Objects.nonNull(dir);
// if (null != exc)
// throw exc;
return recurse ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Objects.nonNull(dir);
Objects.nonNull(attrs);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Objects.nonNull(file);
Objects.nonNull(attrs);
Path found = file.getFileName();
for (String name : matchers.keySet())
if (!results.containsKey(name)) {
PathMatcher matcher = matchers.get(name);
if (null != found && matcher.matches(found) && Files.isExecutable(file) && check(file, name, version)) {
results.put(name, file);
if (results.size() == matchers.size())
return FileVisitResult.TERMINATE;
}
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
Objects.nonNull(file);
// if (null != exc)
// throw exc;
return FileVisitResult.CONTINUE;
}
}
public static boolean check(Path executable, String... match) {
if (null == executable || Files.notExists(executable) || !Files.isExecutable(executable))
return false;
if (null == match || String.join(" ", match).trim().isEmpty())
return false;
try {
String[] command = combine(executable, "--version");
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
process.waitFor();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (null != (line = reader.readLine())) {
line = line.toLowerCase();
int pos = 0;
for (String pattern : match) {
pos = line.indexOf(pattern, pos);
if (pos > -1)
pos += pattern.length();
}
if (pos > -1)
return true;
}
return false;
} catch (IOException | InterruptedException e) {
return false;
}
}
public static String[] combine(Path executable, String... args) {
String[] result = new String[1 + args.length];
result[0] = executable.toString();
for (int i = 0; i < args.length; i++)
result[1 + i] = args[i];
return result;
}
private Walker walker;
public Finder(String version, String... apps) {
if (null == version || (version = version.trim()).isEmpty())
throw new IllegalArgumentException("Illegal 'version' argument in Finder(String, String...): " + version);
if (null == apps)
throw new IllegalArgumentException("Illegal 'apps' argument in Finder(String, String...): " + apps);
this.walker = new Walker(version, apps);
}
public boolean find(Path path, boolean recurse) {
boolean result = isFound();
if (!result && null != path && Files.exists(path))
result = walker.find(path, recurse);
return result;
}
public Path get(String name) {
if (null == name || (name = name.trim()).isEmpty())
throw new IllegalArgumentException("Illegal 'name' argument in Finder.get(String): " + name);
return walker.results.get(name);
}
public boolean isFound() {
return walker.results.size() == walker.matchers.size();
}
public boolean test(String name, Path file) {
if (null == name || (name = name.trim()).isEmpty() || !walker.matchers.containsKey(name))
throw new IllegalArgumentException("Illegal 'name' argument in Finder.test(String, Path): " + name);
boolean result = walker.results.containsKey(name);
if (!result && null != file) {
Path found = file.getFileName();
if (null != found && walker.matchers.get(name).matches(found) && Files.isExecutable(file) && check(file, name, walker.version)) {
walker.results.put(name, file);
result = true;
}
}
return result;
}
}