Bug 15572. Lookup KnownTypeCollection element types in MSSimpleNamespace
[mono.git] / mcs / class / Microsoft.Build / Microsoft.Build.Construction / ProjectRootElement.cs
1 //
2 // ProjectRootElement.cs
3 //
4 // Author:
5 //   Leszek Ciesielski (skolima@gmail.com)
6 //
7 // (C) 2011 Leszek Ciesielski
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
29 using System.Collections.Generic;
30
31 using Microsoft.Build.Evaluation;
32 using Microsoft.Build.Internal;
33 using System.Text;
34 using System;
35 using System.Xml;
36 using System.IO;
37 using System.Linq;
38 using System.Globalization;
39 using Microsoft.Build.Exceptions;
40
41 namespace Microsoft.Build.Construction
42 {
43         [System.Diagnostics.DebuggerDisplayAttribute("{FullPath} #Children={Count} DefaultTargets={DefaultTargets} "
44                                                      + "ToolsVersion={ToolsVersion} InitialTargets={InitialTargets}")]
45         public class ProjectRootElement : ProjectElementContainer
46         {
47                 public override string Condition { get { return null; } set { throw new InvalidOperationException (
48                         "Can not set Condition."); } }
49                 string defaultTargets;
50                 public string DefaultTargets {
51                         get { return defaultTargets ?? String.Empty; }
52                         set { defaultTargets = value; }
53                 }
54
55                 string fullPath;
56                 public string FullPath {
57                         get { return fullPath; }
58                         set {
59                                 fullPath = Path.GetFullPath (value);
60                                 DirectoryPath = Path.GetDirectoryName (fullPath);
61                         }
62                 }
63
64                 string directoryPath;
65                 public string DirectoryPath {
66                         get { return directoryPath ?? String.Empty; }
67                         internal set { directoryPath = value; }
68                 }
69
70                 public ICollection<ProjectPropertyElement> Properties {
71                         get { return new CollectionFromEnumerable<ProjectPropertyElement> (
72                                 new FilteredEnumerable<ProjectPropertyElement> (AllChildren)); }
73                 }
74
75                 public ICollection<ProjectChooseElement> ChooseElements {
76                         get { return new CollectionFromEnumerable<ProjectChooseElement> (
77                                 new FilteredEnumerable<ProjectChooseElement> (Children)); }
78                 }
79
80                 public Encoding Encoding {
81                         get { return Encoding.UTF8; }
82                 }
83
84                 public bool HasUnsavedChanges {
85                         get { return true; }
86                 }
87
88                 public ICollection<ProjectImportGroupElement> ImportGroups {
89                         get { return new CollectionFromEnumerable<ProjectImportGroupElement> (
90                                 new FilteredEnumerable<ProjectImportGroupElement> (Children)); }
91                 }
92
93                 public ICollection<ProjectImportGroupElement> ImportGroupsReversed {
94                         get { return new CollectionFromEnumerable<ProjectImportGroupElement> (
95                                 new FilteredEnumerable<ProjectImportGroupElement> (ChildrenReversed)); }
96                 }
97
98                 public ICollection<ProjectImportElement> Imports {
99                         get { return new CollectionFromEnumerable<ProjectImportElement> (
100                                 new FilteredEnumerable<ProjectImportElement> (AllChildren)); }
101                 }
102
103                 string initialTargets;
104                 public string InitialTargets {
105                         get { return initialTargets ?? String.Empty; }
106                         set { initialTargets = value; }
107                 }
108
109                 public ICollection<ProjectItemDefinitionGroupElement> ItemDefinitionGroups {
110                         get { return new CollectionFromEnumerable<ProjectItemDefinitionGroupElement> (
111                                 new FilteredEnumerable<ProjectItemDefinitionGroupElement> (Children)); }
112                 }
113
114                 public ICollection<ProjectItemDefinitionGroupElement> ItemDefinitionGroupsReversed {
115                         get { return new CollectionFromEnumerable<ProjectItemDefinitionGroupElement> (
116                                 new FilteredEnumerable<ProjectItemDefinitionGroupElement> (ChildrenReversed)); }
117                 }
118
119                 public ICollection<ProjectItemDefinitionElement> ItemDefinitions {
120                         get { return new CollectionFromEnumerable<ProjectItemDefinitionElement> (
121                                 new FilteredEnumerable<ProjectItemDefinitionElement> (AllChildren)); }
122                 }
123
124                 public ICollection<ProjectItemGroupElement> ItemGroups {
125                         get { return new CollectionFromEnumerable<ProjectItemGroupElement> (
126                                 new FilteredEnumerable<ProjectItemGroupElement> (Children)); }
127                 }
128
129                 public ICollection<ProjectItemGroupElement> ItemGroupsReversed {
130                         get { return new CollectionFromEnumerable<ProjectItemGroupElement> (
131                                 new FilteredEnumerable<ProjectItemGroupElement> (ChildrenReversed)); }
132                 }
133
134                 public ICollection<ProjectItemElement> Items {
135                         get { return new CollectionFromEnumerable<ProjectItemElement> (
136                                 new FilteredEnumerable<ProjectItemElement> (AllChildren)); }
137                 }
138
139                 public DateTime LastWriteTimeWhenRead {
140                         get { return DateTime.MinValue; }
141                 }
142
143                 public ICollection<ProjectPropertyGroupElement> PropertyGroups {
144                         get { return new CollectionFromEnumerable<ProjectPropertyGroupElement> (
145                                 new FilteredEnumerable<ProjectPropertyGroupElement> (Children)); }
146                 }
147
148                 public ICollection<ProjectPropertyGroupElement> PropertyGroupsReversed {
149                         get { return new CollectionFromEnumerable<ProjectPropertyGroupElement> (
150                                 new FilteredEnumerable<ProjectPropertyGroupElement> (ChildrenReversed)); }
151                 }
152
153                 public string RawXml {
154                         get {
155                                 using (var writer = new StringWriter (CultureInfo.InvariantCulture)) {
156                                         Save (writer);
157                                         return writer.ToString ();
158                                 }
159                         }
160                 }
161
162                 public ICollection<ProjectTargetElement> Targets {
163                         get { return new CollectionFromEnumerable<ProjectTargetElement> (
164                                 new FilteredEnumerable<ProjectTargetElement> (Children)); }
165                 }
166
167                 public DateTime TimeLastChanged {
168                         get { return DateTime.Now; }
169                 }
170
171                 string toolsVersion;
172                 public string ToolsVersion {
173                         get { return toolsVersion ?? "4.0"; }
174                         set { toolsVersion = value; }
175                 }
176
177                 public ICollection<ProjectUsingTaskElement> UsingTasks {
178                         get { return new CollectionFromEnumerable<ProjectUsingTaskElement> (
179                                 new FilteredEnumerable<ProjectUsingTaskElement> (Children)); }
180                 }
181
182                 public int Version {
183                         get { return 0; }
184                 }
185
186                 ProjectRootElement (ProjectCollection projectCollection)
187                 {
188                 }
189
190                 public static ProjectRootElement Create ()
191                 {
192                         return Create (ProjectCollection.GlobalProjectCollection);
193                 }
194
195                 public static ProjectRootElement Create (ProjectCollection projectCollection)
196                 {
197                         return new ProjectRootElement (projectCollection);
198                 }
199
200                 public static ProjectRootElement Create (string path)
201                 {
202                         return Create (path, ProjectCollection.GlobalProjectCollection);
203                 }
204
205                 public static ProjectRootElement Create (XmlReader xmlReader)
206                 {
207                         return Create (xmlReader, ProjectCollection.GlobalProjectCollection);
208                 }
209
210                 public static ProjectRootElement Create (string path, ProjectCollection projectCollection)
211                 {
212                         var result = Create (projectCollection);
213                         result.FullPath = path;
214                         return result;
215                 }
216
217                 public static ProjectRootElement Create (XmlReader xmlReader, ProjectCollection projectCollection)
218                 {
219                         // yes, this should create en empty project
220                         var result = Create (projectCollection);
221                         return result;
222                 }
223
224                 public ProjectImportElement AddImport (string project)
225                 {
226                         var import = CreateImportElement (project);
227                         AppendChild (import);
228                         return import;
229                 }
230
231                 public ProjectImportGroupElement AddImportGroup ()
232                 {
233                         var importGroup = CreateImportGroupElement ();
234                         AppendChild (importGroup);
235                         return importGroup;
236                 }
237
238                 public ProjectItemElement AddItem (string itemType, string include)
239                 {
240                         return AddItem (itemType, include, null);
241                 }
242
243                 public ProjectItemElement AddItem (string itemType, string include,
244                                                    IEnumerable<KeyValuePair<string, string>> metadata)
245                 {
246                         var @group = ItemGroups.
247                                 Where (p => string.IsNullOrEmpty (p.Condition)
248                                        && p.Items.Where (s => s.ItemType.Equals (itemType,
249                                                 StringComparison.OrdinalIgnoreCase)).FirstOrDefault () != null).
250                                         FirstOrDefault ();
251                         if (@group == null)
252                                 @group = AddItemGroup ();
253                         return @group.AddItem (itemType, include, metadata);
254                 }
255
256                 public ProjectItemDefinitionElement AddItemDefinition (string itemType)
257                 {
258                         var @group = ItemDefinitionGroups.
259                                 Where (p => string.IsNullOrEmpty (p.Condition)
260                                        && p.ItemDefinitions.Where (s => s.ItemType.Equals (itemType,
261                                                 StringComparison.OrdinalIgnoreCase)).FirstOrDefault () != null).
262                                         FirstOrDefault ();
263                         if (@group == null)
264                                 @group = AddItemDefinitionGroup ();
265                         return @group.AddItemDefinition (itemType);
266                 }
267
268                 public ProjectItemDefinitionGroupElement AddItemDefinitionGroup ()
269                 {
270                         var @group = CreateItemDefinitionGroupElement ();
271                         ProjectElementContainer last = ItemDefinitionGroupsReversed.FirstOrDefault ();
272                         if (last == null)
273                                 last = PropertyGroupsReversed.FirstOrDefault ();
274                         InsertAfterChild (@group, last);
275                         return @group;
276                 }
277
278                 public ProjectItemGroupElement AddItemGroup ()
279                 {
280                         var @group = CreateItemGroupElement ();
281                         ProjectElementContainer last = ItemGroupsReversed.FirstOrDefault ();
282                         if (last == null)
283                                 last = PropertyGroupsReversed.FirstOrDefault ();
284                         InsertAfterChild (@group, last);
285                         return @group;
286                 }
287
288                 public ProjectPropertyElement AddProperty (string name, string value)
289                 {
290                         ProjectPropertyGroupElement parentGroup = null;
291                         foreach (var @group in PropertyGroups) {
292                                 if (string.IsNullOrEmpty (@group.Condition)) {
293                                         if (parentGroup == null)
294                                                 parentGroup = @group;
295                                         var property = @group.Properties.
296                                                 Where (p => string.IsNullOrEmpty (p.Condition)
297                                                        && p.Name.Equals (name, StringComparison.OrdinalIgnoreCase)).
298                                                         FirstOrDefault ();
299                                         if (property != null) {
300                                                 property.Value = value;
301                                                 return property;
302                                         }
303                                 }
304                         }
305                         if (parentGroup == null)
306                                 parentGroup = AddPropertyGroup ();
307                         return parentGroup.AddProperty (name, value);
308                 }
309
310                 public ProjectPropertyGroupElement AddPropertyGroup ()
311                 {
312                         var @group = CreatePropertyGroupElement ();
313                         var last = PropertyGroupsReversed.FirstOrDefault ();
314                         InsertAfterChild (@group, last);
315                         return @group;
316                 }
317
318                 public ProjectTargetElement AddTarget (string name)
319                 {
320                         var target = CreateTargetElement (name);
321                         AppendChild (target);
322                         return target;
323                 }
324
325                 public ProjectUsingTaskElement AddUsingTask (string name, string assemblyFile, string assemblyName)
326                 {
327                         var usingTask = CreateUsingTaskElement (name, assemblyFile, assemblyName);
328                         AppendChild (usingTask);
329                         return usingTask;
330                 }
331
332                 public ProjectChooseElement CreateChooseElement ()
333                 {
334                         return new ProjectChooseElement (this);
335                 }
336
337                 public ProjectImportElement CreateImportElement (string project)
338                 {
339                         return new ProjectImportElement (project, this);
340                 }
341
342                 public ProjectImportGroupElement CreateImportGroupElement ()
343                 {
344                         return new ProjectImportGroupElement (this);
345                 }
346
347                 public ProjectItemDefinitionElement CreateItemDefinitionElement (string itemType)
348                 {
349                         return new ProjectItemDefinitionElement (itemType, this);
350                 }
351
352                 public ProjectItemDefinitionGroupElement CreateItemDefinitionGroupElement ()
353                 {
354                         return new ProjectItemDefinitionGroupElement (this);
355                 }
356
357                 public ProjectItemElement CreateItemElement (string itemType)
358                 {
359                         return new ProjectItemElement (itemType, this);
360                 }
361
362                 public ProjectItemElement CreateItemElement (string itemType, string include)
363                 {
364                         var item = CreateItemElement (itemType);
365                         item.Include = include;
366                         return item;
367                 }
368
369                 public ProjectItemGroupElement CreateItemGroupElement ()
370                 {
371                         return new ProjectItemGroupElement (this);
372                 }
373
374                 public ProjectMetadataElement CreateMetadataElement (string name)
375                 {
376                         return new ProjectMetadataElement (name, this);
377                 }
378
379                 public ProjectMetadataElement CreateMetadataElement (string name, string unevaluatedValue)
380                 {
381                         var metadata = CreateMetadataElement (name);
382                         metadata.Value = unevaluatedValue;
383                         return metadata;
384                 }
385
386                 public ProjectOnErrorElement CreateOnErrorElement (string executeTargets)
387                 {
388                         return new ProjectOnErrorElement (executeTargets, this);
389                 }
390
391                 public ProjectOtherwiseElement CreateOtherwiseElement ()
392                 {
393                         return new ProjectOtherwiseElement (this);
394                 }
395
396                 public ProjectOutputElement CreateOutputElement (string taskParameter, string itemType,
397                                                                  string propertyName)
398                 {
399                         return new ProjectOutputElement (taskParameter, itemType, propertyName, this);
400                 }
401
402                 public ProjectExtensionsElement CreateProjectExtensionsElement ()
403                 {
404                         return new ProjectExtensionsElement (this);
405                 }
406
407                 public ProjectPropertyElement CreatePropertyElement (string name)
408                 {
409                         return new ProjectPropertyElement (name, this);
410                 }
411
412                 public ProjectPropertyGroupElement CreatePropertyGroupElement ()
413                 {
414                         return new ProjectPropertyGroupElement (this);
415                 }
416
417                 public ProjectTargetElement CreateTargetElement (string name)
418                 {
419                         return new ProjectTargetElement (name, this);
420                 }
421
422                 public ProjectTaskElement CreateTaskElement (string name)
423                 {
424                         return new ProjectTaskElement (name, this);
425                 }
426
427                 public ProjectUsingTaskBodyElement CreateUsingTaskBodyElement (string evaluate, string body)
428                 {
429                         return new ProjectUsingTaskBodyElement (evaluate, body, this);
430                 }
431
432                 public ProjectUsingTaskElement CreateUsingTaskElement (string taskName, string assemblyFile,
433                                                                        string assemblyName)
434                 {
435                         return new ProjectUsingTaskElement (taskName, assemblyFile, assemblyName, this);
436                 }
437
438                 public ProjectUsingTaskParameterElement CreateUsingTaskParameterElement (string name, string output,
439                                                                                          string required,
440                                                                                          string parameterType)
441                 {
442                         return new ProjectUsingTaskParameterElement (name, output, required, parameterType, this);
443                 }
444
445                 public UsingTaskParameterGroupElement CreateUsingTaskParameterGroupElement ()
446                 {
447                         return new UsingTaskParameterGroupElement (this);
448                 }
449
450                 public ProjectWhenElement CreateWhenElement (string condition)
451                 {
452                         return new ProjectWhenElement (condition, this);
453                 }
454
455                 public static ProjectRootElement Open (string path)
456                 {
457                         return Open (path, ProjectCollection.GlobalProjectCollection);
458                 }
459
460                 public static ProjectRootElement Open (string path, ProjectCollection projectCollection)
461                 {
462                         var result = Create (path, projectCollection);
463                         using (var reader = XmlReader.Create (path))
464                                 result.Load (reader);
465                         return result;
466                 }
467
468                 public void Save ()
469                 {
470                         Save (Encoding);
471                 }
472
473                 public void Save (Encoding saveEncoding)
474                 {
475                         using (var writer = new StreamWriter (File.Create (FullPath), saveEncoding)) {
476                                 Save (writer);
477                         }
478                 }
479
480                 public void Save (string path)
481                 {
482                         Save (path, Encoding);
483                 }
484
485                 public void Save (TextWriter writer)
486                 {
487                         using (var xmlWriter = XmlWriter.Create (writer, new XmlWriterSettings { Indent = true,
488                                 NewLineChars = "\r\n" })) {
489                                 Save (xmlWriter);
490                         }
491                 }
492
493                 public void Save (string path, Encoding encoding)
494                 {
495                         FullPath = path;
496                         Save (encoding);
497                 }
498
499                 public static ProjectRootElement TryOpen (string path)
500                 {
501                         return TryOpen (path, ProjectCollection.GlobalProjectCollection);
502                 }
503
504                 public static ProjectRootElement TryOpen (string path, ProjectCollection projectCollection)
505                 {
506                         // this should be non-null only if the project is already cached
507                         // and caching is not yet implemented
508                         return null;
509                 }
510
511                 internal override void Load (XmlReader reader)
512                 {
513                         try {
514                                 base.Load (reader);
515                         } catch (XmlException ex) {
516                                 throw new InvalidProjectFileException (FullPath, ex.LineNumber, ex.LinePosition, 0, 0,
517                                         ex.Message, null, null, null);
518                         }
519                 }
520
521                 internal override ProjectElement LoadChildElement (string name)
522                 {
523                         switch (name) {
524                         case "PropertyGroup":
525                                 var prop = CreatePropertyGroupElement ();
526                                 AppendChild (prop);
527                                 return prop;
528                         case "ItemGroup":
529                                 var item = CreateItemGroupElement ();
530                                 AppendChild (item);
531                                 return item;
532                         case "Import":
533                                 return AddImport (null);
534                         case "Target":
535                                 return AddTarget (null);
536                         case "ItemDefinitionGroup":
537                                 var def = CreateItemDefinitionGroupElement ();
538                                 AppendChild (def);
539                                 return def;
540                         case "UsingTask":
541                                 return AddUsingTask (null, null, null);
542                         case "Choose":
543                                 var choose = CreateChooseElement ();
544                                 AppendChild (choose);
545                                 return choose;
546                         case "ProjectExtensions":
547                                 var ext = CreateProjectExtensionsElement ();
548                                 AppendChild (ext);
549                                 return ext;
550                         default:
551                                 throw new InvalidProjectFileException (string.Format (
552                                         "Child \"{0}\" is not a known node type.", name));
553                         }
554                 }
555
556                 internal override void LoadAttribute (string name, string value)
557                 {
558                         switch (name) {
559                         case "ToolsVersion":
560                                 ToolsVersion = value;
561                                 break;
562                         case "DefaultTargets":
563                                 DefaultTargets = value;
564                                 break;
565                         case "InitialTargets":
566                                 InitialTargets = value;
567                                 break;
568                         default:
569                                 base.LoadAttribute (name, value);
570                                 break;
571                         }
572                 }
573
574                 internal override void Save (XmlWriter writer)
575                 {
576                         writer.WriteStartElement (XmlName, "http://schemas.microsoft.com/developer/msbuild/2003");
577                         SaveValue (writer);
578                         writer.WriteEndElement ();
579                 }
580
581                 internal override void SaveValue (XmlWriter writer)
582                 {
583                         SaveAttribute (writer, "ToolsVersion", ToolsVersion);
584                         SaveAttribute (writer, "DefaultTargets", DefaultTargets);
585                         SaveAttribute (writer, "InitialTargets", InitialTargets);
586                         base.SaveValue (writer);
587                 }
588
589                 internal override string XmlName {
590                         get { return "Project"; }
591                 }
592         }
593 }