This patch does a test to see if a pattern should result in a recursive search. Recursive searches are triggered by either wildcard directory names or the ** path separator (see the comments for more detail).

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);
+               }
     }
 }

Reply via email to