In class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine:
[mono-project.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / DirectoryScanner.cs
blob904a979b851a64f25124bc90e73fc9ca079dce5d
1 //
2 // DirectoryScanner.cs: Class used by BuildItem.
3 //
4 // Author:
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
6 //
7 // (C) 2005 Marek Sieradzki
8 //
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.
28 #if NET_2_0
30 using System;
31 using System.Collections.Generic;
32 using System.IO;
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 ()
56 public void Scan ()
58 Dictionary <string, bool> excludedItems;
59 List <ITaskItem> includedItems;
60 string[] splitExclude;
62 if (includes == null)
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> ();
70 if (excludes != null)
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;
84 FileInfo[] fileInfo;
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);
90 } else {
91 if (name.Split (Path.DirectorySeparatorChar).Length > name.Split (Path.AltDirectorySeparatorChar).Length) {
92 separatedPath = name.Split (new char [] {Path.DirectorySeparatorChar},
93 StringSplitOptions.RemoveEmptyEntries);
94 } else {
95 separatedPath = name.Split (new char [] {Path.AltDirectorySeparatorChar},
96 StringSplitOptions.RemoveEmptyEntries);
98 if (separatedPath.Length == 1 && separatedPath [0] == String.Empty)
99 return;
101 int offset = 0;
102 if (Path.IsPathRooted (name)) {
103 baseDirectory = new DirectoryInfo (Path.GetPathRoot (name));
104 if (IsRunningOnWindows)
105 // skip the "drive:"
106 offset = 1;
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;
130 FileInfo[] fileInfo;
132 if (name.IndexOf ('?') == -1 && name.IndexOf ('*') == -1) {
133 if (!excludedItems.ContainsKey (Path.GetFullPath (name)))
134 excludedItems.Add (Path.GetFullPath (name), true);
135 } else {
136 if (name.Split (Path.DirectorySeparatorChar).Length > name.Split (Path.AltDirectorySeparatorChar).Length) {
137 separatedPath = name.Split (new char [] {Path.DirectorySeparatorChar},
138 StringSplitOptions.RemoveEmptyEntries);
139 } else {
140 separatedPath = name.Split (new char [] {Path.AltDirectorySeparatorChar},
141 StringSplitOptions.RemoveEmptyEntries);
143 if (separatedPath.Length == 1 && separatedPath [0] == String.Empty)
144 return;
146 int offset = 0;
147 if (Path.IsPathRooted (name)) {
148 baseDirectory = new DirectoryInfo (Path.GetPathRoot (name));
149 if (IsRunningOnWindows)
150 // skip the "drive:"
151 offset = 1;
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)
163 ptr++;
164 if (input.Length == ptr + 1) {
165 FileInfo[] fi;
166 fi = directory.GetFiles (input [ptr]);
167 return fi;
168 } else {
169 DirectoryInfo[] di;
170 FileInfo[] fi;
171 List <FileInfo> fileInfos = new List <FileInfo> ();
172 if (input [ptr] == ".") {
173 di = new DirectoryInfo [1];
174 di [0] = directory;
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();
197 } else {
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];
206 int i = 0;
207 foreach (FileInfo file in fileInfos)
208 fi [i++] = file;
209 return fi;
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; }
238 #endif