Merge pull request #1079 from esdrubal/webclient_cancel
[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 ?? Directory.GetCurrentDirectory (); }
67                         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 ?? string.Empty; }
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                         ToolsVersion = "4.0";
189                 }
190
191                 public static ProjectRootElement Create ()
192                 {
193                         return Create (ProjectCollection.GlobalProjectCollection);
194                 }
195
196                 public static ProjectRootElement Create (ProjectCollection projectCollection)
197                 {
198                         return new ProjectRootElement (projectCollection);
199                 }
200
201                 public static ProjectRootElement Create (string path)
202                 {
203                         return Create (path, ProjectCollection.GlobalProjectCollection);
204                 }
205
206                 public static ProjectRootElement Create (XmlReader xmlReader)
207                 {
208                         return Create (xmlReader, ProjectCollection.GlobalProjectCollection);
209                 }
210
211                 public static ProjectRootElement Create (string path, ProjectCollection projectCollection)
212                 {
213                         var result = Create (projectCollection);
214                         result.FullPath = path;
215                         return result;
216                 }
217
218                 public static ProjectRootElement Create (XmlReader xmlReader, ProjectCollection projectCollection)
219                 {
220                         var result = Create (projectCollection);
221                         result.ToolsVersion = null;
222                         result.Load (xmlReader);
223                         return result;
224                 }
225
226                 public ProjectImportElement AddImport (string project)
227                 {
228                         var import = CreateImportElement (project);
229                         AppendChild (import);
230                         return import;
231                 }
232
233                 public ProjectImportGroupElement AddImportGroup ()
234                 {
235                         var importGroup = CreateImportGroupElement ();
236                         AppendChild (importGroup);
237                         return importGroup;
238                 }
239
240                 public ProjectItemElement AddItem (string itemType, string include)
241                 {
242                         return AddItem (itemType, include, null);
243                 }
244
245                 public ProjectItemElement AddItem (string itemType, string include,
246                                                    IEnumerable<KeyValuePair<string, string>> metadata)
247                 {
248                         var @group = ItemGroups.
249                                 Where (p => string.IsNullOrEmpty (p.Condition)
250                                        && p.Items.Where (s => s.ItemType.Equals (itemType,
251                                                 StringComparison.OrdinalIgnoreCase)).FirstOrDefault () != null).
252                                         FirstOrDefault ();
253                         if (@group == null)
254                                 @group = AddItemGroup ();
255                         return @group.AddItem (itemType, include, metadata);
256                 }
257
258                 public ProjectItemDefinitionElement AddItemDefinition (string itemType)
259                 {
260                         var @group = ItemDefinitionGroups.
261                                 Where (p => string.IsNullOrEmpty (p.Condition)
262                                        && p.ItemDefinitions.Where (s => s.ItemType.Equals (itemType,
263                                                 StringComparison.OrdinalIgnoreCase)).FirstOrDefault () != null).
264                                         FirstOrDefault ();
265                         if (@group == null)
266                                 @group = AddItemDefinitionGroup ();
267                         return @group.AddItemDefinition (itemType);
268                 }
269
270                 public ProjectItemDefinitionGroupElement AddItemDefinitionGroup ()
271                 {
272                         var @group = CreateItemDefinitionGroupElement ();
273                         ProjectElementContainer last = ItemDefinitionGroupsReversed.FirstOrDefault ();
274                         if (last == null)
275                                 last = PropertyGroupsReversed.FirstOrDefault ();
276                         InsertAfterChild (@group, last);
277                         return @group;
278                 }
279
280                 public ProjectItemGroupElement AddItemGroup ()
281                 {
282                         var @group = CreateItemGroupElement ();
283                         ProjectElementContainer last = ItemGroupsReversed.FirstOrDefault ();
284                         if (last == null)
285                                 last = PropertyGroupsReversed.FirstOrDefault ();
286                         InsertAfterChild (@group, last);
287                         return @group;
288                 }
289
290                 public ProjectPropertyElement AddProperty (string name, string value)
291                 {
292                         ProjectPropertyGroupElement parentGroup = null;
293                         foreach (var @group in PropertyGroups) {
294                                 if (string.IsNullOrEmpty (@group.Condition)) {
295                                         if (parentGroup == null)
296                                                 parentGroup = @group;
297                                         var property = @group.Properties.
298                                                 Where (p => string.IsNullOrEmpty (p.Condition)
299                                                        && p.Name.Equals (name, StringComparison.OrdinalIgnoreCase)).
300                                                         FirstOrDefault ();
301                                         if (property != null) {
302                                                 property.Value = value;
303                                                 return property;
304                                         }
305                                 }
306                         }
307                         if (parentGroup == null)
308                                 parentGroup = AddPropertyGroup ();
309                         return parentGroup.AddProperty (name, value);
310                 }
311
312                 public ProjectPropertyGroupElement AddPropertyGroup ()
313                 {
314                         var @group = CreatePropertyGroupElement ();
315                         var last = PropertyGroupsReversed.FirstOrDefault ();
316                         InsertAfterChild (@group, last);
317                         return @group;
318                 }
319
320                 public ProjectTargetElement AddTarget (string name)
321                 {
322                         var target = CreateTargetElement (name);
323                         AppendChild (target);
324                         return target;
325                 }
326
327                 public ProjectUsingTaskElement AddUsingTask (string name, string assemblyFile, string assemblyName)
328                 {
329                         var usingTask = CreateUsingTaskElement (name, assemblyFile, assemblyName);
330                         AppendChild (usingTask);
331                         return usingTask;
332                 }
333
334                 public ProjectChooseElement CreateChooseElement ()
335                 {
336                         return new ProjectChooseElement (this);
337                 }
338
339                 public ProjectImportElement CreateImportElement (string project)
340                 {
341                         return new ProjectImportElement (project, this);
342                 }
343
344                 public ProjectImportGroupElement CreateImportGroupElement ()
345                 {
346                         return new ProjectImportGroupElement (this);
347                 }
348
349                 public ProjectItemDefinitionElement CreateItemDefinitionElement (string itemType)
350                 {
351                         return new ProjectItemDefinitionElement (itemType, this);
352                 }
353
354                 public ProjectItemDefinitionGroupElement CreateItemDefinitionGroupElement ()
355                 {
356                         return new ProjectItemDefinitionGroupElement (this);
357                 }
358
359                 public ProjectItemElement CreateItemElement (string itemType)
360                 {
361                         return new ProjectItemElement (itemType, this);
362                 }
363
364                 public ProjectItemElement CreateItemElement (string itemType, string include)
365                 {
366                         var item = CreateItemElement (itemType);
367                         item.Include = include;
368                         return item;
369                 }
370
371                 public ProjectItemGroupElement CreateItemGroupElement ()
372                 {
373                         return new ProjectItemGroupElement (this);
374                 }
375
376                 public ProjectMetadataElement CreateMetadataElement (string name)
377                 {
378                         return new ProjectMetadataElement (name, this);
379                 }
380
381                 public ProjectMetadataElement CreateMetadataElement (string name, string unevaluatedValue)
382                 {
383                         var metadata = CreateMetadataElement (name);
384                         metadata.Value = unevaluatedValue;
385                         return metadata;
386                 }
387
388                 public ProjectOnErrorElement CreateOnErrorElement (string executeTargets)
389                 {
390                         return new ProjectOnErrorElement (executeTargets, this);
391                 }
392
393                 public ProjectOtherwiseElement CreateOtherwiseElement ()
394                 {
395                         return new ProjectOtherwiseElement (this);
396                 }
397
398                 public ProjectOutputElement CreateOutputElement (string taskParameter, string itemType,
399                                                                  string propertyName)
400                 {
401                         return new ProjectOutputElement (taskParameter, itemType, propertyName, this);
402                 }
403
404                 public ProjectExtensionsElement CreateProjectExtensionsElement ()
405                 {
406                         return new ProjectExtensionsElement (this);
407                 }
408
409                 public ProjectPropertyElement CreatePropertyElement (string name)
410                 {
411                         return new ProjectPropertyElement (name, this);
412                 }
413
414                 public ProjectPropertyGroupElement CreatePropertyGroupElement ()
415                 {
416                         return new ProjectPropertyGroupElement (this);
417                 }
418
419                 public ProjectTargetElement CreateTargetElement (string name)
420                 {
421                         return new ProjectTargetElement (name, this);
422                 }
423
424                 public ProjectTaskElement CreateTaskElement (string name)
425                 {
426                         return new ProjectTaskElement (name, this);
427                 }
428
429                 public ProjectUsingTaskBodyElement CreateUsingTaskBodyElement (string evaluate, string body)
430                 {
431                         return new ProjectUsingTaskBodyElement (evaluate, body, this);
432                 }
433
434                 public ProjectUsingTaskElement CreateUsingTaskElement (string taskName, string assemblyFile,
435                                                                        string assemblyName)
436                 {
437                         return new ProjectUsingTaskElement (taskName, assemblyFile, assemblyName, this);
438                 }
439
440                 public ProjectUsingTaskParameterElement CreateUsingTaskParameterElement (string name, string output,
441                                                                                          string required,
442                                                                                          string parameterType)
443                 {
444                         return new ProjectUsingTaskParameterElement (name, output, required, parameterType, this);
445                 }
446
447                 public UsingTaskParameterGroupElement CreateUsingTaskParameterGroupElement ()
448                 {
449                         return new UsingTaskParameterGroupElement (this);
450                 }
451
452                 public ProjectWhenElement CreateWhenElement (string condition)
453                 {
454                         return new ProjectWhenElement (condition, this);
455                 }
456
457                 public static ProjectRootElement Open (string path)
458                 {
459                         return Open (path, ProjectCollection.GlobalProjectCollection);
460                 }
461
462                 public static ProjectRootElement Open (string path, ProjectCollection projectCollection)
463                 {
464                         var result = Create (path, projectCollection);
465                         using (var reader = XmlReader.Create (path))
466                                 result.Load (reader);
467                         return result;
468                 }
469
470                 public void Save ()
471                 {
472                         if (FullPath == null)
473                                 throw new InvalidOperationException ("This project was not given the file path to write to.");
474                         Save (Encoding);
475                 }
476
477                 public void Save (Encoding saveEncoding)
478                 {
479                         using (var writer = new StreamWriter (File.Create (FullPath), saveEncoding)) {
480                                 Save (writer);
481                         }
482                 }
483
484                 public void Save (string path)
485                 {
486                         Save (path, Encoding);
487                 }
488
489                 public void Save (TextWriter writer)
490                 {
491                         using (var xmlWriter = XmlWriter.Create (writer, new XmlWriterSettings { Indent = true,
492                                 NewLineChars = "\r\n" })) {
493                                 Save (xmlWriter);
494                         }
495                 }
496
497                 public void Save (string path, Encoding encoding)
498                 {
499                         FullPath = path;
500                         Save (encoding);
501                 }
502
503                 public static ProjectRootElement TryOpen (string path)
504                 {
505                         return TryOpen (path, ProjectCollection.GlobalProjectCollection);
506                 }
507
508                 public static ProjectRootElement TryOpen (string path, ProjectCollection projectCollection)
509                 {
510                         // this should be non-null only if the project is already cached
511                         // and caching is not yet implemented
512                         return null;
513                 }
514
515                 internal override void Load (XmlReader reader)
516                 {
517                         try {
518                                 base.Load (reader);
519                         } catch (XmlException ex) {
520                                 throw new InvalidProjectFileException (FullPath, ex.LineNumber, ex.LinePosition, 0, 0,
521                                         ex.Message, null, null, null);
522                         }
523                 }
524
525                 internal override ProjectElement LoadChildElement (XmlReader reader)
526                 {
527                         switch (reader.LocalName) {
528                         case "PropertyGroup":
529                                 var prop = CreatePropertyGroupElement ();
530                                 AppendChild (prop);
531                                 return prop;
532                         case "ItemGroup":
533                                 var item = CreateItemGroupElement ();
534                                 AppendChild (item);
535                                 return item;
536                         case "ImportGroup":
537                                 return AddImportGroup ();
538                         case "Import":
539                                 return AddImport (null);
540                         case "Target":
541                                 return AddTarget (null);
542                         case "ItemDefinitionGroup":
543                                 var def = CreateItemDefinitionGroupElement ();
544                                 AppendChild (def);
545                                 return def;
546                         case "UsingTask":
547                                 var ut = AddUsingTask (null, null, null);
548                                 return ut;
549                         case "Choose":
550                                 var choose = CreateChooseElement ();
551                                 AppendChild (choose);
552                                 return choose;
553                         case "ProjectExtensions":
554                                 var ext = CreateProjectExtensionsElement ();
555                                 AppendChild (ext);
556                                 return ext;
557                         default:
558                                 throw CreateError (reader, string.Format ("Child \"{0}\" is not a known node type.", reader.LocalName), -1);
559                         }
560                 }
561
562                 internal override void LoadAttribute (string name, string value)
563                 {
564                         switch (name) {
565                         case "ToolsVersion":
566                                 ToolsVersion = value;
567                                 break;
568                         case "DefaultTargets":
569                                 DefaultTargets = value;
570                                 break;
571                         case "InitialTargets":
572                                 InitialTargets = value;
573                                 break;
574                         default:
575                                 base.LoadAttribute (name, value);
576                                 break;
577                         }
578                 }
579
580                 internal override void Save (XmlWriter writer)
581                 {
582                         writer.WriteStartElement (XmlName, MSBuildNamespace);
583                         SaveValue (writer);
584                         writer.WriteEndElement ();
585                 }
586
587                 internal override void SaveValue (XmlWriter writer)
588                 {
589                         SaveAttribute (writer, "ToolsVersion", ToolsVersion);
590                         SaveAttribute (writer, "DefaultTargets", DefaultTargets);
591                         SaveAttribute (writer, "InitialTargets", InitialTargets);
592                         base.SaveValue (writer);
593                 }
594
595                 internal override string XmlName {
596                         get { return "Project"; }
597                 }
598         }
599 }