Implementation of the 2.0 session state model
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Project.cs
index efae3c78de540fa68dfe243babd888de6f8523bc..fbd9517409dd76b5f06f3ec3e0543caff056106d 100644 (file)
@@ -42,7 +42,6 @@ namespace Microsoft.Build.BuildEngine {
        public class Project {
        
                bool                            buildEnabled;
-               //IDictionary                   conditionedProperties;
                Dictionary <string, List <string>>      conditionedProperties;
                string[]                        defaultTargets;
                Encoding                        encoding;
@@ -54,7 +53,7 @@ namespace Microsoft.Build.BuildEngine {
                string                          firstTargetName;
                string                          fullFileName;
                BuildPropertyGroup              globalProperties;
-               GroupingCollection              groups;
+               GroupingCollection              groupingCollection;
                bool                            isDirty;
                bool                            isValidated;
                BuildItemGroupCollection        itemGroups;
@@ -80,18 +79,20 @@ namespace Microsoft.Build.BuildEngine {
 
                public Project (Engine engine)
                {
+                       buildEnabled = engine.BuildEnabled;
                        parentEngine  = engine;
                        xmlDocument = new XmlDocument ();
-                       groups = new GroupingCollection ();
-                       imports = new ImportCollection (this);
+                       groupingCollection = new GroupingCollection (this);
+                       imports = new ImportCollection (groupingCollection);
                        usingTasks = new UsingTaskCollection (this);
-                       itemGroups = new BuildItemGroupCollection (groups);
-                       propertyGroups = new BuildPropertyGroupCollection (groups);
+                       itemGroups = new BuildItemGroupCollection (groupingCollection);
+                       propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
                        targets = new TargetCollection (this);
                        
                        taskDatabase = new TaskDatabase ();
-                       if (engine.DefaultTasksRegistered == true)
+                       if (engine.DefaultTasksRegistered) {
                                taskDatabase.CopyTasks (engine.DefaultTasks);
+                       }
                        
                        globalProperties = new BuildPropertyGroup ();
                        fullFileName = String.Empty;
@@ -161,23 +162,20 @@ namespace Microsoft.Build.BuildEngine {
                [MonoTODO]
                public bool Build (string targetName)
                {
-                       if (targets.Exists (targetName) == false)
-                               throw new Exception (String.Format ("Target {0} does not exist.", targetName));
-                       
-                       return this.targets [targetName].Build ();
+                       return Build (new string [1] { targetName });
                }
                
                [MonoTODO]
                public bool Build (string[] targetNames)
                {
-                       return Build (targetNames, new Hashtable ());
+                       return Build (targetNames, null);
                }
                
                [MonoTODO]
                public bool Build (string[] targetNames,
                                   IDictionary targetOutputs)
                {
-                       return Build (targetNames, new Hashtable (), BuildSettings.None);
+                       return Build (targetNames, targetOutputs, BuildSettings.None);
                }
                
                [MonoTODO]
@@ -187,21 +185,25 @@ namespace Microsoft.Build.BuildEngine {
                
                {
                        CheckUnloaded ();
+                       
                        if (targetNames.Length == 0) {
-                               if (defaultTargets != null && defaultTargets.Length != 0) {
+                               if (defaultTargets != null && defaultTargets.Length != 0)
                                        targetNames = defaultTargets;
-                               }
-                               else if (firstTargetName != null) {
+                               else if (firstTargetName != null)
                                        targetNames = new string [1] { firstTargetName};
-                               }
                                else
                                        return false;
                        }
+                       
                        foreach (string target in targetNames) {
-                               if (Build (target) == false) {
+                               if (!targets.Exists (target))
+                                       // FIXME: test if it's logged
+                                       return false;
+                               
+                               if (!targets [target].Build ())
                                        return false;
-                               }
                        }
+                               
                        return true;
                }
 
@@ -219,7 +221,7 @@ namespace Microsoft.Build.BuildEngine {
                        if (evaluatedItemsByName.ContainsKey (itemName))
                                return evaluatedItemsByName [itemName];
                        else
-                               return null;
+                               return new BuildItemGroup ();
                }
 
                public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
@@ -227,12 +229,17 @@ namespace Microsoft.Build.BuildEngine {
                        if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
                                return evaluatedItemsByNameIgnoringCondition [itemName];
                        else
-                               return null;
+                               return new BuildItemGroup ();
                }
 
                public string GetEvaluatedProperty (string propertyName)
                {
-                       return (string) evaluatedProperties [propertyName];
+                       if (propertyName == null)
+                               throw new ArgumentNullException ("propertyName");
+
+                       BuildProperty bp = evaluatedProperties [propertyName];
+
+                       return bp == null ? null : (string) bp;
                }
 
                public string GetProjectExtensions (string id)
@@ -242,48 +249,17 @@ namespace Microsoft.Build.BuildEngine {
 
                        XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
 
-                       // FIXME: InnerXml or InnerText?
                        if (node == null)
                                return String.Empty;
                        else
                                return node.InnerXml;
                }
 
-               // Does the actual loading.
-               private void DoLoad (TextReader textReader)
-               {
-                       ParentEngine.RemoveLoadedProject (this);
-
-                       XmlReaderSettings settings = new XmlReaderSettings ();
-
-                       if (SchemaFile != null) {
-                               settings.Schemas.Add (null, SchemaFile);
-                               settings.ValidationType = ValidationType.Schema;
-                               settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
-                       }
-
-                       XmlReader xmlReader = XmlReader.Create (textReader, settings);
-                       xmlDocument.Load (xmlReader);
-
-                       if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
-                               throw new InvalidProjectFileException (
-                                       @"The default XML namespace of the project must be the MSBuild XML namespace." + 
-                                       " If the project is authored in the MSBuild 2003 format, please add " +
-                                       "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
-                                       "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  ");
-                       }
-                       ProcessXml ();
-                       ParentEngine.AddLoadedProject (this);
-               }
 
                public void Load (string projectFileName)
                {
                        this.fullFileName = Path.GetFullPath (projectFileName);
-                       try {
-                               DoLoad (new StreamReader (projectFileName));
-                       } catch {
-                               Console.WriteLine ("Failure to load: {0}", projectFileName);
-                       }
+                       DoLoad (new StreamReader (projectFileName));
                }
                
                [MonoTODO]
@@ -297,95 +273,14 @@ namespace Microsoft.Build.BuildEngine {
                {
                        fullFileName = String.Empty;
                        DoLoad (new StringReader (projectXml));
+                       MarkProjectAsDirty ();
                }
 
-               internal void Unload ()
-               {
-                       unloaded = true;
-               }
-
-               internal void CheckUnloaded ()
-               {
-                       if (unloaded)
-                               throw new InvalidOperationException ("This project object is no longer valid.");
-               }
-
-               private void ProcessXml ()
-               {
-                       XmlElement xmlElement = xmlDocument.DocumentElement;
-                       if (xmlElement.Name != "Project")
-                               throw new InvalidProjectFileException ("Invalid root element.");
-                       if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
-                               defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
-                       else
-                               defaultTargets = new string [0];
-                       
-                       ProcessElements (xmlElement, null);
-                       
-                       isDirty = false;
-                       Evaluate ();
-               }
-
-               private void InitializeProperties ()
-               {
-                       BuildProperty bp;
-
-                       foreach (BuildProperty gp in GlobalProperties) {
-                               bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
-                               EvaluatedProperties.AddProperty (bp);
-                       }
-                       
-                       foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
-                               bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
-                               EvaluatedProperties.AddProperty (bp);
-                       }
-
-                       bp = new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved);
-                       EvaluatedProperties.AddProperty (bp);
-               }
-
-               internal void Evaluate ()
-               {
-                       evaluatedItems = new BuildItemGroup (null, this);
-                       evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this);
-                       evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
-                       evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
-                       evaluatedProperties = new BuildPropertyGroup ();
-
-                       InitializeProperties ();
-
-                       // FIXME: questionable order of evaluation
-                       
-                       foreach (Import import in Imports)
-                               import.Evaluate ();
-                       
-                       foreach (BuildPropertyGroup bpg in PropertyGroups) {
-                               if (bpg.Condition == String.Empty)
-                                       bpg.Evaluate ();
-                               else {
-                                       ConditionExpression ce = ConditionParser.ParseCondition (bpg.Condition);
-                                       if (ce.BoolEvaluate (this))
-                                               bpg.Evaluate ();
-                               }
-                       }
-                       
-                       foreach (BuildItemGroup big in ItemGroups) {
-                               if (big.Condition == String.Empty)
-                                       big.Evaluate ();
-                               else {
-                                       ConditionExpression ce = ConditionParser.ParseCondition (big.Condition);
-                                       if (ce.BoolEvaluate (this))
-                                               big.Evaluate ();
-                               }
-                       }
-                       
-                       foreach (UsingTask usingTask in UsingTasks)
-                               usingTask.Evaluate ();
-               }
 
                public void MarkProjectAsDirty ()
                {
                        isDirty = true;
+                       timeOfLastDirty = DateTime.Now;
                }
 
                [MonoTODO]
@@ -459,7 +354,6 @@ namespace Microsoft.Build.BuildEngine {
                        xmlDocument.Save (outTextWriter);
                }
 
-               [MonoTODO]
                public void SetImportedProperty (string propertyName,
                                                 string propertyValue,
                                                 string condition,
@@ -469,7 +363,6 @@ namespace Microsoft.Build.BuildEngine {
                                PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
                }
 
-               [MonoTODO]
                public void SetImportedProperty (string propertyName,
                                                 string propertyValue,
                                                 string condition,
@@ -491,10 +384,36 @@ namespace Microsoft.Build.BuildEngine {
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                public void SetProjectExtensions (string id, string xmlText)
                {
-                       throw new NotImplementedException ();
+                       XmlNode projectExtensions, node;
+
+                       if (id == null || id == String.Empty || xmlText == null)
+                               return;
+
+                       projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
+                       
+                       
+                       if (projectExtensions == null) {
+                               projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
+                               xmlDocument.DocumentElement.AppendChild (projectExtensions);
+
+                               node = xmlDocument.CreateElement (id, XmlNamespace);
+                               node.InnerXml = xmlText;
+                               projectExtensions.AppendChild (node);
+                       } else {
+                               node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
+
+                               if (node == null) {
+                                       node = xmlDocument.CreateElement (id, XmlNamespace);
+                                       projectExtensions.AppendChild (node);
+                               }
+                               
+                               node.InnerXml = xmlText;
+                               
+                       }
+
+                       MarkProjectAsDirty ();
                }
                
                [MonoTODO]
@@ -534,6 +453,69 @@ namespace Microsoft.Build.BuildEngine {
                        throw new NotImplementedException ();
                }
 
+               internal void Unload ()
+               {
+                       unloaded = true;
+               }
+
+               internal void CheckUnloaded ()
+               {
+                       if (unloaded)
+                               throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
+               }
+                               
+               // Does the actual loading.
+               void DoLoad (TextReader textReader)
+               {
+                       try {
+                               ParentEngine.RemoveLoadedProject (this);
+       
+                               XmlReaderSettings settings = new XmlReaderSettings ();
+       
+                               if (SchemaFile != null) {
+                                       settings.Schemas.Add (null, SchemaFile);
+                                       settings.ValidationType = ValidationType.Schema;
+                                       settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
+                               }
+       
+                               XmlReader xmlReader = XmlReader.Create (textReader, settings);
+                               xmlDocument.Load (xmlReader);
+
+                               if (xmlDocument.DocumentElement.Name != "Project") {
+                                       throw new InvalidProjectFileException (String.Format (
+                                               "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
+                               }
+       
+                               if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
+                                       throw new InvalidProjectFileException (
+                                               @"The default XML namespace of the project must be the MSBuild XML namespace." + 
+                                               " If the project is authored in the MSBuild 2003 format, please add " +
+                                               "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
+                                               "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  ");
+                               }
+                               ProcessXml ();
+                               ParentEngine.AddLoadedProject (this);
+                       } catch (Exception e) {
+                               throw new InvalidProjectFileException (e.Message, e);
+                       }
+               }
+
+               void ProcessXml ()
+               {
+                       XmlElement xmlElement = xmlDocument.DocumentElement;
+                       if (xmlElement.Name != "Project")
+                               throw new InvalidProjectFileException ("Invalid root element.");
+                       if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
+                               defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
+                       else
+                               defaultTargets = new string [0];
+                       
+                       ProcessElements (xmlElement, null);
+                       
+                       isDirty = false;
+                       Evaluate ();
+               }
+               
                internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
                {
                        foreach (XmlNode xn in rootElement.ChildNodes) {
@@ -558,10 +540,10 @@ namespace Microsoft.Build.BuildEngine {
                                                AddImport (xe, ip);
                                                break;
                                        case "ItemGroup":
-                                               AddItemGroup (xe);
+                                               AddItemGroup (xe, ip);
                                                break;
                                        case "PropertyGroup":
-                                               AddPropertyGroup (xe);
+                                               AddPropertyGroup (xe, ip);
                                                break;
                                        case  "Choose":
                                                AddChoose (xe);
@@ -573,33 +555,59 @@ namespace Microsoft.Build.BuildEngine {
                        }
                }
                
-               private void AddProjectExtensions (XmlElement xmlElement)
+               internal void Evaluate ()
+               {
+                       evaluatedItems = new BuildItemGroup (null, this, null);
+                       evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null);
+                       evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
+                       evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
+                       evaluatedProperties = new BuildPropertyGroup ();
+
+                       InitializeProperties ();
+
+                       groupingCollection.Evaluate ();
+
+                       //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
+                       foreach (UsingTask usingTask in UsingTasks)
+                               usingTask.Evaluate ();
+               }
+
+               private void InitializeProperties ()
+               {
+                       BuildProperty bp;
+
+                       foreach (BuildProperty gp in GlobalProperties) {
+                               bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
+                               EvaluatedProperties.AddProperty (bp);
+                       }
+                       
+                       foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
+                               bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
+                               EvaluatedProperties.AddProperty (bp);
+                       }
+
+                       bp = new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved);
+                       EvaluatedProperties.AddProperty (bp);
+               }
+               
+               void AddProjectExtensions (XmlElement xmlElement)
                {
-                       if (xmlElement == null)
-                               throw new ArgumentNullException ("xmlElement");
                }
                
-               private void AddMessage (XmlElement xmlElement)
+               void AddMessage (XmlElement xmlElement)
                {
-                       if (xmlElement == null)
-                               throw new ArgumentNullException ("xmlElement");
                }
                
-               private void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
+               void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
                {
-                       if (xmlElement == null)
-                               throw new ArgumentNullException ("xmlElement");
-                       Target target = new Target (xmlElement, this);
+                       Target target = new Target (xmlElement, this, importedProject);
                        targets.AddTarget (target);
-                       if (importedProject == null) {
-                               target.IsImported = false;
-                               if (firstTargetName == null)
-                                       firstTargetName = target.Name;
-                       } else
-                               target.IsImported = true;
+                       
+                       if (firstTargetName == null)
+                               firstTargetName = target.Name;
                }
                
-               private void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
+               void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
                {
                        UsingTask usingTask;
 
@@ -607,7 +615,7 @@ namespace Microsoft.Build.BuildEngine {
                        UsingTasks.Add (usingTask);
                }
                
-               private void AddImport (XmlElement xmlElement, ImportedProject importingProject)
+               void AddImport (XmlElement xmlElement, ImportedProject importingProject)
                {
                        Import import;
                        
@@ -615,35 +623,26 @@ namespace Microsoft.Build.BuildEngine {
                        Imports.Add (import);
                }
                
-               private void AddItemGroup (XmlElement xmlElement)
+               void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
                {
-                       if (xmlElement == null)
-                               throw new ArgumentNullException ("xmlElement");
-                       BuildItemGroup big = new BuildItemGroup (xmlElement, this);
+                       BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject);
                        ItemGroups.Add (big);
-                       //big.Evaluate ();
                }
                
-               private void AddPropertyGroup (XmlElement xmlElement)
+               void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
                {
-                       if (xmlElement == null)
-                               throw new ArgumentNullException ("xmlElement");
-                       BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this);
+                       BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject);
                        PropertyGroups.Add (bpg);
-                       //bpg.Evaluate ();
                }
                
-               private void AddChoose (XmlElement xmlElement)
+               void AddChoose (XmlElement xmlElement)
                {
-                       if (xmlElement == null)
-                               throw new ArgumentNullException ("xmlElement");
-                               
                        BuildChoose bc = new BuildChoose (xmlElement, this);
-                       groups.Add (bc);
+                       groupingCollection.Add (bc);
                        
                }
                
-               private static void ValidationCallBack (object sender, ValidationEventArgs e)
+               static void ValidationCallBack (object sender, ValidationEventArgs e)
                {
                        Console.WriteLine ("Validation Error: {0}", e.Message);
                }
@@ -679,11 +678,11 @@ namespace Microsoft.Build.BuildEngine {
                        get { return evaluatedItemsIgnoringCondition; }
                }
                
-               internal IDictionary EvaluatedItemsByName {
+               internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
                        get { return evaluatedItemsByName; }
                }
                
-               internal IDictionary EvaluatedItemsByNameIgnoringCondition {
+               internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
                        get { return evaluatedItemsByNameIgnoringCondition; }
                }