1 // NAnt - A .NET build tool
\r
2 // Copyright (C) 2001 Gerry Shaw
\r
4 // This program is free software; you can redistribute it and/or modify
\r
5 // it under the terms of the GNU General Public License as published by
\r
6 // the Free Software Foundation; either version 2 of the License, or
\r
7 // (at your option) any later version.
\r
9 // This program is distributed in the hope that it will be useful,
\r
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 // GNU General Public License for more details.
\r
14 // You should have received a copy of the GNU General Public License
\r
15 // along with this program; if not, write to the Free Software
\r
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
18 // Gerry Shaw (gerry_shaw@yahoo.com)
\r
22 "**\*.class" matches all .class files/dirs in a directory tree.
\r
24 "test\a??.java" matches all files/dirs which start with an 'a', then two
\r
25 more characters and then ".java", in a directory called test.
\r
27 "**" matches everything in a directory tree.
\r
29 "**\test\**\XYZ*" matches all files/dirs that start with "XYZ" and where
\r
30 there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
\r
34 DirectoryScanner scanner = DirectoryScanner();
\r
35 scanner.Includes.Add("**\\*.class");
\r
36 scanner.Exlucdes.Add("modules\\*\\**");
\r
37 scanner.BaseDirectory = "test";
\r
39 foreach (string filename in GetIncludedFiles()) {
\r
40 Console.WriteLine(filename);
\r
44 namespace SourceForge.NAnt {
\r
47 using System.Collections.Specialized;
\r
50 using System.Text.RegularExpressions;
\r
52 public class DirectoryScanner {
\r
54 string _baseDirectory = Environment.CurrentDirectory;
\r
56 // holds the nant patterns
\r
57 StringCollection _includes = new StringCollection();
\r
58 StringCollection _excludes = new StringCollection();
\r
60 // holds the nant patterns converted to regular expression patterns
\r
61 StringCollection _includePatterns = null;
\r
62 StringCollection _excludePatterns = null;
\r
64 // holds the result from a scan
\r
65 StringCollection _fileNames = null;
\r
66 StringCollection _directoryNames = null;
\r
68 public StringCollection Includes {
\r
69 get { return _includes; }
\r
72 public StringCollection Excludes {
\r
73 get { return _excludes; }
\r
76 public string BaseDirectory {
\r
77 get { return _baseDirectory; }
\r
78 set { _baseDirectory = value; }
\r
81 public StringCollection FileNames {
\r
83 if (_fileNames == null) {
\r
90 public StringCollection DirectoryNames {
\r
92 if (_directoryNames == null) {
\r
95 return _directoryNames;
\r
99 public void Scan() {
\r
100 _includePatterns = new StringCollection();
\r
101 foreach (string pattern in Includes) {
\r
102 _includePatterns.Add(ToRegexPattern(pattern));
\r
105 _excludePatterns = new StringCollection();
\r
106 foreach (string pattern in Excludes) {
\r
107 _excludePatterns.Add(ToRegexPattern(pattern));
\r
110 _fileNames = new StringCollection();
\r
111 _directoryNames = new StringCollection();
\r
113 ScanDirectory(Path.GetFullPath(BaseDirectory));
\r
116 void ScanDirectory(string path) {
\r
117 // get info for the current directory
\r
118 DirectoryInfo currentDirectoryInfo = new DirectoryInfo(path);
\r
121 foreach (DirectoryInfo directoryInfo in currentDirectoryInfo.GetDirectories()) {
\r
122 ScanDirectory(directoryInfo.FullName);
\r
126 foreach (FileInfo fileInfo in currentDirectoryInfo.GetFiles()) {
\r
127 string filename = Path.Combine(path, fileInfo.Name);
\r
128 if (IsPathIncluded(filename)) {
\r
129 _fileNames.Add(filename);
\r
133 // Check current path last so that delete task will correctly
\r
134 // delete empty directories. This may *seem* like a special case
\r
135 // but it is more like formalizing something in a way that makes
\r
136 // writing the delete task easier :)
\r
137 if (IsPathIncluded(path)) {
\r
138 _directoryNames.Add(path);
\r
142 bool IsPathIncluded(string path) {
\r
143 bool included = false;
\r
145 // check path against includes
\r
146 foreach (string pattern in _includePatterns) {
\r
147 Match m = Regex.Match(path, pattern);
\r
154 // check path against excludes
\r
156 foreach (string pattern in _excludePatterns) {
\r
157 Match m = Regex.Match(path, pattern);
\r
168 string ToRegexPattern(string nantPattern) {
\r
170 StringBuilder pattern = new StringBuilder(nantPattern);
\r
172 // NAnt patterns can use either / \ as a directory seperator.
\r
173 // We must replace both of these characters with Path.DirectorySeperatorChar
\r
174 pattern.Replace('/', Path.DirectorySeparatorChar);
\r
175 pattern.Replace('\\', Path.DirectorySeparatorChar);
\r
177 // Patterns MUST be full paths.
\r
178 if (!Path.IsPathRooted(pattern.ToString())) {
\r
179 pattern = new StringBuilder(Path.Combine(BaseDirectory, pattern.ToString()));
\r
182 // The '\' character is a special character in regular expressions
\r
183 // and must be escaped before doing anything else.
\r
184 pattern.Replace(@"\", @"\\");
\r
186 // Escape the rest of the regular expression special characters.
\r
187 // NOTE: Characters other than . $ ^ { [ ( | ) * + ? \ match themselves.
\r
188 // TODO: Decide if ] and } are missing from this list, the above
\r
189 // list of characters was taking from the .NET SDK docs.
\r
190 pattern.Replace(".", @"\.");
\r
191 pattern.Replace("$", @"\$");
\r
192 pattern.Replace("^", @"\^");
\r
193 pattern.Replace("{", @"\{");
\r
194 pattern.Replace("[", @"\[");
\r
195 pattern.Replace("(", @"\(");
\r
196 pattern.Replace(")", @"\)");
\r
197 pattern.Replace("+", @"\+");
\r
199 // Special case directory seperator string under Windows.
\r
200 string seperator = Path.DirectorySeparatorChar.ToString();
\r
201 if (seperator == @"\") {
\r
205 // Convert NAnt pattern characters to regular expression patterns.
\r
207 // SPECIAL CASE: to match subdirectory OR current directory. If
\r
208 // we don't do this then we can write something like 'src/**/*.cs'
\r
209 // to match all the files ending in .cs in the src directory OR
\r
210 // subdirectories of src.
\r
211 pattern.Replace(seperator + "**", "(" + seperator + ".|)|");
\r
213 // | is a place holder for * to prevent it from being replaced in next line
\r
214 pattern.Replace("**", ".|");
\r
215 pattern.Replace("*", "[^" + seperator + "]*");
\r
216 pattern.Replace("?", "[^" + seperator + "]?");
\r
217 pattern.Replace('|', '*'); // replace place holder string
\r
219 // Help speed up the search
\r
220 pattern.Insert(0, '^'); // start of line
\r
221 pattern.Append('$'); // end of line
\r
223 return pattern.ToString();
\r