2 // ProjectRootElement.cs
5 // Leszek Ciesielski (skolima@gmail.com)
7 // (C) 2011 Leszek Ciesielski
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System.Collections.Generic;
31 using Microsoft.Build.Evaluation;
32 using Microsoft.Build.Internal;
38 using System.Globalization;
39 using Microsoft.Build.Exceptions;
41 namespace Microsoft.Build.Construction
43 [System.Diagnostics.DebuggerDisplayAttribute("{FullPath} #Children={Count} DefaultTargets={DefaultTargets} "
44 + "ToolsVersion={ToolsVersion} InitialTargets={InitialTargets}")]
45 public class ProjectRootElement : ProjectElementContainer
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; }
56 public string FullPath {
57 get { return fullPath; }
59 fullPath = Path.GetFullPath (value);
60 DirectoryPath = Path.GetDirectoryName (fullPath);
65 public string DirectoryPath {
66 get { return directoryPath ?? Directory.GetCurrentDirectory (); }
67 set { directoryPath = value; }
70 public ICollection<ProjectPropertyElement> Properties {
71 get { return new CollectionFromEnumerable<ProjectPropertyElement> (
72 new FilteredEnumerable<ProjectPropertyElement> (AllChildren)); }
75 public ICollection<ProjectChooseElement> ChooseElements {
76 get { return new CollectionFromEnumerable<ProjectChooseElement> (
77 new FilteredEnumerable<ProjectChooseElement> (Children)); }
80 public Encoding Encoding {
81 get { return Encoding.UTF8; }
84 public bool HasUnsavedChanges {
88 public ICollection<ProjectImportGroupElement> ImportGroups {
89 get { return new CollectionFromEnumerable<ProjectImportGroupElement> (
90 new FilteredEnumerable<ProjectImportGroupElement> (Children)); }
93 public ICollection<ProjectImportGroupElement> ImportGroupsReversed {
94 get { return new CollectionFromEnumerable<ProjectImportGroupElement> (
95 new FilteredEnumerable<ProjectImportGroupElement> (ChildrenReversed)); }
98 public ICollection<ProjectImportElement> Imports {
99 get { return new CollectionFromEnumerable<ProjectImportElement> (
100 new FilteredEnumerable<ProjectImportElement> (AllChildren)); }
103 string initialTargets;
104 public string InitialTargets {
105 get { return initialTargets ?? String.Empty; }
106 set { initialTargets = value; }
109 public ICollection<ProjectItemDefinitionGroupElement> ItemDefinitionGroups {
110 get { return new CollectionFromEnumerable<ProjectItemDefinitionGroupElement> (
111 new FilteredEnumerable<ProjectItemDefinitionGroupElement> (Children)); }
114 public ICollection<ProjectItemDefinitionGroupElement> ItemDefinitionGroupsReversed {
115 get { return new CollectionFromEnumerable<ProjectItemDefinitionGroupElement> (
116 new FilteredEnumerable<ProjectItemDefinitionGroupElement> (ChildrenReversed)); }
119 public ICollection<ProjectItemDefinitionElement> ItemDefinitions {
120 get { return new CollectionFromEnumerable<ProjectItemDefinitionElement> (
121 new FilteredEnumerable<ProjectItemDefinitionElement> (AllChildren)); }
124 public ICollection<ProjectItemGroupElement> ItemGroups {
125 get { return new CollectionFromEnumerable<ProjectItemGroupElement> (
126 new FilteredEnumerable<ProjectItemGroupElement> (Children)); }
129 public ICollection<ProjectItemGroupElement> ItemGroupsReversed {
130 get { return new CollectionFromEnumerable<ProjectItemGroupElement> (
131 new FilteredEnumerable<ProjectItemGroupElement> (ChildrenReversed)); }
134 public ICollection<ProjectItemElement> Items {
135 get { return new CollectionFromEnumerable<ProjectItemElement> (
136 new FilteredEnumerable<ProjectItemElement> (AllChildren)); }
139 public DateTime LastWriteTimeWhenRead {
140 get { return DateTime.MinValue; }
143 public ICollection<ProjectPropertyGroupElement> PropertyGroups {
144 get { return new CollectionFromEnumerable<ProjectPropertyGroupElement> (
145 new FilteredEnumerable<ProjectPropertyGroupElement> (Children)); }
148 public ICollection<ProjectPropertyGroupElement> PropertyGroupsReversed {
149 get { return new CollectionFromEnumerable<ProjectPropertyGroupElement> (
150 new FilteredEnumerable<ProjectPropertyGroupElement> (ChildrenReversed)); }
153 public string RawXml {
155 using (var writer = new StringWriter (CultureInfo.InvariantCulture)) {
157 return writer.ToString ();
162 public ICollection<ProjectTargetElement> Targets {
163 get { return new CollectionFromEnumerable<ProjectTargetElement> (
164 new FilteredEnumerable<ProjectTargetElement> (Children)); }
167 public DateTime TimeLastChanged {
168 get { return DateTime.Now; }
172 public string ToolsVersion {
173 get { return toolsVersion ?? string.Empty; }
174 set { toolsVersion = value; }
177 public ICollection<ProjectUsingTaskElement> UsingTasks {
178 get { return new CollectionFromEnumerable<ProjectUsingTaskElement> (
179 new FilteredEnumerable<ProjectUsingTaskElement> (Children)); }
186 ProjectRootElement (ProjectCollection projectCollection)
188 ToolsVersion = "4.0";
191 public static ProjectRootElement Create ()
193 return Create (ProjectCollection.GlobalProjectCollection);
196 public static ProjectRootElement Create (ProjectCollection projectCollection)
198 return new ProjectRootElement (projectCollection);
201 public static ProjectRootElement Create (string path)
203 return Create (path, ProjectCollection.GlobalProjectCollection);
206 public static ProjectRootElement Create (XmlReader xmlReader)
208 return Create (xmlReader, ProjectCollection.GlobalProjectCollection);
211 public static ProjectRootElement Create (string path, ProjectCollection projectCollection)
213 var result = Create (projectCollection);
214 result.FullPath = path;
218 public static ProjectRootElement Create (XmlReader xmlReader, ProjectCollection projectCollection)
220 var result = Create (projectCollection);
221 result.ToolsVersion = null;
222 result.Load (xmlReader);
226 public ProjectImportElement AddImport (string project)
228 var import = CreateImportElement (project);
229 AppendChild (import);
233 public ProjectImportGroupElement AddImportGroup ()
235 var importGroup = CreateImportGroupElement ();
236 AppendChild (importGroup);
240 public ProjectItemElement AddItem (string itemType, string include)
242 return AddItem (itemType, include, null);
245 public ProjectItemElement AddItem (string itemType, string include,
246 IEnumerable<KeyValuePair<string, string>> metadata)
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).
254 @group = AddItemGroup ();
255 return @group.AddItem (itemType, include, metadata);
258 public ProjectItemDefinitionElement AddItemDefinition (string itemType)
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).
266 @group = AddItemDefinitionGroup ();
267 return @group.AddItemDefinition (itemType);
270 public ProjectItemDefinitionGroupElement AddItemDefinitionGroup ()
272 var @group = CreateItemDefinitionGroupElement ();
273 ProjectElementContainer last = ItemDefinitionGroupsReversed.FirstOrDefault ();
275 last = PropertyGroupsReversed.FirstOrDefault ();
276 InsertAfterChild (@group, last);
280 public ProjectItemGroupElement AddItemGroup ()
282 var @group = CreateItemGroupElement ();
283 ProjectElementContainer last = ItemGroupsReversed.FirstOrDefault ();
285 last = PropertyGroupsReversed.FirstOrDefault ();
286 InsertAfterChild (@group, last);
290 public ProjectPropertyElement AddProperty (string name, string value)
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)).
301 if (property != null) {
302 property.Value = value;
307 if (parentGroup == null)
308 parentGroup = AddPropertyGroup ();
309 return parentGroup.AddProperty (name, value);
312 public ProjectPropertyGroupElement AddPropertyGroup ()
314 var @group = CreatePropertyGroupElement ();
315 var last = PropertyGroupsReversed.FirstOrDefault ();
316 InsertAfterChild (@group, last);
320 public ProjectTargetElement AddTarget (string name)
322 var target = CreateTargetElement (name);
323 AppendChild (target);
327 public ProjectUsingTaskElement AddUsingTask (string name, string assemblyFile, string assemblyName)
329 var usingTask = CreateUsingTaskElement (name, assemblyFile, assemblyName);
330 AppendChild (usingTask);
334 public ProjectChooseElement CreateChooseElement ()
336 return new ProjectChooseElement (this);
339 public ProjectImportElement CreateImportElement (string project)
341 return new ProjectImportElement (project, this);
344 public ProjectImportGroupElement CreateImportGroupElement ()
346 return new ProjectImportGroupElement (this);
349 public ProjectItemDefinitionElement CreateItemDefinitionElement (string itemType)
351 return new ProjectItemDefinitionElement (itemType, this);
354 public ProjectItemDefinitionGroupElement CreateItemDefinitionGroupElement ()
356 return new ProjectItemDefinitionGroupElement (this);
359 public ProjectItemElement CreateItemElement (string itemType)
361 return new ProjectItemElement (itemType, this);
364 public ProjectItemElement CreateItemElement (string itemType, string include)
366 var item = CreateItemElement (itemType);
367 item.Include = include;
371 public ProjectItemGroupElement CreateItemGroupElement ()
373 return new ProjectItemGroupElement (this);
376 public ProjectMetadataElement CreateMetadataElement (string name)
378 return new ProjectMetadataElement (name, this);
381 public ProjectMetadataElement CreateMetadataElement (string name, string unevaluatedValue)
383 var metadata = CreateMetadataElement (name);
384 metadata.Value = unevaluatedValue;
388 public ProjectOnErrorElement CreateOnErrorElement (string executeTargets)
390 return new ProjectOnErrorElement (executeTargets, this);
393 public ProjectOtherwiseElement CreateOtherwiseElement ()
395 return new ProjectOtherwiseElement (this);
398 public ProjectOutputElement CreateOutputElement (string taskParameter, string itemType,
401 return new ProjectOutputElement (taskParameter, itemType, propertyName, this);
404 public ProjectExtensionsElement CreateProjectExtensionsElement ()
406 return new ProjectExtensionsElement (this);
409 public ProjectPropertyElement CreatePropertyElement (string name)
411 return new ProjectPropertyElement (name, this);
414 public ProjectPropertyGroupElement CreatePropertyGroupElement ()
416 return new ProjectPropertyGroupElement (this);
419 public ProjectTargetElement CreateTargetElement (string name)
421 return new ProjectTargetElement (name, this);
424 public ProjectTaskElement CreateTaskElement (string name)
426 return new ProjectTaskElement (name, this);
429 public ProjectUsingTaskBodyElement CreateUsingTaskBodyElement (string evaluate, string body)
431 return new ProjectUsingTaskBodyElement (evaluate, body, this);
434 public ProjectUsingTaskElement CreateUsingTaskElement (string taskName, string assemblyFile,
437 return new ProjectUsingTaskElement (taskName, assemblyFile, assemblyName, this);
440 public ProjectUsingTaskParameterElement CreateUsingTaskParameterElement (string name, string output,
442 string parameterType)
444 return new ProjectUsingTaskParameterElement (name, output, required, parameterType, this);
447 public UsingTaskParameterGroupElement CreateUsingTaskParameterGroupElement ()
449 return new UsingTaskParameterGroupElement (this);
452 public ProjectWhenElement CreateWhenElement (string condition)
454 return new ProjectWhenElement (condition, this);
457 public static ProjectRootElement Open (string path)
459 return Open (path, ProjectCollection.GlobalProjectCollection);
462 public static ProjectRootElement Open (string path, ProjectCollection projectCollection)
464 var result = Create (path, projectCollection);
465 using (var reader = XmlReader.Create (path))
466 result.Load (reader);
472 if (FullPath == null)
473 throw new InvalidOperationException ("This project was not given the file path to write to.");
477 public void Save (Encoding saveEncoding)
479 using (var writer = new StreamWriter (File.Create (FullPath), saveEncoding)) {
484 public void Save (string path)
486 Save (path, Encoding);
489 public void Save (TextWriter writer)
491 using (var xmlWriter = XmlWriter.Create (writer, new XmlWriterSettings { Indent = true,
492 NewLineChars = "\r\n" })) {
497 public void Save (string path, Encoding encoding)
503 public static ProjectRootElement TryOpen (string path)
505 return TryOpen (path, ProjectCollection.GlobalProjectCollection);
508 public static ProjectRootElement TryOpen (string path, ProjectCollection projectCollection)
510 // this should be non-null only if the project is already cached
511 // and caching is not yet implemented
515 internal override void Load (XmlReader reader)
519 } catch (XmlException ex) {
520 throw new InvalidProjectFileException (FullPath, ex.LineNumber, ex.LinePosition, 0, 0,
521 ex.Message, null, null, null);
525 internal override ProjectElement LoadChildElement (XmlReader reader)
527 switch (reader.LocalName) {
528 case "PropertyGroup":
529 var prop = CreatePropertyGroupElement ();
533 var item = CreateItemGroupElement ();
537 return AddImportGroup ();
539 return AddImport (null);
541 return AddTarget (null);
542 case "ItemDefinitionGroup":
543 var def = CreateItemDefinitionGroupElement ();
547 var ut = AddUsingTask (null, null, null);
550 var choose = CreateChooseElement ();
551 AppendChild (choose);
553 case "ProjectExtensions":
554 var ext = CreateProjectExtensionsElement ();
558 throw CreateError (reader, string.Format ("Child \"{0}\" is not a known node type.", reader.LocalName), -1);
562 internal override void LoadAttribute (string name, string value)
566 ToolsVersion = value;
568 case "DefaultTargets":
569 DefaultTargets = value;
571 case "InitialTargets":
572 InitialTargets = value;
575 base.LoadAttribute (name, value);
580 internal override void Save (XmlWriter writer)
582 writer.WriteStartElement (XmlName, MSBuildNamespace);
584 writer.WriteEndElement ();
587 internal override void SaveValue (XmlWriter writer)
589 SaveAttribute (writer, "ToolsVersion", ToolsVersion);
590 SaveAttribute (writer, "DefaultTargets", DefaultTargets);
591 SaveAttribute (writer, "InitialTargets", InitialTargets);
592 base.SaveValue (writer);
595 internal override string XmlName {
596 get { return "Project"; }