2007-01-19 Marek Sieradzki <marek.sieradzki@gmail.com>
[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.Text;
36 using System.Xml;
37 using System.Xml.Schema;
38 using Microsoft.Build.Framework;
39 using Mono.XBuild.Framework;
40
41 namespace Microsoft.Build.BuildEngine {
42         public class Project {
43         
44                 bool                            buildEnabled;
45                 Dictionary <string, List <string>>      conditionedProperties;
46                 string[]                        defaultTargets;
47                 Encoding                        encoding;
48                 BuildItemGroup                  evaluatedItems;
49                 BuildItemGroup                  evaluatedItemsIgnoringCondition;
50                 Dictionary <string, BuildItemGroup>     evaluatedItemsByName;
51                 Dictionary <string, BuildItemGroup>     evaluatedItemsByNameIgnoringCondition;
52                 BuildPropertyGroup              evaluatedProperties;
53                 string                          firstTargetName;
54                 string                          fullFileName;
55                 BuildPropertyGroup              globalProperties;
56                 GroupingCollection              groupingCollection;
57                 bool                            isDirty;
58                 bool                            isValidated;
59                 BuildItemGroupCollection        itemGroups;
60                 ImportCollection                imports;
61                 string                          initialTargets;
62                 bool                            needToReevaluate;
63                 Engine                          parentEngine;
64                 BuildPropertyGroupCollection    propertyGroups;
65                 string                          schemaFile;
66                 TaskDatabase                    taskDatabase;
67                 TargetCollection                targets;
68                 DateTime                        timeOfLastDirty;
69                 UsingTaskCollection             usingTasks;
70                 XmlDocument                     xmlDocument;
71                 bool                            unloaded;
72
73                 static XmlNamespaceManager      manager;
74                 static string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
75
76                 public Project ()
77                         : this (Engine.GlobalEngine)
78                 {
79                 }
80
81                 public Project (Engine engine)
82                 {
83                         parentEngine  = engine;
84
85                         buildEnabled = ParentEngine.BuildEnabled;
86                         xmlDocument = new XmlDocument ();
87                         xmlDocument.PreserveWhitespace = false;
88                         xmlDocument.AppendChild (xmlDocument.CreateElement ("Project", XmlNamespace));
89                         xmlDocument.DocumentElement.SetAttribute ("xmlns", ns);
90                         
91                         fullFileName = String.Empty;
92
93                         globalProperties = new BuildPropertyGroup (null, this, null, false);
94                         foreach (BuildProperty bp in parentEngine.GlobalProperties)
95                                 GlobalProperties.AddProperty (bp.Clone (true));
96                         
97                         ProcessXml ();
98                 }
99
100                 [MonoTODO ("Not tested")]
101                 public void AddNewImport (string importLocation,
102                                           string importCondition)
103                 {
104                         if (importLocation == null)
105                                 throw new ArgumentNullException ("importLocation");
106
107                         XmlElement importElement = xmlDocument.CreateElement ("Import", XmlNamespace);
108                         xmlDocument.DocumentElement.AppendChild (importElement);
109                         importElement.SetAttribute ("Project", importLocation);
110                         if (!String.IsNullOrEmpty (importCondition))
111                                 importElement.SetAttribute ("Condition", importCondition);
112
113                         Import import = new Import (importElement, this, null);
114                         imports.Add (import);
115                         MarkProjectAsDirty ();
116                         NeedToReevaluate ();
117                 }
118
119                 public BuildItem AddNewItem (string itemName,
120                                              string itemInclude)
121                 {
122                         return AddNewItem (itemName, itemInclude, false);
123                 }
124                 
125                 [MonoTODO ("Adds item not in the same place as MS")]
126                 public BuildItem AddNewItem (string itemName,
127                                              string itemInclude,
128                                              bool treatItemIncludeAsLiteral)
129                 {
130                         BuildItemGroup big;
131
132                         if (itemGroups.Count == 0)
133                                 big = AddNewItemGroup ();
134                         else {
135                                 BuildItemGroup [] groups = new BuildItemGroup [itemGroups.Count];
136                                 itemGroups.CopyTo (groups, 0);
137                                 big = groups [0];
138                         }
139
140                         BuildItem item = big.AddNewItem (itemName, itemInclude, treatItemIncludeAsLiteral);
141                                 
142                         MarkProjectAsDirty ();
143                         NeedToReevaluate ();
144
145                         return item;
146                 }
147
148                 [MonoTODO ("Not tested")]
149                 public BuildItemGroup AddNewItemGroup ()
150                 {
151                         XmlElement element = xmlDocument.CreateElement ("ItemGroup", XmlNamespace);
152                         xmlDocument.DocumentElement.AppendChild (element);
153
154                         BuildItemGroup big = new BuildItemGroup (element, this, null, false);
155                         itemGroups.Add (big);
156                         MarkProjectAsDirty ();
157                         NeedToReevaluate ();
158
159                         return big;
160                 }
161
162                 [MonoTODO ("Ignores insertAtEndOfProject")]
163                 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
164                 {
165                         XmlElement element = xmlDocument.CreateElement ("PropertyGroup", XmlNamespace);
166                         xmlDocument.DocumentElement.AppendChild (element);
167
168                         BuildPropertyGroup bpg = new BuildPropertyGroup (element, this, null, false);
169                         propertyGroups.Add (bpg);
170                         MarkProjectAsDirty ();
171                         NeedToReevaluate ();
172
173                         return bpg;
174                 }
175                 
176                 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
177                 public void AddNewUsingTaskFromAssemblyFile (string taskName,
178                                                              string assemblyFile)
179                 {
180                         if (taskName == null)
181                                 throw new ArgumentNullException ("taskName");
182                         if (assemblyFile == null)
183                                 throw new ArgumentNullException ("assemblyFile");
184
185                         XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
186                         xmlDocument.DocumentElement.AppendChild (element);
187                         element.SetAttribute ("TaskName", taskName);
188                         element.SetAttribute ("AssemblyFile", assemblyFile);
189
190                         UsingTask ut = new UsingTask (element, this, null);
191                         usingTasks.Add (ut);
192                         MarkProjectAsDirty ();
193                 }
194                 
195                 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
196                 public void AddNewUsingTaskFromAssemblyName (string taskName,
197                                                              string assemblyName)
198                 {
199                         if (taskName == null)
200                                 throw new ArgumentNullException ("taskName");
201                         if (assemblyName == null)
202                                 throw new ArgumentNullException ("assemblyName");
203
204                         XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
205                         xmlDocument.DocumentElement.AppendChild (element);
206                         element.SetAttribute ("TaskName", taskName);
207                         element.SetAttribute ("AssemblyName", assemblyName);
208
209                         UsingTask ut = new UsingTask (element, this, null);
210                         usingTasks.Add (ut);
211                         MarkProjectAsDirty ();
212                 }
213                 
214                 [MonoTODO ("Does nothing")]
215                 public bool Build ()
216                 {
217                         return true;
218                 }
219                 
220                 [MonoTODO ("Not tested")]
221                 public bool Build (string targetName)
222                 {
223                         return Build (new string [1] { targetName });
224                 }
225                 
226                 [MonoTODO ("Not tested")]
227                 public bool Build (string[] targetNames)
228                 {
229                         return Build (targetNames, null);
230                 }
231                 
232                 [MonoTODO ("Not tested")]
233                 public bool Build (string[] targetNames,
234                                    IDictionary targetOutputs)
235                 {
236                         return Build (targetNames, targetOutputs, BuildSettings.None);
237                 }
238                 
239                 [MonoTODO ("Not tested")]
240                 public bool Build (string[] targetNames,
241                                    IDictionary targetOutputs,
242                                    BuildSettings buildFlags)
243                 
244                 {
245                         CheckUnloaded ();
246                         ParentEngine.StartBuild ();
247                         NeedToReevaluate ();
248                         
249                         if (targetNames.Length == 0) {
250                                 if (defaultTargets != null && defaultTargets.Length != 0)
251                                         targetNames = defaultTargets;
252                                 else if (firstTargetName != null)
253                                         targetNames = new string [1] { firstTargetName};
254                                 else
255                                         return false;
256                         }
257                         
258                         foreach (string target in targetNames) {
259                                 if (!targets.Exists (target))
260                                         // FIXME: test if it's logged
261                                         return false;
262                                 
263                                 if (!targets [target].Build ())
264                                         return false;
265                         }
266                                 
267                         return true;
268                 }
269
270                 [MonoTODO]
271                 public string[] GetConditionedPropertyValues (string propertyName)
272                 {
273                         if (conditionedProperties.ContainsKey (propertyName))
274                                 return conditionedProperties [propertyName].ToArray ();
275                         else
276                                 return new string [0];
277                 }
278
279                 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
280                 {                       
281                         if (needToReevaluate) {
282                                 needToReevaluate = false;
283                                 Reevaluate ();
284                         }
285
286                         if (evaluatedItemsByName.ContainsKey (itemName))
287                                 return evaluatedItemsByName [itemName];
288                         else
289                                 return new BuildItemGroup ();
290                 }
291
292                 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
293                 {
294                         if (needToReevaluate) {
295                                 needToReevaluate = false;
296                                 Reevaluate ();
297                         }
298
299                         if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
300                                 return evaluatedItemsByNameIgnoringCondition [itemName];
301                         else
302                                 return new BuildItemGroup ();
303                 }
304
305                 public string GetEvaluatedProperty (string propertyName)
306                 {
307                         if (needToReevaluate) {
308                                 needToReevaluate = false;
309                                 Reevaluate ();
310                         }
311
312                         if (propertyName == null)
313                                 throw new ArgumentNullException ("propertyName");
314
315                         BuildProperty bp = evaluatedProperties [propertyName];
316
317                         return bp == null ? null : (string) bp;
318                 }
319
320                 [MonoTODO ("We should remember that node and not use XPath to get it")]
321                 public string GetProjectExtensions (string id)
322                 {
323                         if (id == null || id == String.Empty)
324                                 return String.Empty;
325
326                         XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
327
328                         if (node == null)
329                                 return String.Empty;
330                         else
331                                 return node.InnerXml;
332                 }
333
334
335                 public void Load (string projectFileName)
336                 {
337                         this.fullFileName = Path.GetFullPath (projectFileName);
338                         DoLoad (new StreamReader (projectFileName));
339                 }
340                 
341                 [MonoTODO ("Not tested")]
342                 public void Load (TextReader textReader)
343                 {
344                         fullFileName = String.Empty;
345                         DoLoad (textReader);
346                 }
347
348                 public void LoadXml (string projectXml)
349                 {
350                         fullFileName = String.Empty;
351                         DoLoad (new StringReader (projectXml));
352                         MarkProjectAsDirty ();
353                 }
354
355
356                 public void MarkProjectAsDirty ()
357                 {
358                         isDirty = true;
359                         timeOfLastDirty = DateTime.Now;
360                 }
361
362                 [MonoTODO ("Not tested")]
363                 public void RemoveAllItemGroups ()
364                 {
365                         int length = ItemGroups.Count;
366                         BuildItemGroup [] groups = new BuildItemGroup [length];
367                         ItemGroups.CopyTo (groups, 0);
368
369                         for (int i = 0; i < length; i++)
370                                 RemoveItemGroup (groups [i]);
371
372                         MarkProjectAsDirty ();
373                         NeedToReevaluate ();
374                 }
375
376                 [MonoTODO ("Not tested")]
377                 public void RemoveAllPropertyGroups ()
378                 {
379                         int length = PropertyGroups.Count;
380                         BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
381                         PropertyGroups.CopyTo (groups, 0);
382
383                         for (int i = 0; i < length; i++)
384                                 RemovePropertyGroup (groups [i]);
385
386                         MarkProjectAsDirty ();
387                         NeedToReevaluate ();
388                 }
389
390                 [MonoTODO]
391                 public void RemoveItem (BuildItem itemToRemove)
392                 {
393                         if (itemToRemove == null)
394                                 throw new ArgumentNullException ("itemToRemove");
395
396                         if (!itemToRemove.FromXml && !itemToRemove.HasParent)
397                                 throw new InvalidOperationException ("The object passed in is not part of the project.");
398
399                         BuildItemGroup big = itemToRemove.ParentItemGroup;
400
401                         if (big.Count == 1) {
402                                 // ParentItemGroup for items from xml and that have parent is the same
403                                 groupingCollection.Remove (big);
404                         } else {
405                                 if (big.ParentProject != this)
406                                         throw new InvalidOperationException ("The object passed in is not part of the project.");
407
408                                 if (itemToRemove.FromXml)
409                                         big.RemoveItem (itemToRemove);
410                                 else
411                                         big.RemoveItem (itemToRemove.ParentItem);
412                         }
413
414                         MarkProjectAsDirty ();
415                         NeedToReevaluate ();
416                 }
417
418                 [MonoTODO ("Not tested")]
419                 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
420                 {
421                         if (itemGroupToRemove == null)
422                                 throw new ArgumentNullException ("itemGroupToRemove");
423
424                         groupingCollection.Remove (itemGroupToRemove);
425                         MarkProjectAsDirty ();
426                 }
427                 
428                 [MonoTODO]
429                 // NOTE: does not modify imported projects
430                 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
431                 {
432                         throw new NotImplementedException ();
433                 }
434
435                 [MonoTODO]
436                 public void RemoveItemsByName (string itemName)
437                 {
438                         if (itemName == null)
439                                 throw new ArgumentNullException ("itemName");
440
441                         throw new NotImplementedException ();
442                 }
443
444                 [MonoTODO ("Not tested")]
445                 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
446                 {
447                         if (propertyGroupToRemove == null)
448                                 throw new ArgumentNullException ("propertyGroupToRemove");
449
450                         groupingCollection.Remove (propertyGroupToRemove);
451                         MarkProjectAsDirty ();
452                 }
453                 
454                 [MonoTODO]
455                 // NOTE: does not modify imported projects
456                 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
457                 {
458                         throw new NotImplementedException ();
459                 }
460
461                 [MonoTODO]
462                 public void ResetBuildStatus ()
463                 {
464                         throw new NotImplementedException ();
465                 }
466
467                 public void Save (string projectFileName)
468                 {
469                         Save (projectFileName, Encoding.Default);
470                         isDirty = false;
471                 }
472
473                 public void Save (string projectFileName, Encoding encoding)
474                 {
475                         xmlDocument.Save (projectFileName);
476                         isDirty = false;
477                 }
478
479                 public void Save (TextWriter outTextWriter)
480                 {
481                         xmlDocument.Save (outTextWriter);
482                         isDirty = false;
483                 }
484
485                 public void SetImportedProperty (string propertyName,
486                                                  string propertyValue,
487                                                  string condition,
488                                                  Project importProject)
489                 {
490                         SetImportedProperty (propertyName, propertyValue, condition, importProject,
491                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
492                 }
493
494                 public void SetImportedProperty (string propertyName,
495                                                  string propertyValue,
496                                                  string condition,
497                                                  Project importedProject,
498                                                  PropertyPosition position)
499                 {
500                         SetImportedProperty (propertyName, propertyValue, condition, importedProject,
501                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
502                 }
503
504                 [MonoTODO]
505                 public void SetImportedProperty (string propertyName,
506                                                  string propertyValue,
507                                                  string condition,
508                                                  Project importedProject,
509                                                  PropertyPosition position,
510                                                  bool treatPropertyValueAsLiteral)
511                 {
512                         throw new NotImplementedException ();
513                 }
514
515                 public void SetProjectExtensions (string id, string xmlText)
516                 {
517                         if (id == null)
518                                 throw new ArgumentNullException ("id");
519                         if (xmlText == null)
520                                 throw new ArgumentNullException ("xmlText");
521
522                         XmlNode projectExtensions, node;
523
524                         projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
525                         
526                         if (projectExtensions == null) {
527                                 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
528                                 xmlDocument.DocumentElement.AppendChild (projectExtensions);
529
530                                 node = xmlDocument.CreateElement (id, XmlNamespace);
531                                 node.InnerXml = xmlText;
532                                 projectExtensions.AppendChild (node);
533                         } else {
534                                 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
535
536                                 if (node == null) {
537                                         node = xmlDocument.CreateElement (id, XmlNamespace);
538                                         projectExtensions.AppendChild (node);
539                                 }
540                                 
541                                 node.InnerXml = xmlText;
542                                 
543                         }
544
545                         MarkProjectAsDirty ();
546                 }
547                 
548                 public void SetProperty (string propertyName,
549                                          string propertyValue)
550                 {
551                         SetProperty (propertyName, propertyValue, "true",
552                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
553                 }
554
555                 public void SetProperty (string propertyName,
556                                          string propertyValue,
557                                          string condition)
558                 {
559                         SetProperty (propertyName, propertyValue, condition,
560                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
561                 }
562
563                 public void SetProperty (string propertyName,
564                                          string propertyValue,
565                                          string condition,
566                                          PropertyPosition position)
567                 {
568                         SetProperty (propertyName, propertyValue, condition,
569                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
570                 }
571
572                 [MonoTODO]
573                 public void SetProperty (string propertyName,
574                                          string propertyValue,
575                                          string condition,
576                                          PropertyPosition position,
577                                          bool treatPropertyValueAsLiteral)
578                 {
579                         throw new NotImplementedException ();
580                 }
581
582                 internal void Unload ()
583                 {
584                         unloaded = true;
585                 }
586
587                 internal void CheckUnloaded ()
588                 {
589                         if (unloaded)
590                                 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
591                 }
592
593                 internal void NeedToReevaluate ()
594                 {
595                         needToReevaluate = true;
596                 }
597                                 
598                 // Does the actual loading.
599                 void DoLoad (TextReader textReader)
600                 {
601                         try {
602                                 ParentEngine.RemoveLoadedProject (this);
603         
604                                 XmlReaderSettings settings = new XmlReaderSettings ();
605         
606                                 if (SchemaFile != null) {
607                                         settings.Schemas.Add (null, SchemaFile);
608                                         settings.ValidationType = ValidationType.Schema;
609                                         settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
610                                 }
611         
612                                 XmlReader xmlReader = XmlReader.Create (textReader, settings);
613                                 xmlDocument.Load (xmlReader);
614
615                                 if (xmlDocument.DocumentElement.Name != "Project") {
616                                         throw new InvalidProjectFileException (String.Format (
617                                                 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
618                                 }
619         
620                                 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
621                                         throw new InvalidProjectFileException (
622                                                 @"The default XML namespace of the project must be the MSBuild XML namespace." + 
623                                                 " If the project is authored in the MSBuild 2003 format, please add " +
624                                                 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
625                                                 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  ");
626                                 }
627                                 ProcessXml ();
628                                 ParentEngine.AddLoadedProject (this);
629                         } catch (Exception e) {
630                                 throw new InvalidProjectFileException (e.Message, e);
631                         } finally {
632                                 textReader.Close ();
633                         }
634                 }
635
636                 void Reevaluate ()
637                 {
638                         ProcessXml ();
639                 }
640
641                 void ProcessXml ()
642                 {
643                         groupingCollection = new GroupingCollection (this);
644                         imports = new ImportCollection (groupingCollection);
645                         usingTasks = new UsingTaskCollection (this);
646                         itemGroups = new BuildItemGroupCollection (groupingCollection);
647                         propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
648                         targets = new TargetCollection (this);
649                         
650                         taskDatabase = new TaskDatabase ();
651                         if (ParentEngine.DefaultTasksRegistered)
652                                 taskDatabase.CopyTasks (ParentEngine.DefaultTasks);     
653
654                         if (xmlDocument.DocumentElement.GetAttributeNode ("DefaultTargets") != null)
655                                 defaultTargets = xmlDocument.DocumentElement.GetAttribute ("DefaultTargets").Split (';');
656                         else
657                                 defaultTargets = new string [0];
658                         
659                         ProcessElements (xmlDocument.DocumentElement, null);
660                         
661                         isDirty = false;
662                         Evaluate ();
663                 }
664                 
665                 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
666                 {
667                         foreach (XmlNode xn in rootElement.ChildNodes) {
668                                 if (xn is XmlElement) {
669                                         XmlElement xe = (XmlElement) xn;
670                                         switch (xe.Name) {
671                                         case "ProjectExtensions":
672                                                 AddProjectExtensions (xe);
673                                                 break;
674                                         case "Warning":
675                                         case "Message":
676                                         case "Error":
677                                                 AddMessage (xe);
678                                                 break;
679                                         case "Target":
680                                                 AddTarget (xe, ip);
681                                                 break;
682                                         case "UsingTask":
683                                                 AddUsingTask (xe, ip);
684                                                 break;
685                                         case "Import":
686                                                 AddImport (xe, ip);
687                                                 break;
688                                         case "ItemGroup":
689                                                 AddItemGroup (xe, ip);
690                                                 break;
691                                         case "PropertyGroup":
692                                                 AddPropertyGroup (xe, ip);
693                                                 break;
694                                         case  "Choose":
695                                                 AddChoose (xe);
696                                                 break;
697                                         default:
698                                                 throw new InvalidProjectFileException ("Invalid element in project file.");
699                                         }
700                                 }
701                         }
702                 }
703                 
704                 void Evaluate ()
705                 {
706                         evaluatedItems = new BuildItemGroup (null, this, null, true);
707                         evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
708                         evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
709                         evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
710                         evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
711
712                         InitializeProperties ();
713
714                         groupingCollection.Evaluate ();
715
716                         //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
717                         foreach (UsingTask usingTask in UsingTasks)
718                                 usingTask.Evaluate ();
719                 }
720
721                 void InitializeProperties ()
722                 {
723                         BuildProperty bp;
724
725                         foreach (BuildProperty gp in GlobalProperties) {
726                                 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
727                                 EvaluatedProperties.AddProperty (bp);
728                         }
729                         
730                         foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
731                                 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
732                                 EvaluatedProperties.AddProperty (bp);
733                         }
734
735                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved));
736
737                         // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
738                         string projectDir;
739                         if (FullFileName == String.Empty)
740                                 projectDir = Environment.CurrentDirectory;
741                         else
742                                 projectDir = Path.GetDirectoryName (FullFileName);
743
744                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
745                 }
746                 
747                 void AddProjectExtensions (XmlElement xmlElement)
748                 {
749                 }
750                 
751                 void AddMessage (XmlElement xmlElement)
752                 {
753                 }
754                 
755                 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
756                 {
757                         Target target = new Target (xmlElement, this, importedProject);
758                         targets.AddTarget (target);
759                         
760                         if (firstTargetName == null)
761                                 firstTargetName = target.Name;
762                 }
763                 
764                 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
765                 {
766                         UsingTask usingTask;
767
768                         usingTask = new UsingTask (xmlElement, this, importedProject);
769                         UsingTasks.Add (usingTask);
770                 }
771                 
772                 void AddImport (XmlElement xmlElement, ImportedProject importingProject)
773                 {
774                         Import import;
775                         
776                         import = new Import (xmlElement, this, importingProject);
777                         Imports.Add (import);
778                 }
779                 
780                 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
781                 {
782                         BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
783                         ItemGroups.Add (big);
784                 }
785                 
786                 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
787                 {
788                         BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
789                         PropertyGroups.Add (bpg);
790                 }
791                 
792                 void AddChoose (XmlElement xmlElement)
793                 {
794                         BuildChoose bc = new BuildChoose (xmlElement, this);
795                         groupingCollection.Add (bc);
796                 }
797                 
798                 static void ValidationCallBack (object sender, ValidationEventArgs e)
799                 {
800                         Console.WriteLine ("Validation Error: {0}", e.Message);
801                 }
802                 
803                 public bool BuildEnabled {
804                         get {
805                                 return buildEnabled;
806                         }
807                         set {
808                                 buildEnabled = value;
809                         }
810                 }
811
812                 public Encoding Encoding {
813                         get { return encoding; }
814                 }
815
816                 public string DefaultTargets {
817                         get {
818                                 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
819                         }
820                         set {
821                                 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
822                                 defaultTargets = value.Split (';');
823                         }
824                 }
825
826                 public BuildItemGroup EvaluatedItems {
827                         get {
828                                 if (needToReevaluate) {
829                                         needToReevaluate = false;
830                                         Reevaluate ();
831                                 }
832                                 return evaluatedItems;
833                         }
834                 }
835
836                 public BuildItemGroup EvaluatedItemsIgnoringCondition {
837                         get {
838                                 if (needToReevaluate) {
839                                         needToReevaluate = false;
840                                         Reevaluate ();
841                                 }
842                                 return evaluatedItemsIgnoringCondition;
843                         }
844                 }
845                 
846                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
847                         get {
848                                 // FIXME: do we need to do this here?
849                                 if (needToReevaluate) {
850                                         needToReevaluate = false;
851                                         Reevaluate ();
852                                 }
853                                 return evaluatedItemsByName;
854                         }
855                 }
856                 
857                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
858                         get {
859                                 // FIXME: do we need to do this here?
860                                 if (needToReevaluate) {
861                                         needToReevaluate = false;
862                                         Reevaluate ();
863                                 }
864                                 return evaluatedItemsByNameIgnoringCondition;
865                         }
866                 }
867
868                 public BuildPropertyGroup EvaluatedProperties {
869                         get {
870                                 if (needToReevaluate) {
871                                         needToReevaluate = false;
872                                         Reevaluate ();
873                                 }
874                                 return evaluatedProperties;
875                         }
876                 }
877
878                 public string FullFileName {
879                         get { return fullFileName; }
880                         set { fullFileName = value; }
881                 }
882
883                 public BuildPropertyGroup GlobalProperties {
884                         get { return globalProperties; }
885                         set {
886                                 if (value == null)
887                                         throw new ArgumentNullException ("value");
888                                 
889                                 if (value.FromXml)
890                                         throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
891                                 
892                                 globalProperties = value;
893                                 NeedToReevaluate ();
894                         }
895                 }
896
897                 public bool IsDirty {
898                         get { return isDirty; }
899                 }
900
901                 public bool IsValidated {
902                         get { return isValidated; }
903                         set { isValidated = value; }
904                 }
905
906                 public BuildItemGroupCollection ItemGroups {
907                         get { return itemGroups; }
908                 }
909                 
910                 public ImportCollection Imports {
911                         get { return imports; }
912                 }
913                 
914                 public string InitialTargets {
915                         get { return initialTargets; }
916                         set { initialTargets = value; }
917                 }
918
919                 public Engine ParentEngine {
920                         get { return parentEngine; }
921                 }
922
923                 public BuildPropertyGroupCollection PropertyGroups {
924                         get { return propertyGroups; }
925                 }
926
927                 public string SchemaFile {
928                         get { return schemaFile; }
929                         set { schemaFile = value; }
930                 }
931
932                 public TargetCollection Targets {
933                         get { return targets; }
934                 }
935
936                 public DateTime TimeOfLastDirty {
937                         get { return timeOfLastDirty; }
938                 }
939                 
940                 public UsingTaskCollection UsingTasks {
941                         get { return usingTasks; }
942                 }
943
944                 [MonoTODO]
945                 public string Xml {
946                         get { return xmlDocument.InnerXml; }
947                 }
948                 
949                 internal static XmlNamespaceManager XmlNamespaceManager {
950                         get {
951                                 if (manager == null) {
952                                         manager = new XmlNamespaceManager (new NameTable ());
953                                         manager.AddNamespace ("tns", ns);
954                                 }
955                                 
956                                 return manager;
957                         }
958                 }
959                 
960                 internal TaskDatabase TaskDatabase {
961                         get { return taskDatabase; }
962                 }
963                 
964                 internal XmlDocument XmlDocument {
965                         get { return xmlDocument; }
966                 }
967                 
968                 internal static string XmlNamespace {
969                         get { return ns; }
970                 }
971         }
972 }
973
974 #endif