Browse Source

Optimize DirectoryScanner to take advantage of include patterns which are

not beginning with wildcards
PR: 20103


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274819 13f79535-47bb-0310-9956-ffa450edef68
master
Antoine Levy-Lambert 22 years ago
parent
commit
787728897a
3 changed files with 158 additions and 45 deletions
  1. +3
    -0
      WHATSNEW
  2. +105
    -34
      src/main/org/apache/tools/ant/DirectoryScanner.java
  3. +50
    -11
      src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java

+ 3
- 0
WHATSNEW View File

@@ -486,6 +486,9 @@ Other changes:

* OpenVMS is detected as a valid OS family.

* DirectoryScanner has been optimized for cases where include patterns do not start with wildcards
Bugzilla Report 20103.

Changes from Ant 1.5.2 to Ant 1.5.3
===================================



+ 105
- 34
src/main/org/apache/tools/ant/DirectoryScanner.java View File

@@ -57,6 +57,9 @@ package org.apache.tools.ant;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceFactory;
import org.apache.tools.ant.types.selectors.FileSelector;
@@ -639,9 +642,59 @@ public class DirectoryScanner
} else {
dirsNotIncluded.addElement("");
}
scandir(basedir, "", true);
checkIncludePatterns();
}
/**
* this routine is actually checking all the include patterns
* in order to avoid scanning everything under base dir
* @since ant1.6
*/
private void checkIncludePatterns() {
Hashtable newroots = new Hashtable();
// put in the newroots vector the include patterns without wildcard tokens
for (int icounter=0; icounter<includes.length; icounter++) {
String newpattern=SelectorUtils.rtrimWildcardTokens(includes[icounter]);
// check whether the candidate new pattern has a parent
boolean hasParent=false;
Enumeration myenum = newroots.keys();
while (myenum.hasMoreElements()) {
String existingpattern=(String)myenum.nextElement();
if (existingpattern.length() <= newpattern.length()) {
if (newpattern.indexOf(existingpattern)==0) {
hasParent=true;
}
}
}
if ( !hasParent) {
newroots.put(newpattern,includes[icounter]);
}
}
Enumeration enum2 = newroots.keys();
while (enum2.hasMoreElements()) {
String currentelement = (String) enum2.nextElement();
File myfile=new File(basedir,currentelement);
if (myfile.exists()) {
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 {
String originalpattern=(String)newroots.get(currentelement);
if (originalpattern.equals(currentelement)) {
accountForIncludedFile(currentelement,myfile);
}
}
}
}
}

/**
* Top level invocation for a slow scan. A slow scan builds up a full
* list of excluded/included files/directories, whereas a fast scan
@@ -745,27 +798,7 @@ public class DirectoryScanner
File file = new File(dir, newfiles[i]);
if (file.isDirectory()) {
if (isIncluded(name)) {
if (!isExcluded(name)) {
if (isSelected(name, file)) {
dirsIncluded.addElement(name);
if (fast) {
scandir(file, name + File.separator, fast);
}
} else {
everythingIncluded = false;
dirsDeselected.addElement(name);
if (fast && couldHoldIncluded(name)) {
scandir(file, name + File.separator, fast);
}
}

} else {
everythingIncluded = false;
dirsExcluded.addElement(name);
if (fast && couldHoldIncluded(name)) {
scandir(file, name + File.separator, fast);
}
}
accountForIncludedDir(name, file, fast);
} else {
everythingIncluded = false;
dirsNotIncluded.addElement(name);
@@ -778,17 +811,7 @@ public class DirectoryScanner
}
} else if (file.isFile()) {
if (isIncluded(name)) {
if (!isExcluded(name)) {
if (isSelected(name, file)) {
filesIncluded.addElement(name);
} else {
everythingIncluded = false;
filesDeselected.addElement(name);
}
} else {
everythingIncluded = false;
filesExcluded.addElement(name);
}
accountForIncludedFile(name, file);
} else {
everythingIncluded = false;
filesNotIncluded.addElement(name);
@@ -796,7 +819,55 @@ public class DirectoryScanner
}
}
}
/**
* 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) {
if (!isExcluded(name)) {
if (isSelected(name, file)) {
filesIncluded.addElement(name);
} else {
everythingIncluded = false;
filesDeselected.addElement(name);
}
} else {
everythingIncluded = false;
filesExcluded.addElement(name);
}

}
/**
*
* @param name path of the directory relative to the directory of the fileset
* @param file directory as file
* @param fast
*/
private void accountForIncludedDir(String name, File file, boolean fast) {
if (!isExcluded(name)) {
if (isSelected(name, file)) {
dirsIncluded.addElement(name);
if (fast) {
scandir(file, name + File.separator, fast);
}
} else {
everythingIncluded = false;
dirsDeselected.addElement(name);
if (fast && couldHoldIncluded(name)) {
scandir(file, name + File.separator, fast);
}
}

} else {
everythingIncluded = false;
dirsExcluded.addElement(name);
if (fast && couldHoldIncluded(name)) {
scandir(file, name + File.separator, fast);
}
}

}
/**
* Tests whether or not a name matches against at least one include
* pattern.


+ 50
- 11
src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java View File

@@ -526,16 +526,29 @@ public final class SelectorUtils {
*
* @param path Path to tokenize. Must not be <code>null</code>.
*
* @return a Vector of path elements from the tokenized path
*/
public static Vector tokenizePath(String path) {
Vector ret = new Vector();
StringTokenizer st = new StringTokenizer(path, File.separator);
while (st.hasMoreTokens()) {
ret.addElement(st.nextToken());
}
return ret;
}
* @return a Vector of path elements from the tokenized path
*/
public static Vector tokenizePath (String path) {
return tokenizePath(path, File.separator);
}
/**
* Breaks a path up into a Vector of path elements, tokenizing on
*
* @param path Path to tokenize. Must not be <code>null</code>.
* @param separator the separator against which to tokenize.
*
* @return a Vector of path elements from the tokenized path
* @since ant 1.6
*/
public static Vector tokenizePath (String path, String separator) {
Vector ret = new Vector();
StringTokenizer st = new StringTokenizer(path,separator);
while (st.hasMoreTokens()) {
ret.addElement(st.nextToken());
}
return ret;

}

/**
* Same as {@link #tokenizePath tokenizePath} but hopefully faster.
@@ -649,6 +662,32 @@ public final class SelectorUtils {
}
return result.toString();
}

/**
* Tests if a string contains stars or question marks
* @param input a String which one wants to test for containing wildcard
* @return true if the string contains at least a star or a question mark
*/
public static boolean hasWildcards(String input) {
return (input.indexOf('*')!=-1 || input.indexOf('?')!=-1);
}
/**
* removes from a pattern all tokens to the right containing wildcards
* @param input
* @return the leftmost part of the pattern without wildcards
*/
public static String rtrimWildcardTokens(String input) {
Vector v = tokenizePath(input, File.separator);
StringBuffer sb = new StringBuffer();
for (int counter=0; counter < v.size() ; counter++) {
if ( hasWildcards((String)v.elementAt(counter))) {
break;
}
if (counter >0) {
sb.append(File.separator);
}
sb.append((String)v.elementAt(counter));
}
return sb.toString();
}
}


Loading…
Cancel
Save