// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.start; import java.io.File; import java.io.IOException; import java.nio.file.FileSystemLoopException; import java.nio.file.FileVisitResult; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class PathFinder extends SimpleFileVisitor<Path> { // internal tracking of prior notified paths (to avoid repeated notification of same ignored path) private static Set<Path> NOTIFIED_PATHS = new HashSet<>(); private boolean includeDirsInResults = false; private Map<String, Path> hits = new HashMap<>(); private Path basePath = null; private PathMatcher dirMatcher = PathMatchers.getNonHidden(); private PathMatcher fileMatcher = PathMatchers.getNonHidden(); private void addHit(Path path) { String relPath = basePath.relativize(path).toString(); StartLog.debug("Found [" + relPath + "] " + path); hits.put(relPath,path); } public PathMatcher getDirMatcher() { return dirMatcher; } public PathMatcher getFileMatcher() { return fileMatcher; } public List<File> getHitList() { List<File> ret = new ArrayList<>(); for (Path path : hits.values()) { ret.add(path.toFile()); } return ret; } public Collection<Path> getHits() { return hits.values(); } public boolean isIncludeDirsInResults() { return includeDirsInResults; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { if (dirMatcher.matches(dir)) { StartLog.trace("Following dir: " + dir); if (includeDirsInResults && fileMatcher.matches(dir)) { addHit(dir); } return FileVisitResult.CONTINUE; } else { StartLog.trace("Skipping dir: " + dir); return FileVisitResult.SKIP_SUBTREE; } } /** * Set the active basePath, used for resolving relative paths. * <p> * When a hit arrives for a subsequent find that has the same relative path as a prior hit, the new hit overrides the prior path as the active hit. * * @param basePath * the basePath to tag all hits with */ public void setBase(Path basePath) { this.basePath = basePath; } public void setDirMatcher(PathMatcher dirMatcher) { this.dirMatcher = dirMatcher; } public void setFileMatcher(PathMatcher fileMatcher) { this.fileMatcher = fileMatcher; } public void setFileMatcher(String pattern) { this.fileMatcher = PathMatchers.getMatcher(pattern); } public void setIncludeDirsInResults(boolean includeDirsInResults) { this.includeDirsInResults = includeDirsInResults; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (fileMatcher.matches(file)) { addHit(file); } else { StartLog.trace("Ignoring file: " + file); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (exc instanceof FileSystemLoopException) { if (!NOTIFIED_PATHS.contains(file)) { StartLog.warn("skipping detected filesystem loop: " + file); NOTIFIED_PATHS.add(file); } return FileVisitResult.SKIP_SUBTREE; } else { StartLog.warn(exc); return super.visitFileFailed(file,exc); } } }