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@443: * - Specify folder to get all files in there included, but no subdirs
tikhomirov@443: *
- Specify folder to get all files and files in subdirectories included
tikhomirov@443: *
- Specify exact set files (with option to accept or not paths leading to them)
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: }