Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / DirectoryScanner.cs
index 5f93ca38825e4afb3a7f34908164c92e729be739..69c721c9df9cca3c0c778187da4850ec089c68d4 100644 (file)
@@ -31,14 +31,24 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
 namespace Microsoft.Build.BuildEngine {
        internal class DirectoryScanner {
                
                DirectoryInfo   baseDirectory;
-               string          includes;
-               string          excludes;
-               string[]        matchedFilenames;
+               ITaskItem[]     includes, excludes;
+               ITaskItem[]     matchedItems;
+
+               static bool _runningOnWindows;
                
+               static DirectoryScanner ()
+               {
+                       PlatformID pid = Environment.OSVersion.Platform;
+                       _runningOnWindows =((int) pid != 128 && (int) pid != 4 && (int) pid != 6);
+               }
+
                public DirectoryScanner ()
                {
                }
@@ -46,56 +56,77 @@ namespace Microsoft.Build.BuildEngine {
                public void Scan ()
                {
                        Dictionary <string, bool> excludedItems;
-                       List <string> includedItems;
-                       string[] splitInclude, splitExclude;
+                       List <ITaskItem> includedItems;
                        
                        if (includes == null)
                                throw new ArgumentNullException ("Includes");
-                       if (excludes == null)
-                               throw new ArgumentNullException ("Excludes");
                        if (baseDirectory == null)
                                throw new ArgumentNullException ("BaseDirectory");
                        
                        excludedItems = new Dictionary <string, bool> ();
-                       includedItems = new List <string> ();
-                       
-                       splitInclude = includes.Split (';');
-                       splitExclude = excludes.Split (';');
+                       includedItems = new List <ITaskItem> ();
                        
-                       if (excludes != String.Empty) {
-                               foreach (string si in splitExclude) {
-                                       ProcessExclude (si, excludedItems);
-                               }
-                       }
-                       if (includes != String.Empty) {
-                               foreach (string si in splitInclude) {
-                                       ProcessInclude (si, excludedItems, includedItems);
-                               }
-                       }
+                       if (excludes != null)
+                               foreach (ITaskItem excl in excludes)
+                                       ProcessExclude (excl.ItemSpec, excludedItems);
+
+                       foreach (ITaskItem include_item in includes)
+                               ProcessInclude (include_item, excludedItems, includedItems);
 
-                       matchedFilenames = includedItems.ToArray ();
+                       matchedItems = includedItems.ToArray ();
                }
                
-               private void ProcessInclude (string name, Dictionary <string, bool> excludedItems, List <string> includedItems)
+               private void ProcessInclude (ITaskItem include_item, Dictionary <string, bool> excludedItems,
+                               List <ITaskItem> includedItems)
                {
                        string[] separatedPath;
                        FileInfo[] fileInfo;
 
-                       if (name.IndexOf ('?') == -1 && name.IndexOf ('*') == -1) {
+                       string name = include_item.ItemSpec;
+                       if (!HasWildcard (name)) {
                                if (!excludedItems.ContainsKey (Path.GetFullPath(name)))
-                                       includedItems.Add (name);
+                                       includedItems.Add (include_item);
                        } else {
                                if (name.Split (Path.DirectorySeparatorChar).Length > name.Split (Path.AltDirectorySeparatorChar).Length) {
-                                       separatedPath = name.Split (Path.DirectorySeparatorChar);
+                                       separatedPath = name.Split (new char [] {Path.DirectorySeparatorChar},
+                                                       StringSplitOptions.RemoveEmptyEntries);
                                } else {
-                                       separatedPath = name.Split (Path.AltDirectorySeparatorChar);
+                                       separatedPath = name.Split (new char [] {Path.AltDirectorySeparatorChar},
+                                                       StringSplitOptions.RemoveEmptyEntries);
                                }
                                if (separatedPath.Length == 1 && separatedPath [0] == String.Empty)
                                        return;
-                               fileInfo = ParseIncludeExclude (separatedPath, 0, baseDirectory);
-                               foreach (FileInfo fi in fileInfo)
-                                       if (!excludedItems.ContainsKey (fi.FullName))
-                                               includedItems.Add (fi.FullName);
+
+                               int offset = 0;
+                               if (Path.IsPathRooted (name)) {
+                                       baseDirectory = new DirectoryInfo (Path.GetPathRoot (name));
+                                       if (IsRunningOnWindows)
+                                               // skip the "drive:"
+                                               offset = 1;
+                               }
+
+                               string full_path = Path.GetFullPath (Path.Combine (Environment.CurrentDirectory, include_item.ItemSpec));
+                               fileInfo = ParseIncludeExclude (separatedPath, offset, baseDirectory);
+
+                               int wildcard_offset = full_path.IndexOf ("**");
+                               foreach (FileInfo fi in fileInfo) {
+                                       string itemName = fi.FullName;
+                                       if (!Path.IsPathRooted (name) && itemName.Length > baseDirectory.FullName.Length && itemName.StartsWith (baseDirectory.FullName))
+                                               itemName = itemName.Substring (baseDirectory.FullName.Length + 1);
+
+                                       if (!excludedItems.ContainsKey (itemName) &&  !excludedItems.ContainsKey (Path.GetFullPath (itemName))) {
+                                               TaskItem item = new TaskItem (include_item);
+                                               item.ItemSpec = itemName;
+
+                                               if (wildcard_offset >= 0) {
+                                                       string rec_dir = Path.GetDirectoryName (fi.FullName.Substring (wildcard_offset));
+                                                       if (rec_dir.Length > 0)
+                                                               rec_dir += Path.DirectorySeparatorChar;
+                                                       item.SetMetadata ("RecursiveDir", rec_dir);
+                                               }
+                                               includedItems.Add (item);
+                                       }
+                               }
                        }
                }
                
@@ -109,13 +140,24 @@ namespace Microsoft.Build.BuildEngine {
                                        excludedItems.Add (Path.GetFullPath (name), true);
                        } else {
                                if (name.Split (Path.DirectorySeparatorChar).Length > name.Split (Path.AltDirectorySeparatorChar).Length) {
-                                       separatedPath = name.Split (Path.DirectorySeparatorChar);
+                                       separatedPath = name.Split (new char [] {Path.DirectorySeparatorChar},
+                                                                       StringSplitOptions.RemoveEmptyEntries);
                                } else {
-                                       separatedPath = name.Split (Path.AltDirectorySeparatorChar);
+                                       separatedPath = name.Split (new char [] {Path.AltDirectorySeparatorChar},
+                                                                       StringSplitOptions.RemoveEmptyEntries);
                                }
                                if (separatedPath.Length == 1 && separatedPath [0] == String.Empty)
                                        return;
-                               fileInfo = ParseIncludeExclude (separatedPath, 0, baseDirectory);
+
+                               int offset = 0;
+                               if (Path.IsPathRooted (name)) {
+                                       baseDirectory = new DirectoryInfo (Path.GetPathRoot (name));
+                                       if (IsRunningOnWindows)
+                                               // skip the "drive:"
+                                               offset = 1;
+                               }
+
+                               fileInfo = ParseIncludeExclude (separatedPath, offset, baseDirectory);
                                foreach (FileInfo fi in fileInfo)
                                        if (!excludedItems.ContainsKey (fi.FullName))
                                                excludedItems.Add (fi.FullName, true);
@@ -124,35 +166,66 @@ namespace Microsoft.Build.BuildEngine {
                
                private FileInfo[] ParseIncludeExclude (string[] input, int ptr, DirectoryInfo directory)
                {
+                       return ParseIncludeExclude (input, ptr, directory, false);
+               }
+
+               private FileInfo[] ParseIncludeExclude (string[] input, int ptr, DirectoryInfo directory, bool recursive)
+               {
+                       DirectoryInfo[] di;
+                       List <FileInfo> fileInfos = new List<FileInfo> ();
+
                        if (input.Length > 1 && ptr == 0 && input [0] == String.Empty)
                                ptr++;
-                       if (input.Length == ptr + 1) {
-                               FileInfo[] fi;
-                               fi = directory.GetFiles (input [ptr]);
-                               return fi;
-                       } else {
-                               DirectoryInfo[] di;
-                               FileInfo[] fi;
-                               List <FileInfo> fileInfos = new List <FileInfo> ();
-                               if (input [ptr] == ".") {
-                                       di = new DirectoryInfo [1];
-                                       di [0] = directory;
-                               } else if (input [ptr] == "..") {
-                                       di = new DirectoryInfo [1];
-                                       di [0] = directory.Parent;
-                               } else
-                                       di = directory.GetDirectories (input [ptr]);
-                               foreach (DirectoryInfo info in di) {
-                                       fi = ParseIncludeExclude (input, ptr + 1, info);
-                                       foreach (FileInfo file in fi)
-                                               fileInfos.Add (file);
-                               }
-                               fi = new FileInfo [fileInfos.Count];
-                               int i = 0;
-                               foreach (FileInfo file in fileInfos)
-                                       fi [i++] = file;
-                               return fi;
+
+                       string cur = input.Length > ptr ? input[ptr] : input[input.Length-1];
+                       bool dot = cur == ".";
+                       recursive = recursive || cur == "**";
+                       bool parent = cur == "..";
+
+                       if (input.Length <= ptr + 1) {
+                               if (parent)
+                                       directory = directory.Parent;
+                               if ((input.Length == ptr + 1 && !recursive) || input.Length <= ptr)
+                                       return directory.GetFiles (cur);
                        }
+
+                       if (dot) {
+                               di = new DirectoryInfo [1];
+                               di [0] = directory;
+                       } else if (parent) {
+                               di = new DirectoryInfo [1];
+                               di [0] = directory.Parent;
+                       } else if (recursive)
+                       {
+                               // Read this directory and all subdirectories recursive
+                               Stack<DirectoryInfo> currentDirectories = new Stack<DirectoryInfo>();
+                               currentDirectories.Push(directory);
+                               List<DirectoryInfo> allDirectories = new List<DirectoryInfo>();
+
+                               while (currentDirectories.Count > 0)
+                               {
+                                       DirectoryInfo current = currentDirectories.Pop();
+                                       allDirectories.Insert (0, current);
+                                       foreach (DirectoryInfo dir in current.GetDirectories())
+                                       {
+                                               currentDirectories.Push(dir);
+                                       }
+                               }
+
+                               // No further directories shall be read
+                               di = allDirectories.ToArray();
+                       } else
+                               di = directory.GetDirectories (cur);
+
+                       foreach (DirectoryInfo info in di)
+                               fileInfos.AddRange (ParseIncludeExclude (input, ptr + 1, info, recursive));
+
+                       return fileInfos.ToArray ();
+               }
+
+               public static bool HasWildcard (string expression)
+               {
+                       return expression.IndexOf ('?') >= 0 || expression.IndexOf ('*') >= 0;
                }
                
                public DirectoryInfo BaseDirectory {
@@ -160,20 +233,23 @@ namespace Microsoft.Build.BuildEngine {
                        set { baseDirectory = value; }
                }
                
-               public string Includes {
+               public ITaskItem[] Includes {
                        get { return includes; }
                        set { includes = value; }
                }
                
-               public string Excludes {
+               public ITaskItem[] Excludes {
                        get { return excludes; }
                        set { excludes = value; }
                }
                
-               public string[] MatchedFilenames {
-                       get { return matchedFilenames; }
+               public ITaskItem[] MatchedItems {
+                       get { return matchedItems; }
                }
                
+               static bool IsRunningOnWindows {
+                       get { return _runningOnWindows; }
+               }
        }
 }