Merge pull request #1508 from slluis/fix-20966
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Project.cs
index ac6b72dfcae424b8d3725e18330fb92e09a884ab..005752baf98e12f541683c8aa9f258b6a7d03354 100644 (file)
@@ -38,6 +38,7 @@ using System.Text;
 using System.Xml;
 using System.Xml.Schema;
 using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
 using Mono.XBuild.Framework;
 using Mono.XBuild.CommandLine;
 
@@ -322,9 +323,7 @@ namespace Microsoft.Build.BuildEngine {
                                Reevaluate ();
                        }
 
-#if NET_4_0
                        ProcessBeforeAndAfterTargets ();
-#endif
 
                        if (targetNames == null || targetNames.Length == 0) {
                                if (defaultTargets != null && defaultTargets.Length != 0) {
@@ -390,7 +389,7 @@ namespace Microsoft.Build.BuildEngine {
                internal string GetKeyForTarget (string target_name, bool include_global_properties)
                {
                        // target name is case insensitive
-                       return fullFileName + ":" + target_name.ToLower () +
+                       return fullFileName + ":" + target_name.ToLowerInvariant () +
                                        (include_global_properties ? (":" + GlobalPropertiesToString (GlobalProperties))
                                                                   : String.Empty);
                }
@@ -403,7 +402,6 @@ namespace Microsoft.Build.BuildEngine {
                        return sb.ToString ();
                }
 
-#if NET_4_0
                void ProcessBeforeAndAfterTargets ()
                {
                        var beforeTable = Targets.AsIEnumerable ()
@@ -439,7 +437,6 @@ namespace Microsoft.Build.BuildEngine {
                        expr.Parse (targets, ParseOptions.AllowItemsNoMetadataAndSplit);
                        return (string []) expr.ConvertTo (this, typeof (string []));
                }
-#endif
 
                [MonoTODO]
                public string [] GetConditionedPropertyValues (string propertyName)
@@ -555,7 +552,8 @@ namespace Microsoft.Build.BuildEngine {
                public void Load (TextReader textReader, ProjectLoadSettings projectLoadSettings)
                {
                        project_load_settings = projectLoadSettings;
-                       fullFileName = String.Empty;
+                       if (!string.IsNullOrEmpty (fullFileName))
+                               PushThisFileProperty (fullFileName);
                        DoLoad (textReader);
                }
 
@@ -567,7 +565,8 @@ namespace Microsoft.Build.BuildEngine {
                public void LoadXml (string projectXml, ProjectLoadSettings projectLoadSettings)
                {
                        project_load_settings = projectLoadSettings;
-                       fullFileName = String.Empty;
+                       if (!string.IsNullOrEmpty (fullFileName))
+                               PushThisFileProperty (fullFileName);
                        DoLoad (new StringReader (projectXml));
                        MarkProjectAsDirty ();
                }
@@ -935,6 +934,9 @@ namespace Microsoft.Build.BuildEngine {
                                        case "Import":
                                                AddImport (xe, ip, true);
                                                break;
+                                       case "ImportGroup":
+                                               AddImportGroup (xe, ip, true);
+                                               break;
                                        case "ItemGroup":
                                                AddItemGroup (xe, ip);
                                                break;
@@ -944,8 +946,12 @@ namespace Microsoft.Build.BuildEngine {
                                        case  "Choose":
                                                AddChoose (xe, ip);
                                                break;
+                                       case "ItemDefinitionGroup":
+                                               AddItemDefinitionGroup (xe);
+                                               break;
                                        default:
-                                               throw new InvalidProjectFileException (String.Format ("Invalid element '{0}' in project file.", xe.Name));
+                                               var pf = ip == null ? null : string.Format (" '{0}'", ip.FullFileName);
+                                               throw new InvalidProjectFileException (String.Format ("Invalid element '{0}' in project file{1}.", xe.Name, pf));
                                        }
                                }
                        }
@@ -1027,7 +1033,17 @@ namespace Microsoft.Build.BuildEngine {
                        SetExtensionsPathProperties (DefaultExtensionsPath);
                        evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets", DefaultTargets, PropertyType.Reserved));
                        evaluatedProperties.AddProperty (new BuildProperty ("OS", OS, PropertyType.Environment));
+#if XBUILD_12
+                       // see http://msdn.microsoft.com/en-us/library/vstudio/hh162058(v=vs.120).aspx
+                       if (effective_tools_version == "12.0") {
+                               evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath32", toolsPath, PropertyType.Reserved));
+
+                               var frameworkToolsPath = ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version451);
 
+                               evaluatedProperties.AddProperty (new BuildProperty ("MSBuildFrameworkToolsPath", frameworkToolsPath, PropertyType.Reserved));
+                               evaluatedProperties.AddProperty (new BuildProperty ("MSBuildFrameworkToolsPath32", frameworkToolsPath, PropertyType.Reserved));
+                       }
+#endif
                        // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
                        string projectDir;
                        if (FullFileName == String.Empty)
@@ -1102,9 +1118,9 @@ namespace Microsoft.Build.BuildEngine {
                void AddImport (XmlElement xmlElement, ImportedProject importingProject, bool evaluate_properties)
                {
                        // eval all the properties etc till the import
-                       if (evaluate_properties)
-                               groupingCollection.Evaluate (EvaluationType.Property);
-
+                       if (evaluate_properties) {
+                               groupingCollection.Evaluate (EvaluationType.Property | EvaluationType.Choose);
+                       }
                        try {
                                PushThisFileProperty (importingProject != null ? importingProject.FullFileName : FullFileName);
 
@@ -1119,6 +1135,40 @@ namespace Microsoft.Build.BuildEngine {
                        }
                }
 
+               void AddImportGroup (XmlElement xmlElement, ImportedProject importedProject, bool evaluate_properties)
+               {
+                       // eval all the properties etc till the import group
+                       if (evaluate_properties) {
+                               groupingCollection.Evaluate (EvaluationType.Property | EvaluationType.Choose);
+                       }
+                       string condition_attribute = xmlElement.GetAttribute ("Condition");
+                       if (!ConditionParser.ParseAndEvaluate (condition_attribute, this))
+                               return;
+                       foreach (XmlNode xn in xmlElement.ChildNodes) {
+                               if (xn is XmlElement) {
+                                       XmlElement xe = (XmlElement) xn;
+                                       switch (xe.Name) {
+                                       case "Import":
+                                               AddImport (xe, importedProject, evaluate_properties);
+                                               break;
+                                       default:
+                                               throw new InvalidProjectFileException(String.Format("Invalid element '{0}' inside ImportGroup in project file '{1}'.", xe.Name, importedProject.FullFileName));
+                                       }
+                               }
+                       }
+               }
+
+               void AddItemDefinitionGroup (XmlElement xmlElement)
+               {
+                       string condition_attribute = xmlElement.GetAttribute ("Condition");
+                       if (!ConditionParser.ParseAndEvaluate (condition_attribute, this))
+                               return;
+
+                       foreach (XmlNode xn in xmlElement.ChildNodes) {
+                               // TODO: Add all nodes to some internal dictionary?
+                       }
+               }
+
                bool AddSingleImport (XmlElement xmlElement, string projectPath, ImportedProject importingProject, string from_source_msg)
                {
                        Import import = new Import (xmlElement, projectPath, this, importingProject);
@@ -1375,6 +1425,10 @@ namespace Microsoft.Build.BuildEngine {
                        return default (T);
                }
 
+               internal string ThisFileFullPath {
+                       get { return this_file_property_stack.Peek (); }
+               }
+
                // Used for MSBuild*This* set of properties
                internal void PushThisFileProperty (string full_filename)
                {
@@ -1558,7 +1612,7 @@ namespace Microsoft.Build.BuildEngine {
                                return xmlDocument != null && xmlDocument.DocumentElement.HasAttribute ("ToolsVersion");
                        }
                }
-               
+
                public string ToolsVersion {
                        get; internal set;
                }
@@ -1567,6 +1621,11 @@ namespace Microsoft.Build.BuildEngine {
                        get { return last_item_group_containing; }
                }
                
+               internal ProjectLoadSettings ProjectLoadSettings {
+                       get { return project_load_settings; }
+                       set { project_load_settings = value; }
+               }
+
                internal static XmlNamespaceManager XmlNamespaceManager {
                        get {
                                if (manager == null) {