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