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