ee01bac55aa12f62f59ebda9030188da6a362c62
[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.Specialized;
33 using System.IO;
34 using System.Text;
35 using System.Xml;
36 using System.Xml.Schema;
37 using Microsoft.Build.Framework;
38 using Mono.XBuild.Framework;
39
40 namespace Microsoft.Build.BuildEngine {
41         public class Project {
42                 static string separator = ";";
43         
44                 bool                            buildEnabled;
45                 IDictionary                     conditionedProperties;
46                 string[]                        defaultTargets;
47                 IList                           directlyImportedProjects;
48                 Encoding                        encoding;
49                 BuildPropertyGroup              environmentProperties;
50                 BuildItemGroup                  evaluatedItems;
51                 BuildItemGroup                  evaluatedItemsIgnoringCondition;
52                 IDictionary                     evaluatedItemsByName;
53                 IDictionary                     evaluatedItemsByNameIgnoringCondition;
54                 BuildPropertyGroup              evaluatedProperties;
55                 string                          firstTargetName;
56                 string                          fullFileName;
57                 BuildPropertyGroup              globalProperties;
58                 GroupingCollection              groups;
59                 bool                            isDirty;
60                 bool                            isValidated;
61                 bool                            isReset;
62                 BuildItemGroupCollection        itemGroups;
63                 IDictionary                     importedProjects;
64                 Engine                          parentEngine;
65                 BuildPropertyGroupCollection    propertyGroups;
66                 BuildPropertyGroup              reservedProperties;
67                 string                          schemaFile;
68                 TaskDatabase                    taskDatabase;
69                 TargetCollection                targets;
70                 DateTime                        timeOfLastDirty;
71                 IList                           usingTaskElements;
72                 XmlDocument                     xmlDocument;
73                 XmlElement                      xmlElement;
74
75                 public Project ()
76                         : this (null)
77                 {
78                 }
79
80                 public Project (Engine engine)
81                 {
82                         parentEngine  = engine;
83                         xmlDocument = new XmlDocument ();
84                         evaluatedItems = new BuildItemGroup (this);
85                         evaluatedItemsByName = CollectionsUtil.CreateCaseInsensitiveHashtable ();
86                         evaluatedItemsByNameIgnoringCondition = CollectionsUtil.CreateCaseInsensitiveHashtable ();
87                         evaluatedItemsIgnoringCondition = new BuildItemGroup (this);
88                         evaluatedProperties = new BuildPropertyGroup (false, null);
89                         groups = new GroupingCollection ();
90                         itemGroups = new BuildItemGroupCollection (groups);
91                         propertyGroups = new BuildPropertyGroupCollection (groups);
92                         targets = new TargetCollection (this);
93                         usingTaskElements = new ArrayList ();
94                         taskDatabase = new TaskDatabase ();
95                 }
96
97                 [MonoTODO]
98                 public void AddNewImport (string importLocation,
99                                           string importCondition)
100                 {
101                         throw new NotImplementedException ();
102                 }
103
104                 [MonoTODO]
105                 public BuildItem AddNewItem (string itemName,
106                                              string itemInclude)
107                 {
108                         return AddNewItem (itemName, itemInclude, false);
109                 }
110                 
111                 [MonoTODO]
112                 public BuildItem AddNewItem (string itemName,
113                                              string itemInclude,
114                                              bool treatItemIncludeAsLiteral)
115                 {
116                         throw new NotImplementedException ();
117                 }
118
119                 [MonoTODO]
120                 public BuildItemGroup AddNewItemGroup ()
121                 {
122                         throw new NotImplementedException ();
123                 }
124
125                 [MonoTODO]
126                 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
127                 {
128                         throw new NotImplementedException ();
129                 }
130                 
131                 [MonoTODO]
132                 public bool Build ()
133                 {
134                         return true;
135                 }
136                 
137                 [MonoTODO]
138                 public bool Build (string targetName)
139                 {
140                         if (targets.Exists (targetName) == false)
141                                 throw new Exception ("Target specified to build does not exist.");
142                         
143                         this.targets [targetName].Build ();
144                         return true;
145                 }
146                 
147                 [MonoTODO]
148                 public bool Build (string[] targetNames)
149                 {
150                         return Build (targetNames, new Hashtable ());
151                 }
152                 
153                 [MonoTODO]
154                 public bool Build (string[] targetNames,
155                                    IDictionary targetOutputs)
156                 {
157                         return Build (targetNames, new Hashtable (), BuildSettings.None);
158                 }
159                 
160                 [MonoTODO]
161                 public bool Build (string[] targetNames,
162                                    IDictionary targetOutputs,
163                                    BuildSettings buildFlags)
164                 
165                 {
166                         if (targetNames.Length == 0) {
167                                 if (defaultTargets.Length != 0) {
168                                         targetNames = defaultTargets;
169                                 }
170                                 else if (firstTargetName != null) {
171                                         targetNames = new string [1] { firstTargetName};
172                                 }
173                                 else
174                                         return false;
175                         }
176                         foreach (string target in targetNames) {
177                                 if (Build (target) == false) {
178                                         return false;
179                                 }
180                         }
181                         return true;
182                 }
183
184                 public string[] GetConditionedPropertyValues (string propertyName)
185                 {
186                         StringCollection sc = (StringCollection) conditionedProperties [propertyName];
187                         string[] propertyValues = new string [sc.Count];
188                         int i  = 0;
189                         foreach (string propertyValue in sc)
190                                 propertyValues [i++] = propertyValue;
191                         return propertyValues;
192                 }
193
194                 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
195                 {
196                         return (BuildItemGroup) evaluatedItemsByName [itemName];
197                 }
198
199                 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
200                 {
201                         return (BuildItemGroup) evaluatedItemsByNameIgnoringCondition [itemName];
202                 }
203
204                 public string GetEvaluatedProperty (string propertyName)
205                 {
206                         return evaluatedProperties [propertyName];
207                 }
208
209                 [MonoTODO]
210                 public string GetProjectExtensions (string id)
211                 {
212                         throw new NotImplementedException ();
213                 }
214
215                 public void Load (string projectFileName)
216                 {
217                         this.fullFileName = Path.GetFullPath (projectFileName);
218                         XmlSchemaCollection xmlSchemaCollection = null;
219                         XmlTextReader xmlTextReader = null;
220                         XmlValidatingReader xmlValidatingReader = null;
221                         
222                         if (this.schemaFile != null) {
223                                 xmlSchemaCollection = new XmlSchemaCollection ();
224                                 xmlSchemaCollection.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
225                                 xmlSchemaCollection.Add (null, this.schemaFile);
226                                 if (xmlSchemaCollection.Count > 0) {
227                                         xmlTextReader = new XmlTextReader (projectFileName);
228                                         xmlValidatingReader = new XmlValidatingReader (xmlTextReader);
229                                         xmlValidatingReader.ValidationType = ValidationType.Schema;
230                                         xmlValidatingReader.Schemas.Add (xmlSchemaCollection);
231                                         xmlValidatingReader.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
232                                 }
233                         } else {
234                                 xmlTextReader = new XmlTextReader (projectFileName);
235                         }
236                         if (xmlValidatingReader != null)
237                                 xmlDocument.Load (xmlValidatingReader);
238                         else if (xmlTextReader != null)
239                                 xmlDocument.Load (xmlTextReader);
240                         else
241                                 throw new Exception ();
242                         xmlElement = xmlDocument.DocumentElement;
243                         if (xmlElement.Name != "Project")
244                                 throw new InvalidProjectFileException ("Invalid root element.");
245                         if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
246                                 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
247                         else
248                                 defaultTargets = new string [0];
249                         
250                         ProcessElements (xmlElement, null);
251                         
252                         isDirty = false;
253                 }
254                 
255                 [MonoTODO]
256                 public void Load (TextWriter textWriter)
257                 {
258                         throw new NotImplementedException ();
259                 }
260
261                 public void LoadFromXml (XmlDocument projectXml)
262                 {
263                         fullFileName = "";
264                         xmlDocument = projectXml;
265                         xmlElement = xmlDocument.DocumentElement;
266                         if (xmlElement.Name != "Project")
267                                 throw new InvalidProjectFileException ("Invalid root element.");
268                         if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
269                                 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
270                         else
271                                 defaultTargets = new string [0];
272                         
273                         ProcessElements (xmlElement, null);
274                         
275                         isDirty = false;
276                 }
277
278                 public void MarkProjectAsDirty ()
279                 {
280                         isDirty = true;
281                 }
282
283                 [MonoTODO]
284                 public void RemoveAllItemGroups ()
285                 {
286                         throw new NotImplementedException ();
287                 }
288
289                 [MonoTODO]
290                 public void RemoveAllPropertyGroups ()
291                 {
292                         throw new NotImplementedException ();
293                 }
294
295                 [MonoTODO]
296                 public void RemoveAllPropertyGroupsByCondition (string condition)
297                 {
298                         throw new NotImplementedException ();
299                 }
300
301                 [MonoTODO]
302                 public void RemoveItem (BuildItem itemToRemove)
303                 {
304                         throw new NotImplementedException ();
305                 }
306
307                 [MonoTODO]
308                 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
309                 {
310                         throw new NotImplementedException ();
311                 }
312                 
313                 [MonoTODO]
314                 // NOTE: does not modify imported projects
315                 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
316                 {
317                         throw new NotImplementedException ();
318                 }
319
320                 [MonoTODO]
321                 public void RemoveItemsByName (string itemName)
322                 {
323                         throw new NotImplementedException ();
324                 }
325
326                 [MonoTODO]
327                 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
328                 {
329                         throw new NotImplementedException ();
330                 }
331                 
332                 [MonoTODO]
333                 // NOTE: does not modify imported projects
334                 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
335                 {
336                         throw new NotImplementedException ();
337                 }
338
339                 [MonoTODO]
340                 public void ResetBuildStatus ()
341                 {
342                         throw new NotImplementedException ();
343                 }
344
345                 public void Save (string projectFileName)
346                 {
347                         Save (projectFileName, Encoding.Default);
348                 }
349
350                 public void Save (string projectFileName, Encoding encoding)
351                 {
352                         xmlDocument.Save (projectFileName);
353                 }
354
355                 public void Save (TextWriter outTextWriter)
356                 {
357                         xmlDocument.Save (outTextWriter);
358                 }
359
360                 [MonoTODO]
361                 public void SetImportedProperty (string propertyName,
362                                                  string propertyValue,
363                                                  string condition,
364                                                  Project importProject)
365                 {
366                         SetImportedProperty (propertyName, propertyValue, condition, importProject,
367                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
368                 }
369
370                 [MonoTODO]
371                 public void SetImportedProperty (string propertyName,
372                                                  string propertyValue,
373                                                  string condition,
374                                                  Project importedProject,
375                                                  PropertyPosition position)
376                 {
377                         SetImportedProperty (propertyName, propertyValue, condition, importedProject,
378                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
379                 }
380
381                 [MonoTODO]
382                 public void SetImportedProperty (string propertyName,
383                                                  string propertyValue,
384                                                  string condition,
385                                                  Project importedProject,
386                                                  PropertyPosition position,
387                                                  bool treatPropertyValueAsLiteral)
388                 {
389                         throw new NotImplementedException ();
390                 }
391
392                 [MonoTODO]
393                 public void SetProjectExtensions (string id, string xmlText)
394                 {
395                         throw new NotImplementedException ();
396                 }
397
398                 [MonoTODO]
399                 public void SetProperty (string propertyName,
400                                          string propertyValue,
401                                          string condition)
402                 {
403                         SetProperty (propertyName, propertyValue, condition,
404                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
405                 }
406
407                 [MonoTODO]
408                 public void SetProperty (string propertyName,
409                                          string propertyValue,
410                                          string condition,
411                                          PropertyPosition position)
412                 {
413                         SetProperty (propertyName, propertyValue, condition,
414                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
415                 }
416
417                 [MonoTODO]
418                 public void SetProperty (string propertyName,
419                                          string propertyValue,
420                                          string condition,
421                                          PropertyPosition position,
422                                          bool treatPropertyValueAsLiteral)
423                 {
424                         throw new NotImplementedException ();
425                 }
426
427                 private void ProcessElements (XmlElement rootElement, ImportedProject ip)
428                 {
429                         foreach (XmlNode xn in rootElement.ChildNodes) {
430                                 if (xn is XmlElement) {
431                                         XmlElement xe = (XmlElement) xn;
432                                         switch (xe.Name) {
433                                         case "ProjectExtensions":
434                                                 AddProjectExtensions (xe);
435                                                 break;
436                                         case "Warning":
437                                         case "Message":
438                                         case "Error":
439                                                 AddMessage (xe);
440                                                 break;
441                                         case "Target":
442                                                 AddTarget (xe, ip);
443                                                 break;
444                                         case "UsingTask":
445                                                 AddUsingTask (xe, ip);
446                                                 break;
447                                         case "Import":
448                                                 AddImport (xe, ip);
449                                                 break;
450                                         case "ItemGroup":
451                                                 AddItemGroup (xe);
452                                                 break;
453                                         case "PropertyGroup":
454                                                 AddPropertyGroup (xe);
455                                                 break;
456                                         case  "Choose":
457                                                 AddChoose (xe);
458                                                 break;
459                                         default:
460                                                 throw new InvalidProjectFileException ("Invalid element in project file.");
461                                         }
462                                 }
463                         }
464                 }
465                 
466                 private void AddProjectExtensions (XmlElement xmlElement)
467                 {
468                         if (xmlElement == null)
469                                 throw new ArgumentNullException ("xmlElement");
470                 }
471                 
472                 private void AddMessage (XmlElement xmlElement)
473                 {
474                         if (xmlElement == null)
475                                 throw new ArgumentNullException ("xmlElement");
476                 }
477                 
478                 private void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
479                 {
480                         if (xmlElement == null)
481                                 throw new ArgumentNullException ("xmlElement");
482                         Target target = targets.AddNewTarget (xmlElement.GetAttribute ("Name"));
483                         target.BindToXml (xmlElement);
484                         if (importedProject == null) {
485                                 target.IsImported = false;
486                                 if (firstTargetName == null)
487                                         firstTargetName = target.Name;
488                         } else
489                                 target.IsImported = true;
490                 }
491                 
492                 private void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
493                 {
494                         if (xmlElement == null)
495                                 throw new ArgumentNullException ("xmlElement");
496                                 
497                         if (xmlElement.GetAttribute ("TaskName") == String.Empty)
498                                 throw new InvalidProjectFileException ("TaskName attribute must be specified.");
499
500                         usingTaskElements.Add (xmlElement);
501
502                         AssemblyLoadInfo loadInfo = null;
503                         string filename = null;
504                         string name = null;
505                         string taskName = xmlElement.GetAttribute ("TaskName");
506                         
507                         if (xmlElement.GetAttribute ("AssemblyName") != String.Empty) {
508                                 name  = xmlElement.GetAttribute ("AssemblyName");
509                                 loadInfo  = new AssemblyLoadInfo (name, taskName);
510                                 taskDatabase.RegisterTask (taskName, loadInfo);
511                         } else if (xmlElement.GetAttribute ("AssemblyFile") != String.Empty) {
512                                 filename = xmlElement.GetAttribute ("AssemblyFile");
513                                 if (Path.IsPathRooted (filename) == false) {
514                                         if (importedProject == null)
515                                                 filename = Path.Combine (Path.GetDirectoryName (fullFileName), filename);
516                                         else
517                                                 filename = Path.Combine (Path.GetDirectoryName (importedProject.FullFileName), filename);
518                                 }
519                                 loadInfo  = new AssemblyLoadInfo (LoadInfoType.AssemblyFilename, filename, null, null, null, null, taskName);
520                                 taskDatabase.RegisterTask (taskName, loadInfo);
521                         } else
522                                 throw new InvalidProjectFileException ("AssemblyName or AssemblyFile attribute must be specified.");
523                 }
524                 
525                 private void AddImport (XmlElement xmlElement, ImportedProject importingProject)
526                 {
527                         if (xmlElement == null)
528                                 throw new ArgumentNullException ("xmlElement");
529                         
530                         string importedFile;
531                         Expression importedFileExpr;
532                         ImportedProject ImportedProject;
533
534                         importedFileExpr = new Expression (this, xmlElement.GetAttribute ("Project"));
535                         importedFile = (string) importedFileExpr.ToNonArray (typeof (string));
536                         
537                         if (importedFile == String.Empty)
538                                 throw new InvalidProjectFileException ("Project attribute must be specified.");
539                         
540                         if (Path.IsPathRooted (importedFile) == false) {
541                                 if (importingProject == null)
542                                         importedFile = Path.Combine (Path.GetDirectoryName (fullFileName), importedFile);
543                                 else
544                                         importedFile = Path.Combine (Path.GetDirectoryName (importingProject.FullFileName), importedFile);
545                         }
546                         
547                         ImportedProject importedProject = new ImportedProject ();
548                         try {
549                                 importedProject.Load (importedFile);
550                                 ProcessElements (importedProject.XmlDocument.DocumentElement, importedProject);
551                         }
552                         catch (Exception ex) {
553                                 Console.WriteLine (ex);
554                         }
555                 }
556                 
557                 private void AddItemGroup (XmlElement xmlElement)
558                 {
559                         if (xmlElement == null)
560                                 throw new ArgumentNullException ("xmlElement");
561                         BuildItemGroup big = new BuildItemGroup (this);
562                         big.BindToXml (xmlElement);
563                         itemGroups.Add (big);
564                 }
565                 
566                 private void AddPropertyGroup (XmlElement xmlElement)
567                 {
568                         if (xmlElement == null)
569                                 throw new ArgumentNullException ("xmlElement");
570                         BuildPropertyGroup bpg = new BuildPropertyGroup (true, this);
571                         bpg.BindToXml (xmlElement);
572                         propertyGroups.Add (bpg);
573                 }
574                 
575                 private void AddChoose (XmlElement xmlElement)
576                 {
577                         if (xmlElement == null)
578                                 throw new ArgumentNullException ("xmlElement");
579                 }
580                 
581                 private static void ValidationCallBack (object sender, ValidationEventArgs e)
582                 {
583                         Console.WriteLine ("Validation Error: {0}", e.Message);
584                 }
585                 
586                 public bool BuildEnabled {
587                         get {
588                                 return buildEnabled;
589                         }
590                         set {
591                                 buildEnabled = value;
592                         }
593                 }
594
595                 public Encoding Encoding {
596                         get { return encoding; }
597                 }
598
599                 public string DefaultTargets {
600                         get { return xmlElement.GetAttribute ("DefaultTargets"); }
601                         set {
602                                 xmlElement.SetAttribute ("DefaultTargets",value);
603                                 defaultTargets = value.Split (';');
604                         }
605                 }
606
607                 public BuildItemGroup EvaluatedItems {
608                         get { return evaluatedItems; }
609                 }
610
611                 public BuildItemGroup EvaluatedItemsIgnoringCondition {
612                         get { return evaluatedItemsIgnoringCondition; }
613                 }
614                 
615                 internal IDictionary EvaluatedItemsByName {
616                         get { return evaluatedItemsByName; }
617                 }
618                 
619                 internal IDictionary EvaluatedItemsByNameIgnoringCondition {
620                         get { return evaluatedItemsByNameIgnoringCondition; }
621                 }
622
623                 public BuildPropertyGroup EvaluatedProperties {
624                         get { return evaluatedProperties; }
625                 }
626
627                 public string FullFileName {
628                         get { return fullFileName; }
629                         set { fullFileName = value; }
630                 }
631
632                 public BuildPropertyGroup GlobalProperties {
633                         get { return globalProperties; }
634                         set {
635                                 globalProperties = value;
636                                 foreach (BuildProperty bp in globalProperties)
637                                         evaluatedProperties.AddFromExistingProperty (bp);
638                         }
639                 }
640
641                 public bool IsDirty {
642                         get { return isDirty; }
643                 }
644
645                 public bool IsValidated {
646                         get { return isValidated; }
647                         set { isValidated = value; }
648                 }
649
650                 public BuildItemGroupCollection ItemGroups {
651                         get { return itemGroups; }
652                 }
653
654                 public Engine ParentEngine {
655                         get { return parentEngine; }
656                 }
657
658                 public BuildPropertyGroupCollection PropertyGroups {
659                         get { return propertyGroups; }
660                 }
661
662                 public string SchemaFile {
663                         get { return schemaFile; }
664                         set { schemaFile = value; }
665                 }
666
667                 public TargetCollection Targets {
668                         get { return targets; }
669                 }
670
671                 public DateTime TimeOfLastDirty {
672                         get { return timeOfLastDirty; }
673                 }
674
675                 [MonoTODO]
676                 public string Xml {
677                         get { return xmlDocument.InnerXml; }
678                 }
679                 
680                 internal TaskDatabase TaskDatabase {
681                         get { return taskDatabase; }
682                 }
683                 
684                 internal BuildPropertyGroup EnvironmentProperties {
685                         set {
686                                 environmentProperties = value;
687                                 foreach (BuildProperty bp in environmentProperties)
688                                         evaluatedProperties.AddFromExistingProperty (bp);
689                         }
690                 }
691                 
692                 internal BuildPropertyGroup ReservedProperties {
693                         set {
694                                 reservedProperties = value;
695                                 foreach (BuildProperty bp in reservedProperties)
696                                         evaluatedProperties.AddFromExistingProperty (bp);
697                         }
698                 }
699         }
700 }
701
702 #endif