d8f0a92061f122bff013b68ace698981a5f09306
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Project.cs
1 //
2 // Project.cs: Project class
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27
28 #if NET_2_0
29
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Collections.Specialized;
34 using System.IO;
35 using System.Reflection;
36 using System.Text;
37 using System.Xml;
38 using System.Xml.Schema;
39 using Microsoft.Build.Framework;
40 using Mono.XBuild.Framework;
41 using Mono.XBuild.CommandLine;
42
43 namespace Microsoft.Build.BuildEngine {
44         public class Project {
45         
46                 bool                            buildEnabled;
47                 Dictionary <string, List <string>>      conditionedProperties;
48                 string[]                        defaultTargets;
49                 Encoding                        encoding;
50                 BuildItemGroup                  evaluatedItems;
51                 BuildItemGroup                  evaluatedItemsIgnoringCondition;
52                 Dictionary <string, BuildItemGroup>     evaluatedItemsByName;
53                 Dictionary <string, BuildItemGroup>     evaluatedItemsByNameIgnoringCondition;
54                 BuildPropertyGroup              evaluatedProperties;
55                 string                          firstTargetName;
56                 string                          fullFileName;
57                 BuildPropertyGroup              globalProperties;
58                 GroupingCollection              groupingCollection;
59                 bool                            isDirty;
60                 bool                            isValidated;
61                 BuildItemGroupCollection        itemGroups;
62                 ImportCollection                imports;
63                 List<string>                    initialTargets;
64                 Dictionary <string, BuildItemGroup> last_item_group_containing;
65                 bool                            needToReevaluate;
66                 Engine                          parentEngine;
67                 BuildPropertyGroupCollection    propertyGroups;
68                 string                          schemaFile;
69                 TaskDatabase                    taskDatabase;
70                 TargetCollection                targets;
71                 DateTime                        timeOfLastDirty;
72                 UsingTaskCollection             usingTasks;
73                 XmlDocument                     xmlDocument;
74                 bool                            unloaded;
75                 bool                            initialTargetsBuilt;
76                 bool                            building;
77                 BuildSettings                   current_settings;
78                 Stack<Batch>                    batches;
79                 ProjectLoadSettings             project_load_settings;
80
81
82                 static string extensions_path;
83                 static XmlNamespaceManager      manager;
84                 static string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
85
86                 public Project ()
87                         : this (Engine.GlobalEngine)
88                 {
89                 }
90
91                 public Project (Engine engine) : this (engine, null)
92                 {
93                 }
94                 
95                 public Project (Engine engine, string toolsVersion)
96                 {
97                         parentEngine  = engine;
98                         ToolsVersion = toolsVersion;
99
100                         buildEnabled = ParentEngine.BuildEnabled;
101                         xmlDocument = new XmlDocument ();
102                         xmlDocument.PreserveWhitespace = false;
103                         xmlDocument.AppendChild (xmlDocument.CreateElement ("Project", XmlNamespace));
104                         xmlDocument.DocumentElement.SetAttribute ("xmlns", ns);
105                         
106                         fullFileName = String.Empty;
107                         timeOfLastDirty = DateTime.Now;
108                         current_settings = BuildSettings.None;
109                         project_load_settings = ProjectLoadSettings.None;
110
111                         encoding = null;
112
113                         initialTargets = new List<string> ();
114                         defaultTargets = new string [0];
115                         batches = new Stack<Batch> ();
116
117                         globalProperties = new BuildPropertyGroup (null, this, null, false);
118                         foreach (BuildProperty bp in parentEngine.GlobalProperties)
119                                 GlobalProperties.AddProperty (bp.Clone (true));
120                         
121                         ProcessXml ();
122
123                 }
124
125                 [MonoTODO ("Not tested")]
126                 public void AddNewImport (string importLocation,
127                                           string importCondition)
128                 {
129                         if (importLocation == null)
130                                 throw new ArgumentNullException ("importLocation");
131
132                         XmlElement importElement = xmlDocument.CreateElement ("Import", XmlNamespace);
133                         xmlDocument.DocumentElement.AppendChild (importElement);
134                         importElement.SetAttribute ("Project", importLocation);
135                         if (!String.IsNullOrEmpty (importCondition))
136                                 importElement.SetAttribute ("Condition", importCondition);
137
138                         Import import = new Import (importElement, this, null);
139                         imports.Add (import);
140                         MarkProjectAsDirty ();
141                         NeedToReevaluate ();
142                 }
143
144                 public BuildItem AddNewItem (string itemName,
145                                              string itemInclude)
146                 {
147                         return AddNewItem (itemName, itemInclude, false);
148                 }
149                 
150                 [MonoTODO ("Adds item not in the same place as MS")]
151                 public BuildItem AddNewItem (string itemName,
152                                              string itemInclude,
153                                              bool treatItemIncludeAsLiteral)
154                 {
155                         BuildItemGroup big;
156
157                         if (itemGroups.Count == 0)
158                                 big = AddNewItemGroup ();
159                         else {
160                                 if (last_item_group_containing.ContainsKey (itemName)) {
161                                         big = last_item_group_containing [itemName];
162                                 } else {
163                                         // FIXME: not tested
164                                         BuildItemGroup [] groups = new BuildItemGroup [itemGroups.Count];
165                                         itemGroups.CopyTo (groups, 0);
166                                         big = groups [0];
167                                 }
168                         }
169
170                         BuildItem item = big.AddNewItem (itemName, itemInclude, treatItemIncludeAsLiteral);
171                                 
172                         MarkProjectAsDirty ();
173                         NeedToReevaluate ();
174
175                         return item;
176                 }
177
178                 [MonoTODO ("Not tested")]
179                 public BuildItemGroup AddNewItemGroup ()
180                 {
181                         XmlElement element = xmlDocument.CreateElement ("ItemGroup", XmlNamespace);
182                         xmlDocument.DocumentElement.AppendChild (element);
183
184                         BuildItemGroup big = new BuildItemGroup (element, this, null, false);
185                         itemGroups.Add (big);
186                         MarkProjectAsDirty ();
187                         NeedToReevaluate ();
188
189                         return big;
190                 }
191
192                 [MonoTODO ("Ignores insertAtEndOfProject")]
193                 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
194                 {
195                         XmlElement element = xmlDocument.CreateElement ("PropertyGroup", XmlNamespace);
196                         xmlDocument.DocumentElement.AppendChild (element);
197
198                         BuildPropertyGroup bpg = new BuildPropertyGroup (element, this, null, false);
199                         propertyGroups.Add (bpg);
200                         MarkProjectAsDirty ();
201                         NeedToReevaluate ();
202
203                         return bpg;
204                 }
205                 
206                 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
207                 public void AddNewUsingTaskFromAssemblyFile (string taskName,
208                                                              string assemblyFile)
209                 {
210                         if (taskName == null)
211                                 throw new ArgumentNullException ("taskName");
212                         if (assemblyFile == null)
213                                 throw new ArgumentNullException ("assemblyFile");
214
215                         XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
216                         xmlDocument.DocumentElement.AppendChild (element);
217                         element.SetAttribute ("TaskName", taskName);
218                         element.SetAttribute ("AssemblyFile", assemblyFile);
219
220                         UsingTask ut = new UsingTask (element, this, null);
221                         usingTasks.Add (ut);
222                         MarkProjectAsDirty ();
223                 }
224                 
225                 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
226                 public void AddNewUsingTaskFromAssemblyName (string taskName,
227                                                              string assemblyName)
228                 {
229                         if (taskName == null)
230                                 throw new ArgumentNullException ("taskName");
231                         if (assemblyName == null)
232                                 throw new ArgumentNullException ("assemblyName");
233
234                         XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
235                         xmlDocument.DocumentElement.AppendChild (element);
236                         element.SetAttribute ("TaskName", taskName);
237                         element.SetAttribute ("AssemblyName", assemblyName);
238
239                         UsingTask ut = new UsingTask (element, this, null);
240                         usingTasks.Add (ut);
241                         MarkProjectAsDirty ();
242                 }
243                 
244                 [MonoTODO ("Not tested")]
245                 public bool Build ()
246                 {
247                         return Build (new string [0]);
248                 }
249                 
250                 [MonoTODO ("Not tested")]
251                 public bool Build (string targetName)
252                 {
253                         if (targetName == null)
254                                 return Build ((string[]) null);
255                         else
256                                 return Build (new string [1] { targetName });
257                 }
258                 
259                 [MonoTODO ("Not tested")]
260                 public bool Build (string [] targetNames)
261                 {
262                         return Build (targetNames, null);
263                 }
264                 
265                 [MonoTODO ("Not tested")]
266                 public bool Build (string [] targetNames,
267                                    IDictionary targetOutputs)
268                 {
269                         return Build (targetNames, targetOutputs, BuildSettings.None);
270                 }
271                 
272                 [MonoTODO ("Not tested")]
273                 public bool Build (string [] targetNames,
274                                    IDictionary targetOutputs,
275                                    BuildSettings buildFlags)
276                 
277                 {
278                         bool result = false;
279                         ParentEngine.StartProjectBuild (this, targetNames);
280
281                         // Invoking this to emit a warning in case of unsupported
282                         // ToolsVersion
283                         GetToolsVersionToUse (true);
284
285                         string current_directory = Environment.CurrentDirectory;
286                         try {
287                                 current_settings = buildFlags;
288                                 if (!String.IsNullOrEmpty (fullFileName))
289                                         Directory.SetCurrentDirectory (Path.GetDirectoryName (fullFileName));
290                                 building = true;
291                                 result = BuildInternal (targetNames, targetOutputs, buildFlags);
292                         } finally {
293                                 ParentEngine.EndProjectBuild (this, result);
294                                 current_settings = BuildSettings.None;
295                                 Directory.SetCurrentDirectory (current_directory);
296                                 building = false;
297                         }
298
299                         return result;
300                 }
301
302                 bool BuildInternal (string [] targetNames,
303                                    IDictionary targetOutputs,
304                                    BuildSettings buildFlags)
305                 {
306                         CheckUnloaded ();
307                         if (buildFlags == BuildSettings.None) {
308                                 needToReevaluate = false;
309                                 Reevaluate ();
310                         }
311                         
312                         if (targetNames == null || targetNames.Length == 0) {
313                                 if (defaultTargets != null && defaultTargets.Length != 0) {
314                                         targetNames = defaultTargets;
315                                 } else if (firstTargetName != null) {
316                                         targetNames = new string [1] { firstTargetName};
317                                 } else {
318                                         if (targets == null || targets.Count == 0) {
319                                                 LogError (fullFileName, "No target found in the project");
320                                                 return false;
321                                         }
322
323                                         return false;
324                                 }
325                         }
326
327                         if (!initialTargetsBuilt) {
328                                 foreach (string target in initialTargets) {
329                                         if (!BuildTarget (target.Trim (), targetOutputs))
330                                                 return false;
331                                 }
332                                 initialTargetsBuilt = true;
333                         }
334
335                         foreach (string target in targetNames)
336                                 if (!BuildTarget (target.Trim (), targetOutputs))
337                                         return false;
338                                 
339                         return true;
340                 }
341
342                 bool BuildTarget (string target_name, IDictionary targetOutputs)
343                 {
344                         if (target_name == null)
345                                 throw new ArgumentException ("targetNames cannot contain null strings");
346
347                         if (!targets.Exists (target_name)) {
348                                 LogError (fullFileName, "Target named '{0}' not found in the project.", target_name);
349                                 return false;
350                         }
351
352                         string key = GetKeyForTarget (target_name);
353                         if (!targets [target_name].Build (key))
354                                 return false;
355
356                         ITaskItem[] outputs;
357                         if (ParentEngine.BuiltTargetsOutputByName.TryGetValue (key, out outputs)) {
358                                 if (targetOutputs != null)
359                                         targetOutputs.Add (target_name, outputs);
360                         }
361                         return true;
362                 }
363
364                 internal string GetKeyForTarget (string target_name)
365                 {
366                         return GetKeyForTarget (target_name, true);
367                 }
368
369                 internal string GetKeyForTarget (string target_name, bool include_global_properties)
370                 {
371                         // target name is case insensitive
372                         return fullFileName + ":" + target_name.ToLower () +
373                                         (include_global_properties ? (":" + GlobalPropertiesToString (GlobalProperties))
374                                                                    : String.Empty);
375                 }
376
377                 string GlobalPropertiesToString (BuildPropertyGroup bgp)
378                 {
379                         StringBuilder sb = new StringBuilder ();
380                         foreach (BuildProperty bp in bgp)
381                                 sb.AppendFormat (" {0}:{1}", bp.Name, bp.FinalValue);
382                         return sb.ToString ();
383                 }
384
385                 [MonoTODO]
386                 public string [] GetConditionedPropertyValues (string propertyName)
387                 {
388                         if (conditionedProperties.ContainsKey (propertyName))
389                                 return conditionedProperties [propertyName].ToArray ();
390                         else
391                                 return new string [0];
392                 }
393
394                 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
395                 {                       
396                         if (needToReevaluate) {
397                                 needToReevaluate = false;
398                                 Reevaluate ();
399                         }
400
401                         if (evaluatedItemsByName.ContainsKey (itemName))
402                                 return evaluatedItemsByName [itemName];
403                         else
404                                 return new BuildItemGroup (this);
405                 }
406
407                 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
408                 {
409                         if (needToReevaluate) {
410                                 needToReevaluate = false;
411                                 Reevaluate ();
412                         }
413
414                         if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
415                                 return evaluatedItemsByNameIgnoringCondition [itemName];
416                         else
417                                 return new BuildItemGroup (this);
418                 }
419
420                 public string GetEvaluatedProperty (string propertyName)
421                 {
422                         if (needToReevaluate) {
423                                 needToReevaluate = false;
424                                 Reevaluate ();
425                         }
426
427                         if (propertyName == null)
428                                 throw new ArgumentNullException ("propertyName");
429
430                         BuildProperty bp = evaluatedProperties [propertyName];
431
432                         return bp == null ? null : (string) bp;
433                 }
434
435                 [MonoTODO ("We should remember that node and not use XPath to get it")]
436                 public string GetProjectExtensions (string id)
437                 {
438                         if (id == null || id == String.Empty)
439                                 return String.Empty;
440
441                         XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
442
443                         if (node == null)
444                                 return String.Empty;
445                         else
446                                 return node.InnerXml;
447                 }
448
449
450                 public void Load (string projectFileName)
451                 {
452                         Load (projectFileName, ProjectLoadSettings.None);
453                 }
454
455                 public void Load (string projectFileName, ProjectLoadSettings settings)
456                 {
457                         project_load_settings = settings;
458                         if (String.IsNullOrEmpty (projectFileName))
459                                 throw new ArgumentNullException ("projectFileName");
460
461                         if (!File.Exists (projectFileName))
462                                 throw new ArgumentException (String.Format ("Project file {0} not found", projectFileName),
463                                                 "projectFileName");
464
465                         this.fullFileName = Utilities.FromMSBuildPath (Path.GetFullPath (projectFileName));
466
467                         string filename = fullFileName;
468                         if (String.Compare (Path.GetExtension (fullFileName), ".sln", true) == 0) {
469                                 Project tmp_project = ParentEngine.CreateNewProject ();
470                                 SolutionParser sln_parser = new SolutionParser ();
471                                 sln_parser.ParseSolution (fullFileName, tmp_project, delegate (int errorNumber, string message) {
472                                                 LogWarning (filename, message);
473                                         });
474                                 filename = fullFileName + ".proj";
475                                 try {
476                                         tmp_project.Save (filename);
477                                         ParentEngine.RemoveLoadedProject (tmp_project);
478                                         DoLoad (new StreamReader (filename));
479                                 } finally {
480                                         if (Environment.GetEnvironmentVariable ("XBUILD_EMIT_SOLUTION") == null)
481                                                 File.Delete (filename);
482                                 }
483                         } else {
484                                 DoLoad (new StreamReader (filename));
485                         }
486                 }
487                 
488                 [MonoTODO ("Not tested")]
489                 public void Load (TextReader textReader)
490                 {
491                         Load (textReader, ProjectLoadSettings.None);
492                 }
493
494                 public void Load (TextReader textReader, ProjectLoadSettings projectLoadSettings)
495                 {
496                         project_load_settings = projectLoadSettings;
497                         fullFileName = String.Empty;
498                         DoLoad (textReader);
499                 }
500
501                 public void LoadXml (string projectXml)
502                 {
503                         LoadXml (projectXml, ProjectLoadSettings.None);
504                 }
505
506                 public void LoadXml (string projectXml, ProjectLoadSettings projectLoadSettings)
507                 {
508                         project_load_settings = projectLoadSettings;
509                         fullFileName = String.Empty;
510                         DoLoad (new StringReader (projectXml));
511                         MarkProjectAsDirty ();
512                 }
513
514
515                 public void MarkProjectAsDirty ()
516                 {
517                         isDirty = true;
518                         timeOfLastDirty = DateTime.Now;
519                 }
520
521                 [MonoTODO ("Not tested")]
522                 public void RemoveAllItemGroups ()
523                 {
524                         int length = ItemGroups.Count;
525                         BuildItemGroup [] groups = new BuildItemGroup [length];
526                         ItemGroups.CopyTo (groups, 0);
527
528                         for (int i = 0; i < length; i++)
529                                 RemoveItemGroup (groups [i]);
530
531                         MarkProjectAsDirty ();
532                         NeedToReevaluate ();
533                 }
534
535                 [MonoTODO ("Not tested")]
536                 public void RemoveAllPropertyGroups ()
537                 {
538                         int length = PropertyGroups.Count;
539                         BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
540                         PropertyGroups.CopyTo (groups, 0);
541
542                         for (int i = 0; i < length; i++)
543                                 RemovePropertyGroup (groups [i]);
544
545                         MarkProjectAsDirty ();
546                         NeedToReevaluate ();
547                 }
548
549                 [MonoTODO]
550                 public void RemoveItem (BuildItem itemToRemove)
551                 {
552                         if (itemToRemove == null)
553                                 throw new ArgumentNullException ("itemToRemove");
554
555                         if (!itemToRemove.FromXml && !itemToRemove.HasParentItem)
556                                 throw new InvalidOperationException ("The object passed in is not part of the project.");
557
558                         BuildItemGroup big = itemToRemove.ParentItemGroup;
559
560                         if (big.Count == 1) {
561                                 // ParentItemGroup for items from xml and that have parent is the same
562                                 groupingCollection.Remove (big);
563                         } else {
564                                 if (big.ParentProject != this)
565                                         throw new InvalidOperationException ("The object passed in is not part of the project.");
566
567                                 if (itemToRemove.FromXml)
568                                         big.RemoveItem (itemToRemove);
569                                 else
570                                         big.RemoveItem (itemToRemove.ParentItem);
571                         }
572
573                         MarkProjectAsDirty ();
574                         NeedToReevaluate ();
575                 }
576
577                 [MonoTODO ("Not tested")]
578                 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
579                 {
580                         if (itemGroupToRemove == null)
581                                 throw new ArgumentNullException ("itemGroupToRemove");
582
583                         groupingCollection.Remove (itemGroupToRemove);
584                         MarkProjectAsDirty ();
585                 }
586                 
587                 [MonoTODO]
588                 // NOTE: does not modify imported projects
589                 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
590                 {
591                         throw new NotImplementedException ();
592                 }
593
594                 [MonoTODO]
595                 public void RemoveItemsByName (string itemName)
596                 {
597                         if (itemName == null)
598                                 throw new ArgumentNullException ("itemName");
599
600                         throw new NotImplementedException ();
601                 }
602
603                 [MonoTODO ("Not tested")]
604                 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
605                 {
606                         if (propertyGroupToRemove == null)
607                                 throw new ArgumentNullException ("propertyGroupToRemove");
608
609                         groupingCollection.Remove (propertyGroupToRemove);
610                         MarkProjectAsDirty ();
611                 }
612                 
613                 [MonoTODO]
614                 // NOTE: does not modify imported projects
615                 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
616                 {
617                         throw new NotImplementedException ();
618                 }
619
620                 [MonoTODO]
621                 public void ResetBuildStatus ()
622                 {
623                         // hack to allow built targets to be removed
624                         building = true;
625                         Reevaluate ();
626                         building = false;
627                 }
628
629                 public void Save (string projectFileName)
630                 {
631                         Save (projectFileName, Encoding.Default);
632                         isDirty = false;
633                 }
634
635                 [MonoTODO ("Ignores encoding")]
636                 public void Save (string projectFileName, Encoding encoding)
637                 {
638                         xmlDocument.Save (projectFileName);
639                         isDirty = false;
640                 }
641
642                 public void Save (TextWriter outTextWriter)
643                 {
644                         xmlDocument.Save (outTextWriter);
645                         isDirty = false;
646                 }
647
648                 public void SetImportedProperty (string propertyName,
649                                                  string propertyValue,
650                                                  string condition,
651                                                  Project importProject)
652                 {
653                         SetImportedProperty (propertyName, propertyValue, condition, importProject,
654                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
655                 }
656
657                 public void SetImportedProperty (string propertyName,
658                                                  string propertyValue,
659                                                  string condition,
660                                                  Project importedProject,
661                                                  PropertyPosition position)
662                 {
663                         SetImportedProperty (propertyName, propertyValue, condition, importedProject,
664                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
665                 }
666
667                 [MonoTODO]
668                 public void SetImportedProperty (string propertyName,
669                                                  string propertyValue,
670                                                  string condition,
671                                                  Project importedProject,
672                                                  PropertyPosition position,
673                                                  bool treatPropertyValueAsLiteral)
674                 {
675                         throw new NotImplementedException ();
676                 }
677
678                 public void SetProjectExtensions (string id, string xmlText)
679                 {
680                         if (id == null)
681                                 throw new ArgumentNullException ("id");
682                         if (xmlText == null)
683                                 throw new ArgumentNullException ("xmlText");
684
685                         XmlNode projectExtensions, node;
686
687                         projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
688                         
689                         if (projectExtensions == null) {
690                                 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
691                                 xmlDocument.DocumentElement.AppendChild (projectExtensions);
692
693                                 node = xmlDocument.CreateElement (id, XmlNamespace);
694                                 node.InnerXml = xmlText;
695                                 projectExtensions.AppendChild (node);
696                         } else {
697                                 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
698
699                                 if (node == null) {
700                                         node = xmlDocument.CreateElement (id, XmlNamespace);
701                                         projectExtensions.AppendChild (node);
702                                 }
703                                 
704                                 node.InnerXml = xmlText;
705                                 
706                         }
707
708                         MarkProjectAsDirty ();
709                 }
710                 
711                 public void SetProperty (string propertyName,
712                                          string propertyValue)
713                 {
714                         SetProperty (propertyName, propertyValue, "true",
715                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
716                 }
717
718                 public void SetProperty (string propertyName,
719                                          string propertyValue,
720                                          string condition)
721                 {
722                         SetProperty (propertyName, propertyValue, condition,
723                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
724                 }
725
726                 public void SetProperty (string propertyName,
727                                          string propertyValue,
728                                          string condition,
729                                          PropertyPosition position)
730                 {
731                         SetProperty (propertyName, propertyValue, condition,
732                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
733                 }
734
735                 [MonoTODO]
736                 public void SetProperty (string propertyName,
737                                          string propertyValue,
738                                          string condition,
739                                          PropertyPosition position,
740                                          bool treatPropertyValueAsLiteral)
741                 {
742                         throw new NotImplementedException ();
743                 }
744
745                 internal void Unload ()
746                 {
747                         unloaded = true;
748                 }
749
750                 internal void CheckUnloaded ()
751                 {
752                         if (unloaded)
753                                 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
754                 }
755
756                 internal void NeedToReevaluate ()
757                 {
758                         needToReevaluate = true;
759                 }
760                                 
761                 // Does the actual loading.
762                 void DoLoad (TextReader textReader)
763                 {
764                         try {
765                                 ParentEngine.RemoveLoadedProject (this);
766         
767                                 xmlDocument.Load (textReader);
768
769                                 if (xmlDocument.DocumentElement.Name == "VisualStudioProject")
770                                         throw new InvalidProjectFileException (String.Format (
771                                                         "Project file '{0}' is a VS2003 project, which is not " +
772                                                         "supported by xbuild. You need to convert it to msbuild " +
773                                                         "format to build with xbuild.", fullFileName));
774
775                                 if (SchemaFile != null) {
776                                         xmlDocument.Schemas.Add (XmlSchema.Read (
777                                                                 new StreamReader (SchemaFile), ValidationCallBack));
778                                         xmlDocument.Validate (ValidationCallBack);
779                                 }
780
781                                 if (xmlDocument.DocumentElement.Name != "Project") {
782                                         throw new InvalidProjectFileException (String.Format (
783                                                 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
784                                 }
785         
786                                 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
787                                         throw new InvalidProjectFileException (
788                                                 @"The default XML namespace of the project must be the MSBuild XML namespace." + 
789                                                 " If the project is authored in the MSBuild 2003 format, please add " +
790                                                 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
791                                                 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  ");
792                                 }
793                                 ProcessXml ();
794                                 ParentEngine.AddLoadedProject (this);
795                         } catch (Exception e) {
796                                 throw new InvalidProjectFileException (String.Format ("{0}: {1}",
797                                                         fullFileName, e.Message), e);
798                         } finally {
799                                 if (textReader != null)
800                                         textReader.Close ();
801                         }
802                 }
803
804                 void Reevaluate ()
805                 {
806                         ProcessXml ();
807                 }
808
809                 void ProcessXml ()
810                 {
811                         groupingCollection = new GroupingCollection (this);
812                         imports = new ImportCollection (groupingCollection);
813                         usingTasks = new UsingTaskCollection (this);
814                         itemGroups = new BuildItemGroupCollection (groupingCollection);
815                         propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
816                         targets = new TargetCollection (this);
817                         last_item_group_containing = new Dictionary <string, BuildItemGroup> ();
818                         
819                         string effective_tools_version = GetToolsVersionToUse (false);
820                         taskDatabase = new TaskDatabase ();
821                         taskDatabase.CopyTasks (ParentEngine.GetDefaultTasks (effective_tools_version));
822
823                         initialTargets = new List<string> ();
824                         defaultTargets = new string [0];
825                         PrepareForEvaluate (effective_tools_version);
826                         ProcessElements (xmlDocument.DocumentElement, null);
827                         
828                         isDirty = false;
829                         Evaluate ();
830                 }
831
832                 void ProcessProjectAttributes (XmlAttributeCollection attributes)
833                 {
834                         foreach (XmlAttribute attr in attributes) {
835                                 switch (attr.Name) {
836                                 case "InitialTargets":
837                                         initialTargets.AddRange (attr.Value.Split (
838                                                                         new char [] {';', ' '},
839                                                                         StringSplitOptions.RemoveEmptyEntries));
840                                         break;
841                                 case "DefaultTargets":
842                                         // first non-empty DefaultTargets found is used
843                                         if (defaultTargets == null || defaultTargets.Length == 0)
844                                                 defaultTargets = attr.Value.Split (new char [] {';', ' '},
845                                                         StringSplitOptions.RemoveEmptyEntries);
846                                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets",
847                                                                 DefaultTargets, PropertyType.Reserved));
848                                         break;
849                                 }
850                         }
851                 }
852
853                 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
854                 {
855                         ProcessProjectAttributes (rootElement.Attributes);
856                         foreach (XmlNode xn in rootElement.ChildNodes) {
857                                 if (xn is XmlElement) {
858                                         XmlElement xe = (XmlElement) xn;
859                                         switch (xe.Name) {
860                                         case "ProjectExtensions":
861                                                 AddProjectExtensions (xe);
862                                                 break;
863                                         case "Warning":
864                                         case "Message":
865                                         case "Error":
866                                                 AddMessage (xe);
867                                                 break;
868                                         case "Target":
869                                                 AddTarget (xe, ip);
870                                                 break;
871                                         case "UsingTask":
872                                                 AddUsingTask (xe, ip);
873                                                 break;
874                                         case "Import":
875                                                 AddImport (xe, ip);
876                                                 break;
877                                         case "ItemGroup":
878                                                 AddItemGroup (xe, ip);
879                                                 break;
880                                         case "PropertyGroup":
881                                                 AddPropertyGroup (xe, ip);
882                                                 break;
883                                         case  "Choose":
884                                                 AddChoose (xe);
885                                                 break;
886                                         default:
887                                                 throw new InvalidProjectFileException (String.Format ("Invalid element '{0}' in project file.", xe.Name));
888                                         }
889                                 }
890                         }
891                 }
892                 
893                 void PrepareForEvaluate (string effective_tools_version)
894                 {
895                         evaluatedItems = new BuildItemGroup (null, this, null, true);
896                         evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
897                         evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
898                         evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
899                         if (building && current_settings == BuildSettings.None)
900                                 RemoveBuiltTargets ();
901
902                         InitializeProperties (effective_tools_version);
903                 }
904
905                 void Evaluate ()
906                 {
907                         groupingCollection.Evaluate ();
908
909                         //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
910                         foreach (UsingTask usingTask in UsingTasks)
911                                 usingTask.Evaluate ();
912                 }
913
914                 // Removes entries of all earlier built targets for this project
915                 void RemoveBuiltTargets ()
916                 {
917                         ParentEngine.ClearBuiltTargetsForProject (this);
918                 }
919
920                 void InitializeProperties (string effective_tools_version)
921                 {
922                         BuildProperty bp;
923
924                         evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
925
926                         foreach (BuildProperty gp in GlobalProperties) {
927                                 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
928                                 evaluatedProperties.AddProperty (bp);
929                         }
930                         
931                         foreach (BuildProperty gp in GlobalProperties)
932                                 ParentEngine.GlobalProperties.AddProperty (gp);
933
934                         // add properties that we dont have from parent engine's
935                         // global properties
936                         foreach (BuildProperty gp in ParentEngine.GlobalProperties) {
937                                 if (evaluatedProperties [gp.Name] == null) {
938                                         bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
939                                         evaluatedProperties.AddProperty (bp);
940                                 }
941                         }
942
943                         foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
944                                 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
945                                 evaluatedProperties.AddProperty (bp);
946                         }
947
948                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectFile", Path.GetFileName (fullFileName),
949                                                 PropertyType.Reserved));
950                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectFullPath", fullFileName, PropertyType.Reserved));
951                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectName",
952                                                 Path.GetFileNameWithoutExtension (fullFileName),
953                                                 PropertyType.Reserved));
954                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectExtension",
955                                                 Path.GetExtension (fullFileName),
956                                                 PropertyType.Reserved));
957
958                         string toolsPath = parentEngine.Toolsets [effective_tools_version].ToolsPath;
959                         if (toolsPath == null)
960                                 throw new Exception (String.Format ("Invalid tools version '{0}', no tools path set for this.", effective_tools_version));
961                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", toolsPath, PropertyType.Reserved));
962                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath", toolsPath, PropertyType.Reserved));
963                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsVersion", effective_tools_version, PropertyType.Reserved));
964                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath", ExtensionsPath, PropertyType.Reserved));
965                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath32", ExtensionsPath, PropertyType.Reserved));
966                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath64", ExtensionsPath, PropertyType.Reserved));
967                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets", DefaultTargets, PropertyType.Reserved));
968                         evaluatedProperties.AddProperty (new BuildProperty ("OS", OS, PropertyType.Environment));
969
970                         // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
971                         string projectDir;
972                         if (FullFileName == String.Empty)
973                                 projectDir = Environment.CurrentDirectory;
974                         else
975                                 projectDir = Path.GetDirectoryName (FullFileName);
976
977                         evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
978                 }
979
980                 // precedence:
981                 // ToolsVersion property
982                 // ToolsVersion attribute on the project
983                 // parentEngine's DefaultToolsVersion
984                 string GetToolsVersionToUse (bool emitWarning)
985                 {
986                         if (!String.IsNullOrEmpty (ToolsVersion))
987                                 return ToolsVersion;
988
989                         if (!HasToolsVersionAttribute)
990                                 return parentEngine.DefaultToolsVersion;
991
992                         if (parentEngine.Toolsets [DefaultToolsVersion] == null) {
993                                 if (emitWarning)
994                                         LogWarning (FullFileName, "Project has unknown ToolsVersion '{0}'. Using the default tools version '{1}' instead.",
995                                                 DefaultToolsVersion, parentEngine.DefaultToolsVersion);
996                                 return parentEngine.DefaultToolsVersion;
997                         }
998
999                         return DefaultToolsVersion;
1000                 }
1001                 
1002                 void AddProjectExtensions (XmlElement xmlElement)
1003                 {
1004                 }
1005                 
1006                 void AddMessage (XmlElement xmlElement)
1007                 {
1008                 }
1009                 
1010                 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
1011                 {
1012                         Target target = new Target (xmlElement, this, importedProject);
1013                         targets.AddTarget (target);
1014                         
1015                         if (firstTargetName == null)
1016                                 firstTargetName = target.Name;
1017                 }
1018                 
1019                 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
1020                 {
1021                         UsingTask usingTask;
1022
1023                         usingTask = new UsingTask (xmlElement, this, importedProject);
1024                         UsingTasks.Add (usingTask);
1025                 }
1026                 
1027                 void AddImport (XmlElement xmlElement, ImportedProject importingProject)
1028                 {
1029                         // eval all the properties etc till the import
1030                         groupingCollection.Evaluate (EvaluationType.Property);
1031
1032                         Import import = new Import (xmlElement, this, importingProject);
1033                         if (!ConditionParser.ParseAndEvaluate (import.Condition, this))
1034                                 return;
1035
1036                         if (Imports.Contains (import)) {
1037                                 LogWarning (importingProject != null ? importingProject.FullFileName : fullFileName,
1038                                                 "A circular reference was found involving the import of {0}. Only" +
1039                                                 " the first import of this file will be used, ignoring others.",
1040                                                 import.ProjectPath);
1041
1042                                 return;
1043                         }
1044
1045                         if (String.Compare (fullFileName, import.EvaluatedProjectPath) == 0) {
1046                                 LogWarning (importingProject != null ? importingProject.FullFileName : fullFileName,
1047                                                 "The main project file was imported here, which creates a circular " +
1048                                                 "reference. Ignoring this import.");
1049
1050                                 return;
1051                         }
1052
1053                         Imports.Add (import);
1054                         import.Evaluate (project_load_settings == ProjectLoadSettings.IgnoreMissingImports);
1055                 }
1056                 
1057                 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
1058                 {
1059                         BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
1060                         ItemGroups.Add (big);
1061                 }
1062                 
1063                 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
1064                 {
1065                         BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
1066                         PropertyGroups.Add (bpg);
1067                 }
1068                 
1069                 void AddChoose (XmlElement xmlElement)
1070                 {
1071                         BuildChoose bc = new BuildChoose (xmlElement, this);
1072                         groupingCollection.Add (bc);
1073                 }
1074                 
1075                 static void ValidationCallBack (object sender, ValidationEventArgs e)
1076                 {
1077                         Console.WriteLine ("Validation Error: {0}", e.Message);
1078                 }
1079                 
1080                 public bool BuildEnabled {
1081                         get {
1082                                 return buildEnabled;
1083                         }
1084                         set {
1085                                 buildEnabled = value;
1086                         }
1087                 }
1088
1089                 [MonoTODO]
1090                 public Encoding Encoding {
1091                         get { return encoding; }
1092                 }
1093
1094                 public string DefaultTargets {
1095                         get {
1096                                 return String.Join ("; ", defaultTargets);
1097                         }
1098                         set {
1099                                 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
1100                                 if (value != null)
1101                                         defaultTargets = value.Split (new char [] {';', ' '},
1102                                                         StringSplitOptions.RemoveEmptyEntries);
1103                         }
1104                 }
1105
1106                 public BuildItemGroup EvaluatedItems {
1107                         get {
1108                                 if (needToReevaluate) {
1109                                         needToReevaluate = false;
1110                                         Reevaluate ();
1111                                 }
1112                                 return evaluatedItems;
1113                         }
1114                 }
1115
1116                 public BuildItemGroup EvaluatedItemsIgnoringCondition {
1117                         get {
1118                                 if (needToReevaluate) {
1119                                         needToReevaluate = false;
1120                                         Reevaluate ();
1121                                 }
1122                                 return evaluatedItemsIgnoringCondition;
1123                         }
1124                 }
1125                 
1126                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
1127                         get {
1128                                 // FIXME: do we need to do this here?
1129                                 if (needToReevaluate) {
1130                                         needToReevaluate = false;
1131                                         Reevaluate ();
1132                                 }
1133                                 return evaluatedItemsByName;
1134                         }
1135                 }
1136
1137                 internal IEnumerable EvaluatedItemsByNameAsDictionaryEntries {
1138                         get {
1139                                 if (EvaluatedItemsByName.Count == 0)
1140                                         yield break;
1141
1142                                 foreach (KeyValuePair<string, BuildItemGroup> pair in EvaluatedItemsByName) {
1143                                         foreach (BuildItem bi in pair.Value)
1144                                                 yield return new DictionaryEntry (pair.Key, bi.ConvertToITaskItem (null, ExpressionOptions.ExpandItemRefs));
1145                                 }
1146                         }
1147                 }
1148
1149                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
1150                         get {
1151                                 // FIXME: do we need to do this here?
1152                                 if (needToReevaluate) {
1153                                         needToReevaluate = false;
1154                                         Reevaluate ();
1155                                 }
1156                                 return evaluatedItemsByNameIgnoringCondition;
1157                         }
1158                 }
1159
1160                 // For batching implementation
1161                 Dictionary<string, BuildItemGroup> perBatchItemsByName;
1162                 Dictionary<string, BuildItemGroup> commonItemsByName;
1163
1164                 struct Batch {
1165                         public Dictionary<string, BuildItemGroup> perBatchItemsByName;
1166                         public Dictionary<string, BuildItemGroup> commonItemsByName;
1167
1168                         public Batch (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1169                         {
1170                                 this.perBatchItemsByName = perBatchItemsByName;
1171                                 this.commonItemsByName = commonItemsByName;
1172                         }
1173                 }
1174
1175                 Stack<Batch> Batches {
1176                         get { return batches; }
1177                 }
1178
1179                 internal void PushBatch (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1180                 {
1181                         batches.Push (new Batch (perBatchItemsByName, commonItemsByName));
1182                         SetBatchedItems (perBatchItemsByName, commonItemsByName);
1183                 }
1184
1185                 internal void PopBatch ()
1186                 {
1187                         batches.Pop ();
1188                         if (batches.Count > 0) {
1189                                 Batch b = batches.Peek ();
1190                                 SetBatchedItems (b.perBatchItemsByName, b.commonItemsByName);
1191                         } else {
1192                                 SetBatchedItems (null, null);
1193                         }
1194                 }
1195
1196                 void SetBatchedItems (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1197                 {
1198                         this.perBatchItemsByName = perBatchItemsByName;
1199                         this.commonItemsByName = commonItemsByName;
1200                 }
1201
1202                 // Honors batching
1203                 internal bool TryGetEvaluatedItemByNameBatched (string itemName, out BuildItemGroup group)
1204                 {
1205                         if (perBatchItemsByName != null && perBatchItemsByName.TryGetValue (itemName, out group))
1206                                 return true;
1207
1208                         if (commonItemsByName != null && commonItemsByName.TryGetValue (itemName, out group))
1209                                 return true;
1210
1211                         group = null;
1212                         return EvaluatedItemsByName.TryGetValue (itemName, out group);
1213                 }
1214
1215                 internal string GetMetadataBatched (string itemName, string metadataName)
1216                 {
1217                         BuildItemGroup group = null;
1218                         if (itemName == null) {
1219                                 //unqualified, all items in a batch(bucket) have the
1220                                 //same metadata values
1221                                 group = GetFirst<BuildItemGroup> (perBatchItemsByName.Values);
1222                                 if (group == null)
1223                                         group = GetFirst<BuildItemGroup> (commonItemsByName.Values);
1224                         } else {
1225                                 //qualified
1226                                 TryGetEvaluatedItemByNameBatched (itemName, out group);
1227                         }
1228
1229                         if (group != null) {
1230                                 foreach (BuildItem item in group) {
1231                                         if (item.HasMetadata (metadataName))
1232                                                 return item.GetEvaluatedMetadata (metadataName);
1233                                 }
1234                         }
1235                         return String.Empty;
1236                 }
1237
1238                 internal IEnumerable<BuildItemGroup> GetAllItemGroups ()
1239                 {
1240                         if (perBatchItemsByName == null && commonItemsByName == null)
1241                                 foreach (BuildItemGroup group in EvaluatedItemsByName.Values)
1242                                         yield return group;
1243
1244                         if (perBatchItemsByName != null)
1245                                 foreach (BuildItemGroup group in perBatchItemsByName.Values)
1246                                         yield return group;
1247
1248                         if (commonItemsByName != null)
1249                                 foreach (BuildItemGroup group in commonItemsByName.Values)
1250                                         yield return group;
1251                 }
1252
1253                 T GetFirst<T> (ICollection<T> list)
1254                 {
1255                         if (list == null)
1256                                 return default (T);
1257
1258                         foreach (T t in list)
1259                                 return t;
1260
1261                         return default (T);
1262                 }
1263
1264                 internal void LogWarning (string filename, string message, params object[] messageArgs)
1265                 {
1266                         BuildWarningEventArgs bwea = new BuildWarningEventArgs (
1267                                 null, null, filename, 0, 0, 0, 0, String.Format (message, messageArgs),
1268                                 null, null);
1269                         ParentEngine.EventSource.FireWarningRaised (this, bwea);
1270                 }
1271
1272                 internal void LogError (string filename, string message,
1273                                      params object[] messageArgs)
1274                 {
1275                         BuildErrorEventArgs beea = new BuildErrorEventArgs (
1276                                 null, null, filename, 0, 0, 0, 0, String.Format (message, messageArgs),
1277                                 null, null);
1278                         ParentEngine.EventSource.FireErrorRaised (this, beea);
1279                 }
1280
1281                 static string ExtensionsPath {
1282                         get {
1283                                 if (extensions_path == null) {
1284                                         // NOTE: code from mcs/tools/gacutil/driver.cs
1285                                         PropertyInfo gac = typeof (System.Environment).GetProperty (
1286                                                         "GacPath", BindingFlags.Static | BindingFlags.NonPublic);
1287
1288                                         if (gac != null) {
1289                                                 MethodInfo get_gac = gac.GetGetMethod (true);
1290                                                 string gac_path = (string) get_gac.Invoke (null, null);
1291                                                 extensions_path = Path.GetFullPath (Path.Combine (
1292                                                                         gac_path, Path.Combine ("..", "xbuild")));
1293                                         }
1294                                 }
1295                                 return extensions_path;
1296                         }
1297                 }
1298
1299                 public BuildPropertyGroup EvaluatedProperties {
1300                         get {
1301                                 if (needToReevaluate) {
1302                                         needToReevaluate = false;
1303                                         Reevaluate ();
1304                                 }
1305                                 return evaluatedProperties;
1306                         }
1307                 }
1308
1309                 internal IEnumerable EvaluatedPropertiesAsDictionaryEntries {
1310                         get {
1311                                 foreach (BuildProperty bp in EvaluatedProperties)
1312                                         yield return new DictionaryEntry (bp.Name, bp.Value);
1313                         }
1314                 }
1315
1316                 public string FullFileName {
1317                         get { return fullFileName; }
1318                         set { fullFileName = value; }
1319                 }
1320
1321                 public BuildPropertyGroup GlobalProperties {
1322                         get { return globalProperties; }
1323                         set {
1324                                 if (value == null)
1325                                         throw new ArgumentNullException ("value");
1326                                 
1327                                 if (value.FromXml)
1328                                         throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
1329                                 
1330                                 globalProperties = value;
1331                         }
1332                 }
1333
1334                 public bool IsDirty {
1335                         get { return isDirty; }
1336                 }
1337
1338                 public bool IsValidated {
1339                         get { return isValidated; }
1340                         set { isValidated = value; }
1341                 }
1342
1343                 public BuildItemGroupCollection ItemGroups {
1344                         get { return itemGroups; }
1345                 }
1346                 
1347                 public ImportCollection Imports {
1348                         get { return imports; }
1349                 }
1350                 
1351                 public string InitialTargets {
1352                         get {
1353                                 return String.Join ("; ", initialTargets.ToArray ());
1354                         }
1355                         set {
1356                                 initialTargets.Clear ();
1357                                 xmlDocument.DocumentElement.SetAttribute ("InitialTargets", value);
1358                                 if (value != null)
1359                                         initialTargets.AddRange (value.Split (
1360                                                                 new char [] {';', ' '}, StringSplitOptions.RemoveEmptyEntries));
1361                         }
1362                 }
1363
1364                 public Engine ParentEngine {
1365                         get { return parentEngine; }
1366                 }
1367
1368                 public BuildPropertyGroupCollection PropertyGroups {
1369                         get { return propertyGroups; }
1370                 }
1371
1372                 public string SchemaFile {
1373                         get { return schemaFile; }
1374                         set { schemaFile = value; }
1375                 }
1376
1377                 public TargetCollection Targets {
1378                         get { return targets; }
1379                 }
1380
1381                 public DateTime TimeOfLastDirty {
1382                         get { return timeOfLastDirty; }
1383                 }
1384                 
1385                 public UsingTaskCollection UsingTasks {
1386                         get { return usingTasks; }
1387                 }
1388
1389                 [MonoTODO]
1390                 public string Xml {
1391                         get { return xmlDocument.InnerXml; }
1392                 }
1393
1394                 // corresponds to the xml attribute
1395                 public string DefaultToolsVersion {
1396                         get {
1397                                 if (xmlDocument != null)
1398                                         return xmlDocument.DocumentElement.GetAttribute ("ToolsVersion");
1399                                 return null;
1400                         }
1401                         set {
1402                                 if (xmlDocument != null)
1403                                         xmlDocument.DocumentElement.SetAttribute ("ToolsVersion", value);
1404                         }
1405                 }
1406
1407                 public bool HasToolsVersionAttribute {
1408                         get {
1409                                 return xmlDocument != null && xmlDocument.DocumentElement.HasAttribute ("ToolsVersion");
1410                         }
1411                 }
1412                 
1413                 public string ToolsVersion {
1414                         get; internal set;
1415                 }
1416
1417                 internal Dictionary <string, BuildItemGroup> LastItemGroupContaining {
1418                         get { return last_item_group_containing; }
1419                 }
1420                 
1421                 internal static XmlNamespaceManager XmlNamespaceManager {
1422                         get {
1423                                 if (manager == null) {
1424                                         manager = new XmlNamespaceManager (new NameTable ());
1425                                         manager.AddNamespace ("tns", ns);
1426                                 }
1427                                 
1428                                 return manager;
1429                         }
1430                 }
1431                 
1432                 internal TaskDatabase TaskDatabase {
1433                         get { return taskDatabase; }
1434                 }
1435                 
1436                 internal XmlDocument XmlDocument {
1437                         get { return xmlDocument; }
1438                 }
1439                 
1440                 internal static string XmlNamespace {
1441                         get { return ns; }
1442                 }
1443
1444                 static string OS {
1445                         get {
1446                                 PlatformID pid = Environment.OSVersion.Platform;
1447                                 switch ((int)pid) {
1448                                 case 128:
1449                                 case 4:
1450                                         return "Unix";
1451                                 case 6:
1452                                         return "OSX";
1453                                 default:
1454                                         return "Windows_NT";
1455                                 }
1456                         }
1457                 }
1458
1459         }
1460 }
1461
1462 #endif