2 // DirectoryScanner.cs: Class used by BuildItem.
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.Collections
.Generic
;
34 using Microsoft
.Build
.Framework
;
35 using Microsoft
.Build
.Utilities
;
37 namespace Microsoft
.Build
.BuildEngine
{
38 internal class DirectoryScanner
{
40 DirectoryInfo baseDirectory
;
41 ITaskItem
[] includes
, excludes
;
42 ITaskItem
[] matchedItems
;
44 static bool _runningOnWindows
;
46 static DirectoryScanner ()
48 PlatformID pid
= Environment
.OSVersion
.Platform
;
49 _runningOnWindows
=((int) pid
!= 128 && (int) pid
!= 4 && (int) pid
!= 6);
52 public DirectoryScanner ()
58 Dictionary
<string, bool> excludedItems
;
59 List
<ITaskItem
> includedItems
;
60 string[] splitExclude
;
63 throw new ArgumentNullException ("Includes");
64 if (baseDirectory
== null)
65 throw new ArgumentNullException ("BaseDirectory");
67 excludedItems
= new Dictionary
<string, bool> ();
68 includedItems
= new List
<ITaskItem
> ();
71 foreach (ITaskItem excl
in excludes
)
72 ProcessExclude (excl
.ItemSpec
, excludedItems
);
74 foreach (ITaskItem include_item
in includes
)
75 ProcessInclude (include_item
, excludedItems
, includedItems
);
77 matchedItems
= includedItems
.ToArray ();
80 private void ProcessInclude (ITaskItem include_item
, Dictionary
<string, bool> excludedItems
,
81 List
<ITaskItem
> includedItems
)
83 string[] separatedPath
;
86 string name
= include_item
.ItemSpec
;
87 if (name
.IndexOf ('?') == -1 && name
.IndexOf ('*') == -1) {
88 if (!excludedItems
.ContainsKey (Path
.GetFullPath(name
)))
89 includedItems
.Add (include_item
);
91 if (name
.Split (Path
.DirectorySeparatorChar
).Length
> name
.Split (Path
.AltDirectorySeparatorChar
).Length
) {
92 separatedPath
= name
.Split (new char [] {Path.DirectorySeparatorChar}
,
93 StringSplitOptions
.RemoveEmptyEntries
);
95 separatedPath
= name
.Split (new char [] {Path.AltDirectorySeparatorChar}
,
96 StringSplitOptions
.RemoveEmptyEntries
);
98 if (separatedPath
.Length
== 1 && separatedPath
[0] == String
.Empty
)
102 if (Path
.IsPathRooted (name
)) {
103 baseDirectory
= new DirectoryInfo (Path
.GetPathRoot (name
));
104 if (IsRunningOnWindows
)
109 string full_path
= Path
.GetFullPath (Path
.Combine (Environment
.CurrentDirectory
, include_item
.ItemSpec
));
110 fileInfo
= ParseIncludeExclude (separatedPath
, offset
, baseDirectory
);
112 int wildcard_offset
= full_path
.IndexOf ("**");
113 foreach (FileInfo fi
in fileInfo
) {
114 if (!excludedItems
.ContainsKey (fi
.FullName
)) {
115 TaskItem item
= new TaskItem (include_item
);
116 item
.ItemSpec
= fi
.FullName
;
117 string rec_dir
= Path
.GetDirectoryName (fi
.FullName
.Substring (wildcard_offset
));
118 if (rec_dir
.Length
> 0)
119 rec_dir
+= Path
.DirectorySeparatorChar
;
120 item
.SetMetadata ("RecursiveDir", rec_dir
);
121 includedItems
.Add (item
);
127 private void ProcessExclude (string name
, Dictionary
<string, bool> excludedItems
)
129 string[] separatedPath
;
132 if (name
.IndexOf ('?') == -1 && name
.IndexOf ('*') == -1) {
133 if (!excludedItems
.ContainsKey (Path
.GetFullPath (name
)))
134 excludedItems
.Add (Path
.GetFullPath (name
), true);
136 if (name
.Split (Path
.DirectorySeparatorChar
).Length
> name
.Split (Path
.AltDirectorySeparatorChar
).Length
) {
137 separatedPath
= name
.Split (new char [] {Path.DirectorySeparatorChar}
,
138 StringSplitOptions
.RemoveEmptyEntries
);
140 separatedPath
= name
.Split (new char [] {Path.AltDirectorySeparatorChar}
,
141 StringSplitOptions
.RemoveEmptyEntries
);
143 if (separatedPath
.Length
== 1 && separatedPath
[0] == String
.Empty
)
147 if (Path
.IsPathRooted (name
)) {
148 baseDirectory
= new DirectoryInfo (Path
.GetPathRoot (name
));
149 if (IsRunningOnWindows
)
153 fileInfo
= ParseIncludeExclude (separatedPath
, offset
, baseDirectory
);
154 foreach (FileInfo fi
in fileInfo
)
155 if (!excludedItems
.ContainsKey (fi
.FullName
))
156 excludedItems
.Add (fi
.FullName
, true);
160 private FileInfo
[] ParseIncludeExclude (string[] input
, int ptr
, DirectoryInfo directory
)
162 if (input
.Length
> 1 && ptr
== 0 && input
[0] == String
.Empty
)
164 if (input
.Length
== ptr
+ 1) {
166 fi
= directory
.GetFiles (input
[ptr
]);
171 List
<FileInfo
> fileInfos
= new List
<FileInfo
> ();
172 if (input
[ptr
] == ".") {
173 di
= new DirectoryInfo
[1];
175 } else if (input
[ptr
] == "..") {
176 di
= new DirectoryInfo
[1];
177 di
[0] = directory
.Parent
;
178 } else if (input
[ptr
] == "**")
180 // Read this directory and all subdirectories recursive
181 Stack
<DirectoryInfo
> currentDirectories
= new Stack
<DirectoryInfo
>();
182 currentDirectories
.Push(directory
);
183 List
<DirectoryInfo
> allDirectories
= new List
<DirectoryInfo
>();
185 while (currentDirectories
.Count
> 0)
187 DirectoryInfo current
= currentDirectories
.Pop();
188 allDirectories
.Insert (0, current
);
189 foreach (DirectoryInfo dir
in current
.GetDirectories())
191 currentDirectories
.Push(dir
);
195 // No further directories shall be read
196 di
= allDirectories
.ToArray();
198 di
= directory
.GetDirectories (input
[ptr
]);
200 foreach (DirectoryInfo info
in di
) {
201 fi
= ParseIncludeExclude (input
, ptr
+ 1, info
);
202 foreach (FileInfo file
in fi
)
203 fileInfos
.Add (file
);
205 fi
= new FileInfo
[fileInfos
.Count
];
207 foreach (FileInfo file
in fileInfos
)
213 public DirectoryInfo BaseDirectory
{
214 get { return baseDirectory; }
215 set { baseDirectory = value; }
218 public ITaskItem
[] Includes
{
219 get { return includes; }
220 set { includes = value; }
223 public ITaskItem
[] Excludes
{
224 get { return excludes; }
225 set { excludes = value; }
228 public ITaskItem
[] MatchedItems
{
229 get { return matchedItems; }
232 static bool IsRunningOnWindows
{
233 get { return _runningOnWindows; }