The speed increase should be visible for some cases, but you should see improvements in cases where you generate documentation in directories that get picked up by the current scanner or any other cases where the recursive scans are picking up far more than they need to.
All the unit tests run and pass, and a new one was added to test some new potential troublespots.
I'm having trouble getting my Visual Studio to produce the same code as CVS. Fortunately, diff -b -u seems to reduce the amount of clutter in the diff output.
Matt.
Index: src/NAnt.Core/DirectoryScanner.cs
===================================================================
RCS file: /cvsroot/nant/nant/src/NAnt.Core/DirectoryScanner.cs,v
retrieving revision 1.5
diff -u -b -r1.5 DirectoryScanner.cs
--- src/NAnt.Core/DirectoryScanner.cs 6 Mar 2003 03:19:28 -0000 1.5
+++ src/NAnt.Core/DirectoryScanner.cs 6 Mar 2003 19:30:01 -0000
@@ -47,6 +47,7 @@
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
+using System.Collections;
namespace SourceForge.NAnt {
/// <summary>Used for searching file system based on given include/exclude
rules.</summary>
@@ -111,6 +112,7 @@
// directories that should be scanned and directories scanned so far
StringCollection _searchDirectories = null;
+ ArrayList _searchDirIsRecursive = null;
StringCollection _pathsAlreadySearched = null;
public StringCollection Includes {
@@ -163,6 +165,7 @@
_fileNames = new StringCollection();
_directoryNames = new StringCollection();
_searchDirectories = new StringCollection();
+ _searchDirIsRecursive = new ArrayList();
_pathsAlreadySearched = new StringCollection();
// convert given NAnt patterns to regex patterns with absolute paths
@@ -170,13 +173,12 @@
convertPatterns(_includes, _includePatterns);
convertPatterns(_excludes, _excludePatterns);
- foreach (string path in _searchDirectories) {
- ScanDirectory(path);
+ for (int index = 0; index < _searchDirectories.Count; index++)
{
+ ScanDirectory(_searchDirectories[index],
(bool)_searchDirIsRecursive[index]);
}
}
-
/// <summary>
/// Parses given NAnt search patterns for search directories and
corresponding regex patterns
/// </summary>
@@ -188,10 +190,20 @@
public void convertPatterns(StringCollection nantPatterns, StringCollection
regexPatterns) {
string searchDirectory;
string regexPattern;
+ bool isRecursive;
foreach (string nantPattern in nantPatterns) {
- parseSearchDirectoryAndPattern(nantPattern, out searchDirectory, out
regexPattern);
- if (!_searchDirectories.Contains(searchDirectory)) {
+ parseSearchDirectoryAndPattern(nantPattern, out
searchDirectory, out isRecursive, out regexPattern);
+ int index =
_searchDirectories.IndexOf(searchDirectory);
+ // If the directory was found before, but wasn't
recursive and is now, mark it as so
+ if (index > -1) {
+ if (!(bool)_searchDirIsRecursive[index] &&
isRecursive) {
+ _searchDirIsRecursive[index] =
isRecursive;
+ }
+ }
+ // If the directory has not been added, add it
+ if (index == -1) {
_searchDirectories.Add(searchDirectory);
+ _searchDirIsRecursive.Add(isRecursive);
}
if (!regexPatterns.Contains(regexPattern))
regexPatterns.Add(regexPattern);
@@ -205,6 +217,7 @@
/// </summary>
/// <param name="originalNAntPattern">NAnt searh pattern (relative to the
Basedirectory OR absolute, relative paths refering to parent directories ( ../ ) also
supported)</param>
/// <param name="searchDirectory">Out. Absolute canonical path to the
directory to be searched</param>
+ /// <param name="recursive">Out. Whether the pattern is potentially
recursive or not</param>
/// <param name="regexPattern">Out. Regex search pattern (absolute canonical
path)</param>
/// <history>
/// <change date="20020220" author="Ari H�nnik�inen">Created</change>
@@ -215,8 +228,15 @@
/// "/foo/bar/fudge/nugget". (pattern = "fudge/nugget" would still be
treated as relative to basedir)
/// </change>
/// </history>
- public void parseSearchDirectoryAndPattern(string originalNAntPattern, out
string searchDirectory, out string regexPattern) {
+ public void parseSearchDirectoryAndPattern(string originalNAntPattern,
out string searchDirectory, out bool recursive, out string regexPattern) {
string s = originalNAntPattern;
+ s = s.Replace('\\', Path.DirectorySeparatorChar);
+ s = s.Replace('/', Path.DirectorySeparatorChar);
+
+ // Get indices of pieces used for recursive check only
+ int indexOfFirstDirectoryWildcard = s.IndexOf("**");
+ int indexOfLastOriginalDirectorySeparator =
s.LastIndexOf(Path.DirectorySeparatorChar);
+
// search for the first wildcard character (if any) and exclude the rest
of the string beginnning from the character
char[] wildcards = {'?', '*'};
int indexOfFirstWildcard = s.IndexOfAny(wildcards);
@@ -224,11 +244,20 @@
s = s.Substring(0, indexOfFirstWildcard);
}
- s = s.Replace('\\', Path.DirectorySeparatorChar);
- s= s.Replace('/', Path.DirectorySeparatorChar);
// find the last DirectorySeparatorChar (if any) and exclude the rest of
the string
int indexOfLastDirectorySeparator =
s.LastIndexOf(Path.DirectorySeparatorChar);
+ // The pattern is potentially recursive if and only if more
than one base directory could be matched.
+ // ie:
+ // **
+ // **/*.txt
+ // foo*/xxx
+ // x/y/z?/www
+ // This condition is true if and only if:
+ // - The first wildcard is before the last directory
separator, or
+ // - The pattern contains a directory wildcard ("**")
+ recursive = ( indexOfFirstWildcard <
indexOfLastOriginalDirectorySeparator ) || indexOfFirstDirectoryWildcard != -1;
+
// substring preceding the separator represents our search directory and
the part following it represents nant search pattern relative to it
if (indexOfLastDirectorySeparator != -1) {
s = originalNAntPattern.Substring(0, indexOfLastDirectorySeparator);
@@ -265,10 +294,11 @@
/// Searches a directory recursively for files and directories matching
the search criteria
/// </summary>
/// <param name="path">Directory in which to search (absolute canonical
path)</param>
+ /// <param name="recursive">Whether to scan recursively or not</param>
/// <history>
/// <change date="20020221" author="Ari H�nnik�inen">Checking if the
directory has already been scanned</change>
/// </history>
- void ScanDirectory(string path) {
+ void ScanDirectory(string path, bool recursive) {
// scan each directory only once
if (_pathsAlreadySearched.Contains(path)) {
@@ -286,9 +316,16 @@
bool caseSensitive = VolumeInfo.IsVolumeCaseSensitive(new
Uri(Path.GetDirectoryName(path) + Path.DirectorySeparatorChar));
- // scan subfolders
foreach (DirectoryInfo directoryInfo in
currentDirectoryInfo.GetDirectories()) {
- ScanDirectory(directoryInfo.FullName);
+ if (recursive) {
+ // scan subfolders if we are running
recursively
+ ScanDirectory(directoryInfo.FullName, true);
+ } else {
+ // otherwise just test to see if the
subdirectories are included
+ if (IsPathIncluded(directoryInfo.FullName,
caseSensitive)) {
+
_directoryNames.Add(directoryInfo.FullName);
+ }
+ }
}
// scan files
Index: src/NAnt.Core.Tests/DirectoryScannerTest.cs
===================================================================
RCS file: /cvsroot/nant/nant/src/NAnt.Core.Tests/DirectoryScannerTest.cs,v
retrieving revision 1.2
diff -u -b -r1.2 DirectoryScannerTest.cs
--- src/NAnt.Core.Tests/DirectoryScannerTest.cs 25 Oct 2002 10:18:09 -0000 1.2
+++ src/NAnt.Core.Tests/DirectoryScannerTest.cs 6 Mar 2003 19:30:02 -0000
@@ -180,5 +180,29 @@
_scanner.Includes.Add(@"**\folder3\**\XYZ*");
CheckScan(includedFileNames, excludedFileNames);
}
+
+ /// <summary>Test specifying a folder both recursively and
non-recursively.</summary>
+ /// <remarks>
+ /// Matches all files/dirs that start with "XYZ" and where there is
a
+ /// parent directory called 'folder3' (e.g.
"abc\folder3\def\ghi\XYZ123").
+ /// </remarks>
+ [Test]
+ public void Test_RecursiveWildcardMatching4()
+ {
+ string[] includedFileNames = new string[] {
+ Path.Combine(_folder3, "XYZ.txt"),
+ Path.Combine(_folder3, "XYZ.bak"),
+ Path.Combine(_folder3, "XYZzzz.txt"),
+ };
+ string[] excludedFileNames = new string[] {
+ Path.Combine(_tempDir, "Foo2.bar"),
+ Path.Combine(_folder2, "Foo3.bar"),
+ Path.Combine(_folder3, "Foo4.bar")
+ };
+
+ _scanner.Includes.Add(@"folder3/XYZ*");
+ _scanner.Includes.Add(@"**\folder3\**\XYZ*");
+ CheckScan(includedFileNames, excludedFileNames);
+ }
}
}
