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 15:52:41 UTC

svn commit: r696298 - 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 06:52:40 2008
New Revision: 696298

URL: http://svn.apache.org/viewvc?rev=696298&view=rev
Log:
avoid some tokenization (should really pay of in the next iteration/s) and replace recursion with iteration in findFile/isSymLink - right now we lose memoization of File.list but I'll reintroduce this later.

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=696298&r1=696297&r2=696298&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 06:52:40 2008
@@ -186,12 +186,6 @@
     /** Helper. */
     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
 
-    /** iterations for case-sensitive scanning. */
-    private static final boolean[] CS_SCAN_ONLY = new boolean[] {true};
-
-    /** iterations for non-case-sensitive scanning. */
-    private static final boolean[] CS_THEN_NON_CS = new boolean[] {true, false};
-
     /**
      * Patterns which should be excluded by default.
      *
@@ -901,25 +895,39 @@
      * @since Ant 1.6
      */
     private void checkIncludePatterns() {
+        ensureNonPatternSetsReady();
         Map newroots = new HashMap();
         // put in the newroots map the include patterns without
         // wildcard tokens
+        int wildcardPatternIndex = 0;
         for (int i = 0; i < includes.length; i++) {
+            boolean wildcards = SelectorUtils.hasWildcards(includes[i]);
             if (FileUtils.isAbsolutePath(includes[i])) {
                 //skip abs. paths not under basedir, if set:
                 if (basedir != null
                     && !SelectorUtils.matchPatternStart(includes[i],
                     basedir.getAbsolutePath(), isCaseSensitive())) {
+                    if (wildcards) {
+                        wildcardPatternIndex++;
+                    }
                     continue;
                 }
             } else if (basedir == null) {
                 //skip non-abs. paths if basedir == null:
+                if (wildcards) {
+                    wildcardPatternIndex++;
+                }
                 continue;
             }
-            newroots.put(SelectorUtils.rtrimWildcardTokens(
-                includes[i]), includes[i]);
+            if (wildcards) {
+                newroots.put(includePatterns[wildcardPatternIndex++]
+                             .rtrimWildcardTokens(), includes[i]);
+            } else {
+                newroots.put(new TokenizedPath(includes[i]), includes[i]);
+            }
         }
-        if (newroots.containsKey("") && basedir != null) {
+        if (newroots.containsKey(TokenizedPath.EMPTY_PATH)
+            && basedir != null) {
             // we are going to scan everything anyway
             scandir(basedir, "", true);
         } else {
@@ -937,12 +945,12 @@
             }
             while (it.hasNext()) {
                 Map.Entry entry = (Map.Entry) it.next();
-                String currentelement = (String) entry.getKey();
+                TokenizedPath currentPath = (TokenizedPath) entry.getKey();
+                String currentelement = currentPath.toString();
                 if (basedir == null
                     && !FileUtils.isAbsolutePath(currentelement)) {
                     continue;
                 }
-                String originalpattern = (String) entry.getValue();
                 File myfile = new File(basedir, currentelement);
 
                 if (myfile.exists()) {
@@ -955,18 +963,24 @@
                             : FILE_UTILS.removeLeadingPath(canonBase,
                                          getCanonicalFile(myfile));
                         if (!path.equals(currentelement) || ON_VMS) {
-                            myfile = findFile(basedir, currentelement, true);
+                            myfile = currentPath.findFile(basedir, true);
                             if (myfile != null && basedir != null) {
                                 currentelement = FILE_UTILS.removeLeadingPath(
                                     basedir, myfile);
+                                if (!currentPath.toString()
+                                    .equals(currentelement)) {
+                                    currentPath =
+                                        new TokenizedPath(currentelement);
+                                }
                             }
                         }
                     } catch (IOException ex) {
                         throw new BuildException(ex);
                     }
                 }
+
                 if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) {
-                    File f = findFile(basedir, currentelement, false);
+                    File f = currentPath.findFile(basedir, false);
                     if (f != null && f.exists()) {
                         // adapt currentelement to the case we've
                         // actually found
@@ -974,11 +988,12 @@
                             ? f.getAbsolutePath()
                             : FILE_UTILS.removeLeadingPath(basedir, f);
                         myfile = f;
+                        currentPath = new TokenizedPath(currentelement);
                     }
                 }
+
                 if (myfile != null && myfile.exists()) {
-                    if (!followSymlinks
-                        && isSymlink(basedir, currentelement)) {
+                    if (!followSymlinks && currentPath.isSymlink(basedir)) {
                         continue;
                     }
                     if (myfile.isDirectory()) {
@@ -997,6 +1012,7 @@
                             scandir(myfile, currentelement, true);
                         }
                     } else {
+                        String originalpattern = (String) entry.getValue();
                         boolean included = isCaseSensitive()
                             ? originalpattern.equals(currentelement)
                             : originalpattern.equalsIgnoreCase(currentelement);
@@ -1642,110 +1658,6 @@
     }
 
     /**
-     * From <code>base</code> traverse the filesystem in order to find
-     * a file that matches the given name.
-     *
-     * @param base base File (dir).
-     * @param path file path.
-     * @param cs whether to scan case-sensitively.
-     * @return File object that points to the file in question or null.
-     *
-     * @since Ant 1.6.3
-     */
-    private File findFile(File base, String path, boolean cs) {
-        if (FileUtils.isAbsolutePath(path)) {
-            if (base == null) {
-                String[] s = FILE_UTILS.dissect(path);
-                base = new File(s[0]);
-                path = s[1];
-            } else {
-                File f = FILE_UTILS.normalize(path);
-                String s = FILE_UTILS.removeLeadingPath(base, f);
-                if (s.equals(f.getAbsolutePath())) {
-                    //removing base from path yields no change; path
-                    //not child of base
-                    return null;
-                }
-                path = s;
-            }
-        }
-        return findFile(base, SelectorUtils.tokenizePath(path), cs);
-    }
-
-    /**
-     * From <code>base</code> traverse the filesystem in order to find
-     * a file that matches the given stack of names.
-     *
-     * @param base base File (dir).
-     * @param pathElements Vector of path elements (dirs...file).
-     * @param cs whether to scan case-sensitively.
-     * @return File object that points to the file in question or null.
-     *
-     * @since Ant 1.6.3
-     */
-    private File findFile(File base, Vector pathElements, boolean cs) {
-        if (pathElements.size() == 0) {
-            return base;
-        }
-        String current = (String) pathElements.remove(0);
-        if (base == null) {
-            return findFile(new File(current), pathElements, cs);
-        }
-        if (!base.isDirectory()) {
-            return null;
-        }
-        String[] files = list(base);
-        if (files == null) {
-            throw new BuildException("IO error scanning directory "
-                                     + base.getAbsolutePath());
-        }
-        boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
-        for (int i = 0; i < matchCase.length; i++) {
-            for (int j = 0; j < files.length; j++) {
-                if (matchCase[i] ? files[j].equals(current)
-                                 : files[j].equalsIgnoreCase(current)) {
-                    return findFile(new File(base, files[j]), pathElements, cs);
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Do we have to traverse a symlink when trying to reach path from
-     * basedir?
-     * @param base base File (dir).
-     * @param path file path.
-     * @since Ant 1.6
-     */
-    private boolean isSymlink(File base, String path) {
-        return isSymlink(base, SelectorUtils.tokenizePath(path));
-    }
-
-    /**
-     * Do we have to traverse a symlink when trying to reach path from
-     * basedir?
-     * @param base base File (dir).
-     * @param pathElements Vector of path elements (dirs...file).
-     * @since Ant 1.6
-     */
-    private boolean isSymlink(File base, Vector pathElements) {
-        if (pathElements.size() > 0) {
-            String current = (String) pathElements.remove(0);
-            try {
-                return FILE_UTILS.isSymbolicLink(base, current)
-                    || isSymlink(new File(base, current), pathElements);
-            } 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);
-            }
-        }
-        return false;
-    }
-
-    /**
      * Has the directory with the given path relative to the base
      * directory already been scanned?
      *

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=696298&r1=696297&r2=696298&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 06:52:40 2008
@@ -698,18 +698,7 @@
      * @return the leftmost part of the pattern without wildcards
      */
     public static String rtrimWildcardTokens(String input) {
-        String[] tokens = tokenizePathAsArray(input);
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < tokens.length; i++) {
-            if (hasWildcards(tokens[i])) {
-                break;
-            }
-            if (i > 0 && sb.charAt(sb.length() - 1) != File.separatorChar) {
-                sb.append(File.separator);
-            }
-            sb.append(tokens[i]);
-        }
-        return sb.toString();
+        return new TokenizedPattern(input).rtrimWildcardTokens().toString();
     }
 }
 

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=696298&r1=696297&r2=696298&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 06:52:40 2008
@@ -18,12 +18,30 @@
 
 package org.apache.tools.ant.types.selectors;
 
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
 /**
  * Container for a path that has been split into its components.
  * @since 1.8.0
  */
 public class TokenizedPath {
 
+    /**
+     * Instance that holds no tokens at all.
+     */
+    public static final TokenizedPath EMPTY_PATH =
+        new TokenizedPath("", new String[0]);
+
+    /** Helper. */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    /** iterations for case-sensitive scanning. */
+    private static final boolean[] CS_SCAN_ONLY = new boolean[] {true};
+    /** iterations for non-case-sensitive scanning. */
+    private static final boolean[] CS_THEN_NON_CS = new boolean[] {true, false};
+
     private final String path;
     private final String tokenizedPath[];
 
@@ -33,10 +51,14 @@
     *                <code>null</code>.
     */
     public TokenizedPath(String path) {
-        this.path = path;    
-        this.tokenizedPath = SelectorUtils.tokenizePathAsArray(path);
+        this(path, SelectorUtils.tokenizePathAsArray(path));
     }
     
+    /* package */ TokenizedPath(String path, String[] tokens) {
+        this.path = path;
+        this.tokenizedPath = tokens;
+    }
+
     /**
      * @return The original path String
      */
@@ -54,4 +76,106 @@
     /* package */ String[] getTokens() {
         return tokenizedPath;
     }
+
+    /**
+     * From <code>base</code> traverse the filesystem in order to find
+     * a file that matches the given name.
+     *
+     * @param base base File (dir).
+     * @param cs whether to scan case-sensitively.
+     * @return File object that points to the file in question or null.
+     */
+    public File findFile(File base, final boolean cs) {
+        String[] tokens = tokenizedPath;
+        if (FileUtils.isAbsolutePath(path)) {
+            if (base == null) {
+                String[] s = FILE_UTILS.dissect(path);
+                base = new File(s[0]);
+                tokens = SelectorUtils.tokenizePathAsArray(s[1]);
+            } else {
+                File f = FILE_UTILS.normalize(path);
+                String s = FILE_UTILS.removeLeadingPath(base, f);
+                if (s.equals(f.getAbsolutePath())) {
+                    //removing base from path yields no change; path
+                    //not child of base
+                    return null;
+                }
+                tokens = SelectorUtils.tokenizePathAsArray(s);
+            }
+        }
+        return findFile(base, tokens, cs);
+    }
+
+    /**
+     * Do we have to traverse a symlink when trying to reach path from
+     * basedir?
+     * @param base base File (dir).
+     */
+    public boolean isSymlink(File base) {
+        for (int i = 0; i < tokenizedPath.length; i++) {
+            try {
+                if (FILE_UTILS.isSymbolicLink(base, tokenizedPath[i])) {
+                    return true;
+                }
+                base = new File(base, tokenizedPath[i]);
+            } catch (java.io.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);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * true if the original paths are equal.
+     */
+    public boolean equals(Object o) {
+        return o instanceof TokenizedPath
+            && path.equals(((TokenizedPath) o).path);
+    }
+
+    public int hashCode() {
+        return path.hashCode();
+    }
+
+    /**
+     * From <code>base</code> traverse the filesystem in order to find
+     * a file that matches the given stack of names.
+     *
+     * @param base base File (dir) - must not be null.
+     * @param pathElements array of path elements (dirs...file).
+     * @param cs whether to scan case-sensitively.
+     * @return File object that points to the file in question or null.
+     */
+    private static File findFile(File base, final String[] pathElements,
+                                 final boolean cs) {
+        for (int current = 0; current < pathElements.length; current++) {
+            if (!base.isDirectory()) {
+                return null;
+            }
+            String[] files = base.list();
+            if (files == null) {
+                throw new BuildException("IO error scanning directory "
+                                         + base.getAbsolutePath());
+            }
+            boolean found = false;
+            boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
+            for (int i = 0; !found && i < matchCase.length; i++) {
+                for (int j = 0; !found && j < files.length; j++) {
+                    if (matchCase[i]
+                        ? files[j].equals(pathElements[current])
+                        : files[j].equalsIgnoreCase(pathElements[current])) {
+                        base = new File(base, files[j]);
+                        found = true;
+                    }
+                }
+            }
+            if (!found) {
+                return null;
+            }
+        }
+        return pathElements.length == 0 && !base.isDirectory() ? null : base;
+    }
 }

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=696298&r1=696297&r2=696298&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 06:52:40 2008
@@ -18,13 +18,16 @@
 
 package org.apache.tools.ant.types.selectors;
 
+import java.io.File;
+
 /**
- * Provides reusable path pattern matching.  PathPattern is preferable to equivalent
- * SelectorUtils methods if you need to execute multiple matching with the same pattern 
- * because here the pattern itself will be parsed only once.
+ * Provides reusable path pattern matching.  PathPattern is preferable
+ * to equivalent SelectorUtils methods if you need to execute multiple
+ * matching with the same pattern because here the pattern itself will
+ * be parsed only once.
  * @see SelectorUtils#matchPath(String, String)
  * @see SelectorUtils#matchPath(String, String, boolean)
- * @since 1.8
+ * @since 1.8.0
  */
 public class TokenizedPattern {
 
@@ -37,10 +40,14 @@
     *                <code>null</code>.
     */
     public TokenizedPattern(String pattern) {
-        this.pattern = pattern;    
-        this.tokenizedPattern = SelectorUtils.tokenizePathAsArray(pattern);
+        this(pattern, SelectorUtils.tokenizePathAsArray(pattern));
     }
     
+    private TokenizedPattern(String pattern, String[] tokens) {
+        this.pattern = pattern;
+        this.tokenizedPattern = tokens;
+    }
+
     /**
      * Tests whether or not a given path matches a given pattern.
      *
@@ -91,6 +98,18 @@
     }
 
     /**
+     * true if the original patterns are equal.
+     */
+    public boolean equals(Object o) {
+        return o instanceof TokenizedPattern
+            && pattern.equals(((TokenizedPattern) o).pattern);
+    }
+
+    public int hashCode() {
+        return pattern.hashCode();
+    }
+
+    /**
      * The depth (or length) of a pattern.
      */
     public int depth() {
@@ -108,4 +127,30 @@
         }
         return false;
     }
+
+    /**
+     * Returns a new TokenizedPath where all tokens of this pattern to
+     * the right containing wildcards have been removed
+     * @return the leftmost part of the pattern without wildcards
+     */
+    public TokenizedPath rtrimWildcardTokens() {
+        StringBuffer sb = new StringBuffer();
+        int newLen = 0;
+        for (; newLen < tokenizedPattern.length; newLen++) {
+            if (SelectorUtils.hasWildcards(tokenizedPattern[newLen])) {
+                break;
+            }
+            if (newLen > 0
+                && sb.charAt(sb.length() - 1) != File.separatorChar) {
+                sb.append(File.separator);
+            }
+            sb.append(tokenizedPattern[newLen]);
+        }
+        if (newLen == 0) {
+            return TokenizedPath.EMPTY_PATH;
+        }
+        String[] newPats = new String[newLen];
+        System.arraycopy(tokenizedPattern, 0, newPats, 0, newLen);
+        return new TokenizedPath(sb.toString(), newPats);
+    }
 }