tikhomirov@229: /* tikhomirov@443: * Copyright (c) 2011-2012 TMate Software Ltd tikhomirov@229: * tikhomirov@229: * This program is free software; you can redistribute it and/or modify tikhomirov@229: * it under the terms of the GNU General Public License as published by tikhomirov@229: * the Free Software Foundation; version 2 of the License. tikhomirov@229: * tikhomirov@229: * This program is distributed in the hope that it will be useful, tikhomirov@229: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@229: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@229: * GNU General Public License for more details. tikhomirov@229: * tikhomirov@229: * For information on how to redistribute this software under tikhomirov@229: * the terms of a license other than GNU General Public License tikhomirov@229: * contact TMate Software at support@hg4j.com tikhomirov@229: */ tikhomirov@229: package org.tmatesoft.hg.internal; tikhomirov@229: tikhomirov@443: import static org.tmatesoft.hg.util.Path.CompareResult.*; tikhomirov@443: tikhomirov@229: import java.util.ArrayList; tikhomirov@229: tikhomirov@443: import org.tmatesoft.hg.util.FileIterator; tikhomirov@229: import org.tmatesoft.hg.util.Path; tikhomirov@443: import org.tmatesoft.hg.util.Path.CompareResult; tikhomirov@229: tikhomirov@229: /** tikhomirov@443: * tikhomirov@229: * @author Artem Tikhomirov tikhomirov@229: * @author TMate Software Ltd. tikhomirov@229: */ tikhomirov@229: public class PathScope implements Path.Matcher { tikhomirov@229: private final Path[] files; tikhomirov@229: private final Path[] dirs; tikhomirov@443: private final boolean includeNestedDirs; tikhomirov@443: private final boolean includeParentDirs; tikhomirov@443: private final boolean includeDirContent; tikhomirov@443: tikhomirov@443: /** tikhomirov@443: * See {@link PathScope#PathScope(boolean, boolean, Path...)} tikhomirov@443: */ tikhomirov@443: public PathScope(boolean recursiveDirs, Path... paths) { tikhomirov@443: this(true, recursiveDirs, true, paths); tikhomirov@443: } tikhomirov@229: tikhomirov@443: /** tikhomirov@443: * With matchParentDirs, recursiveDirs and matchDirContent set to false, tikhomirov@443: * this scope matches only exact paths specified. tikhomirov@443: *

tikhomirov@443: * With matchParentDirs set to true, parent directories for files and folders listed in tikhomirov@443: * the paths would get accepted as well (handy for {@link FileIterator FileIterators}). tikhomirov@443: * Note, if supplied path lists a file, parent directory for the file is not matched unless matchParentDirs tikhomirov@443: * is true. To match file's immediate parent without matching all other parents up to the root, just add file parent tikhomirov@443: * along with the file to paths. tikhomirov@443: *

tikhomirov@443: * With recursiveDirs set to true, subdirectories (with files) of directories listed in paths would tikhomirov@443: * be matched as well. Similar to `a/b/**` tikhomirov@443: *

tikhomirov@443: * With matchDirContent set to true, files right under any directory listed in path would be matched. tikhomirov@443: * Similar to `a/b/*`. Makes little sense to set to false when recursiceDirs is true, although may still tikhomirov@443: * be useful in certain scenarios, e.g. PathScope(false, true, false, "a/") matches files under "a/b/*" and "a/b/c/*", but not files "a/*". tikhomirov@443: * tikhomirov@443: * @param matchParentDirs true to accept parent dirs of supplied paths tikhomirov@443: * @param recursiveDirs true to include subdirectories and files of supplied paths tikhomirov@443: * @param includeDirContent tikhomirov@443: * @param paths files and folders to match tikhomirov@443: */ tikhomirov@443: public PathScope(boolean matchParentDirs, boolean recursiveDirs, boolean matchDirContent, Path... paths) { tikhomirov@229: if (paths == null) { tikhomirov@229: throw new IllegalArgumentException(); tikhomirov@229: } tikhomirov@443: includeParentDirs = matchParentDirs; tikhomirov@443: includeNestedDirs = recursiveDirs; tikhomirov@443: includeDirContent = matchDirContent; tikhomirov@229: ArrayList f = new ArrayList(5); tikhomirov@229: ArrayList d = new ArrayList(5); tikhomirov@229: for (Path p : paths) { tikhomirov@229: if (p.isDirectory()) { tikhomirov@229: d.add(p); tikhomirov@229: } else { tikhomirov@229: f.add(p); tikhomirov@229: } tikhomirov@229: } tikhomirov@229: files = f.toArray(new Path[f.size()]); tikhomirov@229: dirs = d.toArray(new Path[d.size()]); tikhomirov@229: } tikhomirov@229: tikhomirov@229: public boolean accept(Path path) { tikhomirov@229: if (path.isDirectory()) { tikhomirov@443: // either equals to or a parent of a directory we know about (i.e. configured dir is *nested* in supplied arg). tikhomirov@443: // Also, accept arg if it happened to be nested into configured dir (i.e. one of them is *parent* for the arg), tikhomirov@443: // and recursiveDirs is true. tikhomirov@229: for (Path d : dirs) { tikhomirov@229: switch(d.compareWith(path)) { tikhomirov@229: case Same : return true; tikhomirov@443: case ImmediateChild : tikhomirov@443: case Nested : return includeParentDirs; // path is parent to one of our locations tikhomirov@443: case ImmediateParent : tikhomirov@443: case Parent : return includeNestedDirs; // path is nested in one of our locations tikhomirov@229: } tikhomirov@229: } tikhomirov@443: if (!includeParentDirs) { tikhomirov@443: return false; tikhomirov@443: } tikhomirov@443: // If one of configured files is nested under the path, and we shall report parents, accept. tikhomirov@443: // Note, I don't respect includeDirContent here as with file it's easy to add parent to paths explicitly, if needed. tikhomirov@443: // (if includeDirContent == .f and includeParentDirs == .f, directory than owns a scope file won't get reported) tikhomirov@229: for (Path f : files) { tikhomirov@443: CompareResult cr = f.compareWith(path); tikhomirov@443: if (cr == Nested || cr == ImmediateChild) { tikhomirov@229: return true; tikhomirov@229: } tikhomirov@229: } tikhomirov@229: } else { tikhomirov@229: for (Path f : files) { tikhomirov@229: if (f.equals(path)) { tikhomirov@229: return true; tikhomirov@229: } tikhomirov@229: } tikhomirov@443: // if interested in nested/recursive dirs, shall check if supplied file is under any of our configured locations tikhomirov@443: if (!includeNestedDirs && !includeDirContent) { tikhomirov@443: return false; tikhomirov@443: } tikhomirov@443: for (Path d : dirs) { tikhomirov@443: CompareResult cr = d.compareWith(path); tikhomirov@443: if (includeNestedDirs && cr == Parent) { tikhomirov@443: // file is nested in one of our locations tikhomirov@443: return true; tikhomirov@443: } tikhomirov@443: if (includeDirContent && cr == ImmediateParent) { tikhomirov@443: // file is right under one of our directories, and includeDirContents is .t tikhomirov@443: return true; tikhomirov@443: } tikhomirov@443: // try another directory tikhomirov@443: } tikhomirov@229: } tikhomirov@229: return false; tikhomirov@229: } tikhomirov@229: }