Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Evaluation / ProjectCollection.cs
index a7f72770440ce84f6e804bec6d8515a8834730d4..ab3ee06638909f6d645195d96d662e817cb55271 100644 (file)
@@ -41,6 +41,7 @@ using System.IO;
 using System.Linq;
 using System.Xml;
 using System.Reflection;
+using System.Globalization;
 
 namespace Microsoft.Build.Evaluation
 {
@@ -106,7 +107,7 @@ namespace Microsoft.Build.Evaluation
 
                public ProjectCollection (IDictionary<string, string> globalProperties, IEnumerable<ILogger> loggers,
                                ToolsetDefinitionLocations toolsetDefinitionLocations)
-                       : this (globalProperties, loggers, null, toolsetDefinitionLocations, int.MaxValue, false)
+                       : this (globalProperties, loggers, null, toolsetDefinitionLocations, 1, false)
                {
                }
 
@@ -118,7 +119,7 @@ namespace Microsoft.Build.Evaluation
                        global_properties = globalProperties ?? new Dictionary<string, string> ();
                        this.loggers = loggers != null ? loggers.ToList () : new List<ILogger> ();
                        toolset_locations = toolsetDefinitionLocations;
-                       max_node_count = maxNodeCount;
+                       MaxNodeCount = maxNodeCount;
                        OnlyLogCriticalEvents = onlyLogCriticalEvents;
 
                        LoadDefaultToolsets ();
@@ -133,8 +134,6 @@ namespace Microsoft.Build.Evaluation
                [MonoTODO ("not fired yet")]
                public event EventHandler<ProjectXmlChangedEventArgs> ProjectXmlChanged;
 
-               readonly int max_node_count;
-
                public void AddProject (Project project)
                {
                        this.loaded_projects.Add (project);
@@ -146,8 +145,14 @@ namespace Microsoft.Build.Evaluation
                        get { return loaded_projects.Count; }
                }
 
+               string default_tools_version;
                public string DefaultToolsVersion {
-                       get { return Toolsets.Any () ? Toolsets.First ().ToolsVersion : null; }
+                       get { return default_tools_version; }
+                       set {
+                               if (GetToolset (value) == null)
+                                       throw new InvalidOperationException (string.Format ("Toolset '{0}' does not exist", value));
+                               default_tools_version = value;
+                       }
                }
 
                public void Dispose ()
@@ -182,12 +187,14 @@ namespace Microsoft.Build.Evaluation
                
                public Project LoadProject (string fileName, string toolsVersion)
                {
-                       return LoadProject (fileName, toolsVersion);
+                       return LoadProject (fileName, null, toolsVersion);
                }
                
                public Project LoadProject (string fileName, IDictionary<string,string> globalProperties, string toolsVersion)
                {
-                       return new Project (fileName, globalProperties, toolsVersion);
+                       var ret = new Project (fileName, globalProperties, toolsVersion);
+                       loaded_projects.Add (ret);
+                       return ret;
                }
                
                // These methods somehow don't add the project to ProjectCollection...
@@ -252,10 +259,10 @@ namespace Microsoft.Build.Evaluation
                        AddToolset (new Toolset ("4.0",
                                ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version40), this, null));
 #endif
-#if NET_4_5
-                       AddToolset (new Toolset ("4.5",
-                               ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version45), this, null));
+#if XBUILD_12
+                       AddToolset (new Toolset ("12.0", ToolLocationHelper.GetPathToBuildTools ("12.0"), this, null));
 #endif
+                       default_tools_version = toolsets.First ().ToolsVersion;
                }
                
                [MonoTODO ("not verified at all")]
@@ -288,14 +295,17 @@ namespace Microsoft.Build.Evaluation
                        throw new NotImplementedException ();
                }
 
+               [MonoTODO ("Not verified at all")]
                public void UnloadProject (Project project)
                {
-                       throw new NotImplementedException ();
+                       this.loaded_projects.Remove (project);
                }
 
+               [MonoTODO ("Not verified at all")]
                public void UnloadProject (ProjectRootElement projectRootElement)
                {
-                       throw new NotImplementedException ();
+                       foreach (var proj in loaded_projects.Where (p => p.Xml == projectRootElement).ToArray ())
+                               UnloadProject (proj);
                }
 
                public static Version Version {
@@ -313,6 +323,10 @@ namespace Microsoft.Build.Evaluation
                [MonoTODO]
                public bool IsBuildEnabled { get; set; }
                
+               internal string BuildStartupDirectory { get; set; }
+               
+               internal int MaxNodeCount { get; private set; }
+               
                Stack<string> ongoing_imports = new Stack<string> ();
                
                internal Stack<string> OngoingImports {
@@ -382,12 +396,12 @@ namespace Microsoft.Build.Evaluation
                        // FIXME: add MSBuildProgramFiles32
                        yield return create ("MSBuildProjectDefaultTargets", () => project.DefaultTargets);
                        yield return create ("MSBuildProjectDirectory", () => project.DirectoryPath + Path.DirectorySeparatorChar);
-                       // FIXME: add MSBuildProjectDirectoryNoRoot
+                       yield return create ("MSBuildProjectDirectoryNoRoot", () => project.DirectoryPath.Substring (Path.GetPathRoot (project.DirectoryPath).Length));
                        yield return create ("MSBuildProjectExtension", () => Path.GetExtension (project.FullPath));
                        yield return create ("MSBuildProjectFile", () => Path.GetFileName (project.FullPath));
                        yield return create ("MSBuildProjectFullPath", () => project.FullPath);
                        yield return create ("MSBuildProjectName", () => Path.GetFileNameWithoutExtension (project.FullPath));
-                       // FIXME: add MSBuildStartupDirectory
+                       yield return create ("MSBuildStartupDirectory", () => BuildStartupDirectory);
                        yield return create ("MSBuildThisFile", () => Path.GetFileName (GetEvaluationTimeThisFile (projectFullPath)));
                        yield return create ("MSBuildThisFileFullPath", () => GetEvaluationTimeThisFile (projectFullPath));
                        yield return create ("MSBuildThisFileName", () => Path.GetFileNameWithoutExtension (GetEvaluationTimeThisFile (projectFullPath)));
@@ -398,6 +412,8 @@ namespace Microsoft.Build.Evaluation
                                string dir = GetEvaluationTimeThisFileDirectory (projectFullPath) + Path.DirectorySeparatorChar;
                                return dir.Substring (Path.GetPathRoot (dir).Length);
                                });
+                       yield return create ("MSBuildToolsPath", () => toolset.ToolsPath);
+                       yield return create ("MSBuildToolsVersion", () => toolset.ToolsVersion);
                }
                
                // These are required for reserved property, represents dynamically changing property values.
@@ -413,5 +429,69 @@ namespace Microsoft.Build.Evaluation
                {
                        return OngoingImports.Count > 0 ? OngoingImports.Peek () : (nonImportingTimeFullPath () ?? string.Empty);
                }
+               
+               static readonly char [] item_target_sep = {';'};
+               
+               internal static IEnumerable<T> GetAllItems<T> (Func<string,string> expandString, string include, string exclude, Func<string,T> creator, Func<string,ITaskItem> taskItemCreator, string directory, Action<T,string> assignRecurse, Func<ITaskItem,bool> isDuplicate)
+               {
+                       var includes = expandString (include).Trim ().Split (item_target_sep, StringSplitOptions.RemoveEmptyEntries);
+                       var excludes = expandString (exclude).Trim ().Split (item_target_sep, StringSplitOptions.RemoveEmptyEntries);
+                       
+                       if (includes.Length == 0)
+                               yield break;
+                       if (includes.Length == 1 && includes [0].IndexOf ('*') < 0 && excludes.Length == 0) {
+                               // for most case - shortcut.
+                               var item = creator (includes [0]);
+                               yield return item;
+                       } else {
+                               var ds = new Microsoft.Build.BuildEngine.DirectoryScanner () {
+                                       BaseDirectory = new DirectoryInfo (directory),
+                                       Includes = includes.Where (s => !string.IsNullOrWhiteSpace (s)).Select (i => taskItemCreator (i)).ToArray (),
+                                       Excludes = excludes.Where (s => !string.IsNullOrWhiteSpace (s)).Select (e => taskItemCreator (e)).ToArray (),
+                               };
+                               ds.Scan ();
+                               foreach (var taskItem in ds.MatchedItems) {
+                                       if (isDuplicate (taskItem))
+                                               continue; // skip duplicate
+                                       var item = creator (taskItem.ItemSpec);
+                                       string recurse = taskItem.GetMetadata ("RecursiveDir");
+                                       assignRecurse (item, recurse);
+                                       yield return item;
+                               }
+                       }
+               }
+               
+               static readonly char [] path_sep = {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
+               
+               internal static string GetWellKnownMetadata (string name, string file, Func<string,string> getFullPath, string recursiveDir)
+               {
+                       switch (name.ToLower (CultureInfo.InvariantCulture)) {
+                       case "fullpath":
+                               return getFullPath (file);
+                       case "rootdir":
+                               return Path.GetPathRoot (getFullPath (file));
+                       case "filename":
+                               return Path.GetFileNameWithoutExtension (file);
+                       case "extension":
+                               return Path.GetExtension (file);
+                       case "relativedir":
+                                       var idx = file.LastIndexOfAny (path_sep);
+                                       return idx < 0 ? string.Empty : file.Substring (0, idx + 1);
+                       case "directory":
+                                       var fp = getFullPath (file);
+                                       return Path.GetDirectoryName (fp).Substring (Path.GetPathRoot (fp).Length);
+                       case "recursivedir":
+                               return recursiveDir;
+                       case "identity":
+                               return file;
+                       case "modifiedtime":
+                               return new FileInfo (getFullPath (file)).LastWriteTime.ToString ("yyyy-MM-dd HH:mm:ss.fffffff");
+                       case "createdtime":
+                               return new FileInfo (getFullPath (file)).CreationTime.ToString ("yyyy-MM-dd HH:mm:ss.fffffff");
+                       case "accessedtime":
+                               return new FileInfo (getFullPath (file)).LastAccessTime.ToString ("yyyy-MM-dd HH:mm:ss.fffffff");
+                       }
+                       return null;
+               }
        }
 }