You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by bo...@apache.org on 2008/09/17 17:11:29 UTC

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

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 <code>null</code>.
+     * @param path 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
+     */
+    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 <code>false</code> 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 <code>null</code>.
+     * @return <code>true</code> when the name matches against at least one
+     *         include pattern, or <code>false</code> 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 <code>false</code> 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 <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.
+     */
+    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 <code>false</code> 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 <code>null</code>.
+     * @return <code>true</code> when the name matches against at least one
+     *         exclude pattern, or <code>false</code> 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
+     *                <code>null</code>.
+     * @param isCaseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     * @return <code>true</code> if the pattern matches against the string,
+     *         or <code>false</code> 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);
+        }
+    }
+        
 }