Return-Path: Delivered-To: apmail-ant-notifications-archive@locus.apache.org Received: (qmail 18476 invoked from network); 17 Sep 2008 15:11:51 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 17 Sep 2008 15:11:51 -0000 Received: (qmail 28718 invoked by uid 500); 17 Sep 2008 15:11:48 -0000 Delivered-To: apmail-ant-notifications-archive@ant.apache.org Received: (qmail 28702 invoked by uid 500); 17 Sep 2008 15:11:48 -0000 Mailing-List: contact notifications-help@ant.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ant.apache.org Delivered-To: mailing list notifications@ant.apache.org Received: (qmail 28693 invoked by uid 99); 17 Sep 2008 15:11:48 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 17 Sep 2008 08:11:48 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 17 Sep 2008 15:10:58 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 97973238896B; Wed, 17 Sep 2008 08:11:30 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r696336 - in /ant/core/trunk/src/main/org/apache/tools/ant: DirectoryScanner.java types/selectors/SelectorUtils.java types/selectors/TokenizedPath.java types/selectors/TokenizedPattern.java Date: Wed, 17 Sep 2008 15:11:29 -0000 To: notifications@ant.apache.org From: bodewig@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080917151130.97973238896B@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: bodewig Date: Wed Sep 17 08:11:28 2008 New Revision: 696336 URL: http://svn.apache.org/viewvc?rev=696336&view=rev Log: avoid redundant tokenization. this is almost complete except for non-wildcard include patterns, will take care of them next. Modified: ant/core/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPath.java ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPattern.java Modified: ant/core/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java?rev=696336&r1=696335&r2=696336&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java Wed Sep 17 08:11:28 2008 @@ -860,8 +860,8 @@ throw illegal; } } - if (isIncluded("")) { - if (!isExcluded("")) { + if (isIncluded(TokenizedPath.EMPTY_PATH)) { + if (!isExcluded(TokenizedPath.EMPTY_PATH)) { if (isSelected("", basedir)) { dirsIncluded.addElement(""); } else { @@ -997,19 +997,11 @@ continue; } if (myfile.isDirectory()) { - if (isIncluded(currentelement) + if (isIncluded(currentPath) && currentelement.length() > 0) { - accountForIncludedDir(currentelement, myfile, true); + accountForIncludedDir(currentPath, myfile, true); } else { - if (currentelement.length() > 0) { - if (currentelement.charAt(currentelement - .length() - 1) - != File.separatorChar) { - currentelement = - currentelement + File.separatorChar; - } - } - scandir(myfile, currentelement, true); + scandir(myfile, currentPath, true); } } else { String originalpattern = (String) entry.getValue(); @@ -1017,7 +1009,7 @@ ? originalpattern.equals(currentelement) : originalpattern.equalsIgnoreCase(currentelement); if (included) { - accountForIncludedFile(currentelement, myfile); + accountForIncludedFile(currentPath, myfile); } } } @@ -1099,9 +1091,9 @@ 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); + TokenizedPath path = new TokenizedPath(arr[i]); + if (!couldHoldIncluded(path)) { + scandir(new File(basedir, arr[i]), path, false); } } } @@ -1127,6 +1119,30 @@ * @see #slowScan */ protected void scandir(File dir, String vpath, boolean fast) { + scandir(dir, new TokenizedPath(vpath), fast); + } + + /** + * 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 null. + * @param path The path relative to the base directory (needed to + * prevent problems with an absolute path when using + * dir). Must not be null. + * @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 + */ + private void scandir(File dir, TokenizedPath path, boolean fast) { if (dir == null) { throw new BuildException("dir must not be null."); } @@ -1141,11 +1157,16 @@ + dir.getAbsolutePath() + "'"); } } - scandir(dir, vpath, fast, newfiles, new LinkedList()); + scandir(dir, path, fast, newfiles, new LinkedList()); } - private void scandir(File dir, String vpath, boolean fast, + private void scandir(File dir, TokenizedPath path, boolean fast, String[] newfiles, LinkedList directoryNamesFollowed) { + String vpath = path.toString(); + if (vpath.length() > 0 && !vpath.endsWith(File.separator)) { + vpath += File.separator; + } + // avoid double scanning of directories, can only happen in fast mode if (fast && hasBeenScanned(vpath)) { return; @@ -1177,11 +1198,12 @@ for (int i = 0; i < newfiles.length; i++) { String name = vpath + newfiles[i]; + TokenizedPath newPath = new TokenizedPath(path, newfiles[i]); File file = new File(dir, newfiles[i]); String[] children = list(file); if (children == null) { // probably file - if (isIncluded(name)) { - accountForIncludedFile(name, file); + if (isIncluded(newPath)) { + accountForIncludedFile(newPath, file); } else { everythingIncluded = false; filesNotIncluded.addElement(name); @@ -1199,20 +1221,19 @@ continue; } - if (isIncluded(name)) { - accountForIncludedDir(name, file, fast, children, + if (isIncluded(newPath)) { + accountForIncludedDir(newPath, file, fast, children, directoryNamesFollowed); } else { everythingIncluded = false; dirsNotIncluded.addElement(name); - if (fast && couldHoldIncluded(name)) { - scandir(file, name + File.separator, fast, children, + if (fast && couldHoldIncluded(newPath)) { + scandir(file, newPath, fast, children, directoryNamesFollowed); } } if (!fast) { - scandir(file, name + File.separator, fast, children, - directoryNamesFollowed); + scandir(file, newPath, fast, children, directoryNamesFollowed); } } } @@ -1227,7 +1248,7 @@ * @param name path of the file relative to the directory of the FileSet. * @param file included File. */ - private void accountForIncludedFile(String name, File file) { + private void accountForIncludedFile(TokenizedPath name, File file) { processIncluded(name, file, filesIncluded, filesExcluded, filesDeselected); } @@ -1239,32 +1260,34 @@ * @param file directory as File. * @param fast whether to perform fast scans. */ - private void accountForIncludedDir(String name, File file, boolean fast) { + private void accountForIncludedDir(TokenizedPath name, File file, + boolean fast) { processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected); if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) { - scandir(file, name + File.separator, fast); + scandir(file, name, fast); } } - private void accountForIncludedDir(String name, File file, boolean fast, + private void accountForIncludedDir(TokenizedPath name, + File file, boolean fast, String[] children, LinkedList directoryNamesFollowed) { processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected); if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) { - scandir(file, name + File.separator, fast, children, - directoryNamesFollowed); + scandir(file, name, fast, children, directoryNamesFollowed); } } - private void processIncluded(String name, File file, Vector inc, - Vector exc, Vector des) { - + private void processIncluded(TokenizedPath path, + File file, Vector inc, Vector exc, + Vector des) { + String name = path.toString(); if (inc.contains(name) || exc.contains(name) || des.contains(name)) { return; } boolean included = false; - if (isExcluded(name)) { + if (isExcluded(path)) { exc.add(name); } else if (isSelected(name, file)) { included = true; @@ -1284,15 +1307,27 @@ * include pattern, or false otherwise. */ protected boolean isIncluded(String name) { + return isIncluded(new TokenizedPath(name)); + } + + /** + * Test whether or not a name matches against at least one include + * pattern. + * + * @param name The name to match. Must not be null. + * @return true when the name matches against at least one + * include pattern, or false otherwise. + */ + private boolean isIncluded(TokenizedPath path) { ensureNonPatternSetsReady(); if (isCaseSensitive() - ? includeNonPatterns.contains(name) - : includeNonPatterns.contains(name.toUpperCase())) { + ? includeNonPatterns.contains(path.toString()) + : includeNonPatterns.contains(path.toString().toUpperCase())) { return true; } for (int i = 0; i < includePatterns.length; i++) { - if (includePatterns[i].matchPath(name, isCaseSensitive())) { + if (includePatterns[i].matchPath(path, isCaseSensitive())) { return true; } } @@ -1308,12 +1343,29 @@ * least one include pattern, or false otherwise. */ protected boolean couldHoldIncluded(String name) { - final TokenizedPath tokenizedName = new TokenizedPath(name); + return couldHoldIncluded(new TokenizedPath(name)); + } + + /** + * Test whether or not a name matches the start of at least one include + * pattern. + * + * @param tokenizedName The name to match. Must not be null. + * @return true when the name matches against the start of at + * least one include pattern, or false otherwise. + */ + private boolean couldHoldIncluded(TokenizedPath tokenizedName) { + int wildCardCount = 0; for (int i = 0; i < includes.length; i++) { - TokenizedPattern tokenizedInclude = - new TokenizedPattern(includes[i]); + TokenizedPattern tokenizedInclude; + boolean wildcard = SelectorUtils.hasWildcards(includes[i]); + if (wildcard) { + tokenizedInclude = includePatterns[wildCardCount++]; + } else { + tokenizedInclude = new TokenizedPattern(includes[i]); + } if (tokenizedInclude.matchStartOf(tokenizedName, isCaseSensitive()) - && isMorePowerfulThanExcludes(name, includes[i]) + && isMorePowerfulThanExcludes(tokenizedName.toString()) && isDeeper(tokenizedInclude, tokenizedName)) { return true; } @@ -1346,17 +1398,15 @@ * 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) { + private boolean isMorePowerfulThanExcludes(String name) { final String soughtexclude = name + File.separatorChar + SelectorUtils.DEEP_TREE_MATCH; - for (int counter = 0; counter < excludes.length; counter++) { - if (excludes[counter].equals(soughtexclude)) { + for (int counter = 0; counter < excludePatterns.length; counter++) { + if (excludePatterns[counter].toString().equals(soughtexclude)) { return false; } } @@ -1365,16 +1415,14 @@ /** * Test whether all contents of the specified directory must be excluded. - * @param name the directory name to check. + * @param path the path 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.DEEP_TREE_MATCH) - && SelectorUtils.matchPath(e.substring(0, e.length() - 2), - name, isCaseSensitive())) { + private boolean contentsExcluded(TokenizedPath path) { + for (int i = 0; i < excludePatterns.length; i++) { + if (excludePatterns[i].endsWith(SelectorUtils.DEEP_TREE_MATCH) + && excludePatterns[i].withoutLastToken() + .matchPath(path, isCaseSensitive())) { return true; } } @@ -1390,11 +1438,23 @@ * exclude pattern, or false otherwise. */ protected boolean isExcluded(String name) { + return isExcluded(new TokenizedPath(name)); + } + + /** + * Test whether or not a name matches against at least one exclude + * pattern. + * + * @param name The name to match. Must not be null. + * @return true when the name matches against at least one + * exclude pattern, or false otherwise. + */ + private boolean isExcluded(TokenizedPath name) { ensureNonPatternSetsReady(); if (isCaseSensitive() - ? excludeNonPatterns.contains(name) - : excludeNonPatterns.contains(name.toUpperCase())) { + ? excludeNonPatterns.contains(name.toString()) + : excludeNonPatterns.contains(name.toString().toUpperCase())) { return true; } for (int i = 0; i < excludePatterns.length; i++) { Modified: ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java?rev=696336&r1=696335&r2=696336&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java Wed Sep 17 08:11:28 2008 @@ -216,12 +216,21 @@ } /** - * Core implementation of matchPath. It is isolated so that it can be called from - * PathPattern. + * Core implementation of matchPath. It is isolated so that it + * can be called from TokenizedPattern. */ - static boolean matchPath(String[] tokenizedPattern, String str, boolean isCaseSensitive) { - String[] strDirs = tokenizePathAsArray(str); + static boolean matchPath(String[] tokenizedPattern, String str, + boolean isCaseSensitive) { + return matchPath(tokenizedPattern, tokenizePathAsArray(str), + isCaseSensitive); + } + /** + * Core implementation of matchPath. It is isolated so that it + * can be called from TokenizedPattern. + */ + static boolean matchPath(String[] tokenizedPattern, String[] strDirs, + boolean isCaseSensitive) { int patIdxStart = 0; int patIdxEnd = tokenizedPattern.length - 1; int strIdxStart = 0; Modified: ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPath.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPath.java?rev=696336&r1=696335&r2=696336&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPath.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPath.java Wed Sep 17 08:11:28 2008 @@ -54,6 +54,26 @@ this(path, SelectorUtils.tokenizePathAsArray(path)); } + /** + * Creates a new path as a child of another path. + * + * @param parent the parent path + * @param child the child, must not contain the file separator + */ + public TokenizedPath(TokenizedPath parent, String child) { + if (parent.path.length() > 0 + && parent.path.charAt(parent.path.length() - 1) + != File.separatorChar) { + path = parent.path + File.separatorChar + child; + } else { + path = parent.path + child; + } + tokenizedPath = new String[parent.tokenizedPath.length + 1]; + System.arraycopy(parent.tokenizedPath, 0, tokenizedPath, 0, + parent.tokenizedPath.length); + tokenizedPath[parent.tokenizedPath.length] = child; + } + /* package */ TokenizedPath(String path, String[] tokens) { this.path = path; this.tokenizedPath = tokens; Modified: ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPattern.java URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPattern.java?rev=696336&r1=696335&r2=696336&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPattern.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/types/selectors/TokenizedPattern.java Wed Sep 17 08:11:28 2008 @@ -31,6 +31,12 @@ */ public class TokenizedPattern { + /** + * Instance that holds no tokens at all. + */ + public static final TokenizedPattern EMPTY_PATTERN = + new TokenizedPattern("", new String[0]); + private final String pattern; private final String tokenizedPattern[]; @@ -77,6 +83,22 @@ } /** + * Tests whether or not a given path matches a given pattern. + * + * @param str The path to match, as a String. Must not be + * null. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * @return true if the pattern matches against the string, + * or false otherwise. + */ + public boolean matchPath(TokenizedPath path, boolean isCaseSensitive) { + return SelectorUtils.matchPath(tokenizedPattern, path.getTokens(), + isCaseSensitive); + } + + /** * Tests whether or not this pattern matches the start of * a path. */ @@ -153,4 +175,31 @@ System.arraycopy(tokenizedPattern, 0, newPats, 0, newLen); return new TokenizedPath(sb.toString(), newPats); } + + /** + * true if the last token equals the given string. + */ + public boolean endsWith(String s) { + return tokenizedPattern.length > 0 + && tokenizedPattern[tokenizedPattern.length - 1].equals(s); + } + + /** + * Returns a new pattern without the last token of this pattern. + */ + public TokenizedPattern withoutLastToken() { + if (tokenizedPattern.length == 0) { + throw new IllegalStateException("cant strip a token from nothing"); + } else if (tokenizedPattern.length == 1) { + return EMPTY_PATTERN; + } else { + String toStrip = tokenizedPattern[tokenizedPattern.length - 1]; + int index = pattern.lastIndexOf(toStrip); + String[] tokens = new String[tokenizedPattern.length - 1]; + System.arraycopy(tokenizedPattern, 0, tokens, 0, + tokenizedPattern.length - 1); + return new TokenizedPattern(pattern.substring(0, index), tokens); + } + } + }