All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.common.util.io.DirectoryScanner Maven / Gradle / Ivy

There is a newer version: 2.4.1.Final
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.sshd.common.util.io;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Objects;
import java.util.function.Supplier;

import org.apache.sshd.common.util.GenericUtils;

/**
 * 

* Class for scanning a directory for files/directories which match certain criteria. *

* *

* These criteria consist of selectors and patterns which have been specified. With the selectors you can select which * files you want to have included. Files which are not selected are excluded. With patterns you can include or exclude * files based on their filename. *

* *

* The idea is simple. A given directory is recursively scanned for all files and directories. Each file/directory is * matched against a set of selectors, including special support for matching against filenames with include and and * exclude patterns. Only files/directories which match at least one pattern of the include pattern list or other file * selector, and don't match any pattern of the exclude pattern list or fail to match against a required selector will * be placed in the list of files/directories found. *

* *

* When no list of include patterns is supplied, "**" will be used, which means that everything will be matched. When no * list of exclude patterns is supplied, an empty list is used, such that nothing will be excluded. When no selectors * are supplied, none are applied. *

* *

* The filename pattern matching is done as follows: The name to be matched is split up in path segments. A path segment * is the name of a directory or file, which is bounded by File.separator ('/' under UNIX, '\' under * Windows). For example, "abc/def/ghi/xyz.java" is split up in the segments "abc", "def","ghi" and "xyz.java". The same * is done for the pattern against which should be matched. *

* *

* The segments of the name and the pattern are then matched against each other. When '**' is used for a path segment in * the pattern, it matches zero or more path segments of the name. *

* *

* There is a special case regarding the use of File.separators at the beginning of the pattern and the * string to match:
* When a pattern starts with a File.separator, the string to match must also start with a * File.separator. When a pattern does not start with a File.separator, the string to match * may not start with a File.separator. When one of these rules is not obeyed, the string will not match. *

* *

* When a name path segment is matched against a pattern path segment, the following special characters can be used:
* '*' matches zero or more characters
* '?' matches one character. *

* *

* Examples:
* "**\*.class" matches all .class files/dirs in a directory tree.
* "test\a??.java" matches all files/dirs which start with an 'a', then two more characters and then * ".java", in a directory called test.
* "**" matches everything in a directory tree.
* "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where there is a parent * directory called test (e.g. "abc\test\def\ghi\XYZ123"). *

* *

* Case sensitivity may be turned off if necessary. By default, it is turned on. *

* *

* Example of usage: *

* *
 * String[] includes = { "**\\*.class" };
 * String[] excludes = { "modules\\*\\**" };
 * ds.setIncludes(includes);
 * ds.setExcludes(excludes);
 * ds.setBasedir(new File("test"));
 * ds.setCaseSensitive(true);
 * ds.scan();
 *
 * System.out.println("FILES:");
 * String[] files = ds.getIncludedFiles();
 * for (int i = 0; i < files.length; i++) {
 *     System.out.println(files[i]);
 * }
 * 
*

* This will scan a directory called test for .class files, but excludes all files in all proper subdirectories of a * directory called "modules". *

* * @author Arnout J. Kuiper [email protected] * @author Magesh Umasankar * @author Bruce Atherton * @author Antoine Levy-Lambert */ public class DirectoryScanner extends PathScanningMatcher { /** * The base directory to be scanned. */ protected Path basedir; public DirectoryScanner() { super(); } public DirectoryScanner(Path dir) { this(dir, Collections.emptyList()); } public DirectoryScanner(Path dir, String... includes) { this(dir, GenericUtils.isEmpty(includes) ? Collections.emptyList() : Arrays.asList(includes)); } public DirectoryScanner(Path dir, Collection includes) { setBasedir(dir); setIncludes(includes); } /** * Sets the base directory to be scanned. This is the directory which is scanned recursively. * * @param basedir The base directory for scanning. Should not be {@code null}. */ public void setBasedir(Path basedir) { this.basedir = Objects.requireNonNull(basedir, "No base directory provided"); } /** * Returns the base directory to be scanned. This is the directory which is scanned recursively. * * @return the base directory to be scanned */ public Path getBasedir() { return basedir; } /** * Scans the base directory for files which match at least one include pattern and don't match any exclude patterns. * If there are selectors then the files must pass muster there, as well. * * @return the matching files * @throws IllegalStateException if the base directory was set incorrectly (i.e. if it is {@code null}, doesn't * exist, or isn't a directory). * @throws IOException if failed to scan the directory (e.g., access denied) */ public Collection scan() throws IOException, IllegalStateException { return scan(LinkedList::new); } public > C scan(Supplier factory) throws IOException, IllegalStateException { Path dir = getBasedir(); if (dir == null) { throw new IllegalStateException("No basedir set"); } if (!Files.exists(dir)) { throw new IllegalStateException("basedir " + dir + " does not exist"); } if (!Files.isDirectory(dir)) { throw new IllegalStateException("basedir " + dir + " is not a directory"); } if (GenericUtils.isEmpty(getIncludes())) { throw new IllegalStateException("No includes set for " + dir); } FileSystem fs = dir.getFileSystem(); String fsSep = fs.getSeparator(); String curSep = getSeparator(); if (!Objects.equals(fsSep, curSep)) { throw new IllegalStateException("Mismatched separator - expected=" + curSep + ", actual=" + fsSep); } return scandir(dir, dir, factory.get()); } /** * Scans the given directory for files and directories. Found files and directories are placed in their respective * collections, based on the matching of includes, excludes, and the selectors. When a directory is found, it is * scanned recursively. * * @param Target matches collection type * @param rootDir The directory to scan. Must not be {@code null}. * @param dir The path relative to the root directory (needed to prevent problems with an absolute path * when using dir). Must not be {@code null}. * @param filesList Target {@link Collection} to accumulate the relative path matches * @return Updated files list * @throws IOException if failed to scan the directory */ protected > C scandir(Path rootDir, Path dir, C filesList) throws IOException { try (DirectoryStream ds = Files.newDirectoryStream(dir)) { for (Path p : ds) { Path rel = rootDir.relativize(p); String name = rel.toString(); if (Files.isDirectory(p)) { if (isIncluded(name)) { filesList.add(p); scandir(rootDir, p, filesList); } else if (couldHoldIncluded(name)) { scandir(rootDir, p, filesList); } } else if (Files.isRegularFile(p)) { if (isIncluded(name)) { filesList.add(p); } } } } return filesList; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy