📄 directoryscanner.java
字号:
// put in the newroots map the include patterns without // wildcard tokens for (int i = 0; i < includes.length; i++) { if (FileUtils.isAbsolutePath(includes[i])) { //skip abs. paths not under basedir, if set: if (basedir != null && !SelectorUtils.matchPatternStart(includes[i], basedir.getAbsolutePath(), isCaseSensitive())) { continue; } } else if (basedir == null) { //skip non-abs. paths if basedir == null: continue; } newroots.put(SelectorUtils.rtrimWildcardTokens( includes[i]), includes[i]); } if (newroots.containsKey("") && basedir != null) { // we are going to scan everything anyway scandir(basedir, "", true); } else { // only scan directories that can include matched files or // directories Iterator it = newroots.entrySet().iterator(); File canonBase = null; if (basedir != null) { try { canonBase = basedir.getCanonicalFile(); } catch (IOException ex) { throw new BuildException(ex); } } while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String currentelement = (String) entry.getKey(); if (basedir == null && !FileUtils.isAbsolutePath(currentelement)) { continue; } String originalpattern = (String) entry.getValue(); File myfile = new File(basedir, currentelement); if (myfile.exists()) { // may be on a case insensitive file system. We want // the results to show what's really on the disk, so // we need to double check. try { String path = (basedir == null) ? myfile.getCanonicalPath() : FILE_UTILS.removeLeadingPath(canonBase, myfile.getCanonicalFile()); if (!path.equals(currentelement) || ON_VMS) { myfile = findFile(basedir, currentelement, true); if (myfile != null && basedir != null) { currentelement = FILE_UTILS.removeLeadingPath( basedir, myfile); } } } catch (IOException ex) { throw new BuildException(ex); } } if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) { File f = findFile(basedir, currentelement, false); if (f != null && f.exists()) { // adapt currentelement to the case we've // actually found currentelement = (basedir == null) ? f.getAbsolutePath() : FILE_UTILS.removeLeadingPath(basedir, f); myfile = f; } } if (myfile != null && myfile.exists()) { if (!followSymlinks && isSymlink(basedir, currentelement)) { continue; } if (myfile.isDirectory()) { if (isIncluded(currentelement) && currentelement.length() > 0) { accountForIncludedDir(currentelement, myfile, true); } else { if (currentelement.length() > 0) { if (currentelement.charAt(currentelement .length() - 1) != File.separatorChar) { currentelement = currentelement + File.separatorChar; } } scandir(myfile, currentelement, true); } } else { boolean included = isCaseSensitive() ? originalpattern.equals(currentelement) : originalpattern.equalsIgnoreCase(currentelement); if (included) { accountForIncludedFile(currentelement, myfile); } } } } } } /** * Clear the result caches for a scan. */ protected synchronized void clearResults() { filesIncluded = new Vector(); filesNotIncluded = new Vector(); filesExcluded = new Vector(); filesDeselected = new Vector(); dirsIncluded = new Vector(); dirsNotIncluded = new Vector(); dirsExcluded = new Vector(); dirsDeselected = new Vector(); everythingIncluded = (basedir != null); scannedDirs.clear(); } /** * Top level invocation for a slow scan. A slow scan builds up a full * list of excluded/included files/directories, whereas a fast scan * will only have full results for included files, as it ignores * directories which can't possibly hold any included files/directories. * <p> * Returns immediately if a slow scan has already been completed. */ protected void slowScan() { synchronized (slowScanLock) { if (haveSlowResults) { return; } if (slowScanning) { while (slowScanning) { try { slowScanLock.wait(); } catch (InterruptedException e) { // Empty } } return; } slowScanning = true; } try { synchronized (this) { // set in/excludes to reasonable defaults if needed: boolean nullIncludes = (includes == null); includes = nullIncludes ? new String[] {"**"} : includes; boolean nullExcludes = (excludes == null); excludes = nullExcludes ? new String[0] : excludes; String[] excl = new String[dirsExcluded.size()]; dirsExcluded.copyInto(excl); String[] notIncl = new String[dirsNotIncluded.size()]; dirsNotIncluded.copyInto(notIncl); processSlowScan(excl); processSlowScan(notIncl); clearCaches(); includes = nullIncludes ? null : includes; excludes = nullExcludes ? null : excludes; } } finally { synchronized (slowScanLock) { haveSlowResults = true; slowScanning = false; slowScanLock.notifyAll(); } } } private void processSlowScan(String[] arr) { for (int i = 0; i < arr.length; i++) { if (!couldHoldIncluded(arr[i])) { scandir(new File(basedir, arr[i]), arr[i] + File.separator, false); } } } /** * Scan 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 dir The directory to scan. Must not be <code>null</code>. * @param vpath The path relative to the base directory (needed to * prevent problems with an absolute path when using * dir). Must not be <code>null</code>. * @param fast Whether or not this call is part of a fast scan. * * @see #filesIncluded * @see #filesNotIncluded * @see #filesExcluded * @see #dirsIncluded * @see #dirsNotIncluded * @see #dirsExcluded * @see #slowScan */ protected void scandir(File dir, String vpath, boolean fast) { if (dir == null) { throw new BuildException("dir must not be null."); } String[] newfiles = dir.list(); if (newfiles == null) { if (!dir.exists()) { throw new BuildException(dir + " doesn't exist."); } else if (!dir.isDirectory()) { throw new BuildException(dir + " is not a directory."); } else { throw new BuildException("IO error scanning directory '" + dir.getAbsolutePath() + "'"); } } scandir(dir, vpath, fast, newfiles); } private void scandir(File dir, String vpath, boolean fast, String[] newfiles) { // avoid double scanning of directories, can only happen in fast mode if (fast && hasBeenScanned(vpath)) { return; } if (!followSymlinks) { Vector noLinks = new Vector(); for (int i = 0; i < newfiles.length; i++) { try { if (FILE_UTILS.isSymbolicLink(dir, newfiles[i])) { String name = vpath + newfiles[i]; File file = new File(dir, newfiles[i]); (file.isDirectory() ? dirsExcluded : filesExcluded).addElement(name); } else { noLinks.addElement(newfiles[i]); } } catch (IOException ioe) { String msg = "IOException caught while checking " + "for links, couldn't get canonical path!"; // will be caught and redirected to Ant's logging system System.err.println(msg); noLinks.addElement(newfiles[i]); } } newfiles = (String[]) (noLinks.toArray(new String[noLinks.size()])); } for (int i = 0; i < newfiles.length; i++) { String name = vpath + newfiles[i]; File file = new File(dir, newfiles[i]); String[] children = file.list(); if (children == null) { // probably file if (isIncluded(name)) { accountForIncludedFile(name, file); } else { everythingIncluded = false; filesNotIncluded.addElement(name); } } else { // dir if (isIncluded(name)) { accountForIncludedDir(name, file, fast, children); } else { everythingIncluded = false; dirsNotIncluded.addElement(name); if (fast && couldHoldIncluded(name)) { scandir(file, name + File.separator, fast, children); } } if (!fast) { scandir(file, name + File.separator, fast, children); } } } } /** * Process included file. * @param name path of the file relative to the directory of the FileSet. * @param file included File. */ private void accountForIncludedFile(String name, File file) { processIncluded(name, file, filesIncluded, filesExcluded, filesDeselected); } /** * Process included directory. * @param name path of the directory relative to the directory of * the FileSet. * @param file directory as File. * @param fast whether to perform fast scans. */ private void accountForIncludedDir(String name, File file, boolean fast) { processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected); if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) { scandir(file, name + File.separator, fast); } } private void accountForIncludedDir(String name, File file, boolean fast, String[] children) { processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected); if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) { scandir(file, name + File.separator, fast, children); } } private void processIncluded(String name, File file, Vector inc, Vector exc, Vector des) { if (inc.contains(name) || exc.contains(name) || des.contains(name)) { return; } boolean included = false; if (isExcluded(name)) { exc.add(name); } else if (isSelected(name, file)) { included = true; inc.add(name); } else { des.add(name); } everythingIncluded &= included; } /** * Test whether or not a name matches against at least one include * pattern. * * @param name The name to match. Must not be <code>null</code>. * @return <code>true</code> when the name matches against at least one * include pattern, or <code>false</code> otherwise. */ protected boolean isIncluded(String name) { ensureNonPatternSetsReady(); if (isCaseSensitive() ? includeNonPatterns.contains(name) : includeNonPatterns.contains(name.toUpperCase())) { return true; } for (int i = 0; i < includePatterns.length; i++) { if (matchPath(includePatterns[i], name, isCaseSensitive())) { return true; } } return false; } /** * Test whether or not a name matches the start of at least one include * pattern. * * @param name The name to match. Must not be <code>null</code>. * @return <code>true</code> when the name matches against the start of at * least one include pattern, or <code>false</code> otherwise. */ protected boolean couldHoldIncluded(String name) { for (int i = 0; i < includes.length; i++) { if (matchPatternStart(includes[i], name, isCaseSensitive()) && isMorePowerfulThanExcludes(name, includes[i]) && isDeeper(includes[i], name)) { return true; } } return false; } /** * Verify that a pattern specifies files deeper * than the level of the specified file. * @param pattern the pattern to check. * @param name the name to check. * @return whether the pattern is deeper than the name. * @since Ant 1.6.3 */ private boolean isDeeper(String pattern, String name) { Vector p = SelectorUtils.tokenizePath(pattern); Vector n = SelectorUtils.tokenizePath(name); return p.contains("**") || p.size() > n.size(); } /** * Find out whether one particular include pattern is more powerful * than all the excludes. * Note: the power comparison is based on the length of the include pattern * and of the exclude patterns without the wildcards. * Ideally the comparison should be done based on the depth * of the match; that is to say how many file separators have been matched * before the first ** or the end of the pattern. * * IMPORTANT : this function should return false "with care". * * @param name the relative path to test. * @param includepattern one include pattern. * @return true if there is no exclude pattern more powerful than this include pattern. * @since Ant 1.6 */ private boolean isMorePowerfulThanExcludes(String name, String includepattern) { String soughtexclude = name + File.separator + "**"; for (int counter = 0; counter < excludes.length; counter++) { if (excludes[counter].equals(soughtexclude)) { return false; } } return true; } /** * Test whether all contents of the specified directory must be excluded. * @param name the directory name to check. * @return whether all the specified directory's contents are excluded. */ private boolean contentsExcluded(String name) { name = (name.endsWith(File.separator)) ? name : name + File.separator; for (int i = 0; i < excludes.length; i++) { String e = excludes[i]; if (e.endsWith("**") && SelectorUtils.matchPath( e.substring(0, e.length() - 2), name, isCaseSensitive())) { return true; } } return false; } /** * Test whether or not a name matches against at least one exclude * pattern. * * @param name The name to match. Must not be <code>null</code>. * @return <code>true</code> when the name matches against at least one
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -