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 public string DefaultTargets { get; set; }
52 public string FullPath {
53 get { return fullPath; }
55 fullPath = Path.GetFullPath (value);
56 DirectoryPath = Path.GetDirectoryName (fullPath);
61 public string DirectoryPath {
62 get { return directoryPath ?? String.Empty; }
63 internal set { directoryPath = value; }
66 public ICollection<ProjectPropertyElement> Properties {
67 get { return new CollectionFromEnumerable<ProjectPropertyElement> (
68 new FilteredEnumerable<ProjectPropertyElement> (AllChildren)); }
71 public ICollection<ProjectChooseElement> ChooseElements {
72 get { return new CollectionFromEnumerable<ProjectChooseElement> (
73 new FilteredEnumerable<ProjectChooseElement> (Children)); }
76 public Encoding Encoding {
77 get { return Encoding.UTF8; }
80 public bool HasUnsavedChanges {
84 public ICollection<ProjectImportGroupElement> ImportGroups {
85 get { return new CollectionFromEnumerable<ProjectImportGroupElement> (
86 new FilteredEnumerable<ProjectImportGroupElement> (Children)); }
89 public ICollection<ProjectImportGroupElement> ImportGroupsReversed {
90 get { return new CollectionFromEnumerable<ProjectImportGroupElement> (
91 new FilteredEnumerable<ProjectImportGroupElement> (ChildrenReversed)); }
94 public ICollection<ProjectImportElement> Imports {
95 get { return new CollectionFromEnumerable<ProjectImportElement> (
96 new FilteredEnumerable<ProjectImportElement> (AllChildren)); }
99 public string InitialTargets { get; set; }
101 public ICollection<ProjectItemDefinitionGroupElement> ItemDefinitionGroups {
102 get { return new CollectionFromEnumerable<ProjectItemDefinitionGroupElement> (
103 new FilteredEnumerable<ProjectItemDefinitionGroupElement> (Children)); }
106 public ICollection<ProjectItemDefinitionGroupElement> ItemDefinitionGroupsReversed {
107 get { return new CollectionFromEnumerable<ProjectItemDefinitionGroupElement> (
108 new FilteredEnumerable<ProjectItemDefinitionGroupElement> (ChildrenReversed)); }
111 public ICollection<ProjectItemDefinitionElement> ItemDefinitions {
112 get { return new CollectionFromEnumerable<ProjectItemDefinitionElement> (
113 new FilteredEnumerable<ProjectItemDefinitionElement> (AllChildren)); }
116 public ICollection<ProjectItemGroupElement> ItemGroups {
117 get { return new CollectionFromEnumerable<ProjectItemGroupElement> (
118 new FilteredEnumerable<ProjectItemGroupElement> (Children)); }
121 public ICollection<ProjectItemGroupElement> ItemGroupsReversed {
122 get { return new CollectionFromEnumerable<ProjectItemGroupElement> (
123 new FilteredEnumerable<ProjectItemGroupElement> (ChildrenReversed)); }
126 public ICollection<ProjectItemElement> Items {
127 get { return new CollectionFromEnumerable<ProjectItemElement> (
128 new FilteredEnumerable<ProjectItemElement> (AllChildren)); }
131 public DateTime LastWriteTimeWhenRead {
132 get { return DateTime.MinValue; }
135 public ICollection<ProjectPropertyGroupElement> PropertyGroups {
136 get { return new CollectionFromEnumerable<ProjectPropertyGroupElement> (
137 new FilteredEnumerable<ProjectPropertyGroupElement> (Children)); }
140 public ICollection<ProjectPropertyGroupElement> PropertyGroupsReversed {
141 get { return new CollectionFromEnumerable<ProjectPropertyGroupElement> (
142 new FilteredEnumerable<ProjectPropertyGroupElement> (ChildrenReversed)); }
145 public string RawXml {
147 using (var writer = new StringWriter (CultureInfo.InvariantCulture)) {
149 return writer.ToString ();
154 public ICollection<ProjectTargetElement> Targets {
155 get { return new CollectionFromEnumerable<ProjectTargetElement> (
156 new FilteredEnumerable<ProjectTargetElement> (Children)); }
159 public DateTime TimeLastChanged {
160 get { return DateTime.Now; }
163 string toolsVersion = "4.0";
164 public string ToolsVersion {
165 get { return toolsVersion; }
166 set { toolsVersion = value; }
169 public ICollection<ProjectUsingTaskElement> UsingTasks {
170 get { return new CollectionFromEnumerable<ProjectUsingTaskElement> (
171 new FilteredEnumerable<ProjectUsingTaskElement> (Children)); }
178 ProjectRootElement (ProjectCollection projectCollection)
182 public static ProjectRootElement Create ()
184 return Create (ProjectCollection.GlobalProjectCollection);
187 public static ProjectRootElement Create (ProjectCollection projectCollection)
189 return new ProjectRootElement (projectCollection);
192 public static ProjectRootElement Create (string path)
194 return Create (path, ProjectCollection.GlobalProjectCollection);
197 public static ProjectRootElement Create (XmlReader xmlReader)
199 return Create (xmlReader, ProjectCollection.GlobalProjectCollection);
202 public static ProjectRootElement Create (string path, ProjectCollection projectCollection)
204 var result = Create (projectCollection);
205 result.FullPath = path;
209 public static ProjectRootElement Create (XmlReader xmlReader, ProjectCollection projectCollection)
211 // yes, this should create en empty project
212 var result = Create (projectCollection);
216 public ProjectImportElement AddImport (string project)
218 var import = CreateImportElement (project);
219 AppendChild (import);
223 public ProjectImportGroupElement AddImportGroup ()
225 var importGroup = CreateImportGroupElement ();
226 AppendChild (importGroup);
230 public ProjectItemElement AddItem (string itemType, string include)
232 return AddItem (itemType, include, null);
235 public ProjectItemElement AddItem (string itemType, string include,
236 IEnumerable<KeyValuePair<string, string>> metadata)
238 var @group = ItemGroups.
239 Where (p => string.IsNullOrEmpty (p.Condition)
240 && p.Items.Where (s => s.ItemType.Equals (itemType,
241 StringComparison.OrdinalIgnoreCase)).FirstOrDefault () != null).
244 @group = AddItemGroup ();
245 return @group.AddItem (itemType, include, metadata);
248 public ProjectItemDefinitionElement AddItemDefinition (string itemType)
250 var @group = ItemDefinitionGroups.
251 Where (p => string.IsNullOrEmpty (p.Condition)
252 && p.ItemDefinitions.Where (s => s.ItemType.Equals (itemType,
253 StringComparison.OrdinalIgnoreCase)).FirstOrDefault () != null).
256 @group = AddItemDefinitionGroup ();
257 return @group.AddItemDefinition (itemType);
260 public ProjectItemDefinitionGroupElement AddItemDefinitionGroup ()
262 var @group = CreateItemDefinitionGroupElement ();
263 ProjectElementContainer last = ItemDefinitionGroupsReversed.FirstOrDefault ();
265 last = PropertyGroupsReversed.FirstOrDefault ();
266 InsertAfterChild (@group, last);
270 public ProjectItemGroupElement AddItemGroup ()
272 var @group = CreateItemGroupElement ();
273 ProjectElementContainer last = ItemGroupsReversed.FirstOrDefault ();
275 last = PropertyGroupsReversed.FirstOrDefault ();
276 InsertAfterChild (@group, last);
280 public ProjectPropertyElement AddProperty (string name, string value)
282 ProjectPropertyGroupElement parentGroup = null;
283 foreach (var @group in PropertyGroups) {
284 if (string.IsNullOrEmpty (@group.Condition)) {
285 if (parentGroup == null)
286 parentGroup = @group;
287 var property = @group.Properties.
288 Where (p => string.IsNullOrEmpty (p.Condition)
289 && p.Name.Equals (name, StringComparison.OrdinalIgnoreCase)).
291 if (property != null) {
292 property.Value = value;
297 if (parentGroup == null)
298 parentGroup = AddPropertyGroup ();
299 return parentGroup.AddProperty (name, value);
302 public ProjectPropertyGroupElement AddPropertyGroup ()
304 var @group = CreatePropertyGroupElement ();
305 var last = PropertyGroupsReversed.FirstOrDefault ();
306 InsertAfterChild (@group, last);
310 public ProjectTargetElement AddTarget (string name)
312 var target = CreateTargetElement (name);
313 AppendChild (target);
317 public ProjectUsingTaskElement AddUsingTask (string name, string assemblyFile, string assemblyName)
319 var usingTask = CreateUsingTaskElement (name, assemblyFile, assemblyName);
320 AppendChild (usingTask);
324 public ProjectChooseElement CreateChooseElement ()
326 return new ProjectChooseElement (this);
329 public ProjectImportElement CreateImportElement (string project)
331 return new ProjectImportElement (project, this);
334 public ProjectImportGroupElement CreateImportGroupElement ()
336 return new ProjectImportGroupElement (this);
339 public ProjectItemDefinitionElement CreateItemDefinitionElement (string itemType)
341 return new ProjectItemDefinitionElement (itemType, this);
344 public ProjectItemDefinitionGroupElement CreateItemDefinitionGroupElement ()
346 return new ProjectItemDefinitionGroupElement (this);
349 public ProjectItemElement CreateItemElement (string itemType)
351 return new ProjectItemElement (itemType, this);
354 public ProjectItemElement CreateItemElement (string itemType, string include)
356 var item = CreateItemElement (itemType);
357 item.Include = include;
361 public ProjectItemGroupElement CreateItemGroupElement ()
363 return new ProjectItemGroupElement (this);
366 public ProjectMetadataElement CreateMetadataElement (string name)
368 return new ProjectMetadataElement (name, this);
371 public ProjectMetadataElement CreateMetadataElement (string name, string unevaluatedValue)
373 var metadata = CreateMetadataElement (name);
374 metadata.Value = unevaluatedValue;
378 public ProjectOnErrorElement CreateOnErrorElement (string executeTargets)
380 return new ProjectOnErrorElement (executeTargets, this);
383 public ProjectOtherwiseElement CreateOtherwiseElement ()
385 return new ProjectOtherwiseElement (this);
388 public ProjectOutputElement CreateOutputElement (string taskParameter, string itemType,
391 return new ProjectOutputElement (taskParameter, itemType, propertyName, this);
394 public ProjectExtensionsElement CreateProjectExtensionsElement ()
396 return new ProjectExtensionsElement (this);
399 public ProjectPropertyElement CreatePropertyElement (string name)
401 return new ProjectPropertyElement (name, this);
404 public ProjectPropertyGroupElement CreatePropertyGroupElement ()
406 return new ProjectPropertyGroupElement (this);
409 public ProjectTargetElement CreateTargetElement (string name)
411 return new ProjectTargetElement (name, this);
414 public ProjectTaskElement CreateTaskElement (string name)
416 return new ProjectTaskElement (name, this);
419 public ProjectUsingTaskBodyElement CreateUsingTaskBodyElement (string evaluate, string body)
421 return new ProjectUsingTaskBodyElement (evaluate, body, this);
424 public ProjectUsingTaskElement CreateUsingTaskElement (string taskName, string assemblyFile,
427 return new ProjectUsingTaskElement (taskName, assemblyFile, assemblyName, this);
430 public ProjectUsingTaskParameterElement CreateUsingTaskParameterElement (string name, string output,
432 string parameterType)
434 return new ProjectUsingTaskParameterElement (name, output, required, parameterType, this);
437 public UsingTaskParameterGroupElement CreateUsingTaskParameterGroupElement ()
439 return new UsingTaskParameterGroupElement (this);
442 public ProjectWhenElement CreateWhenElement (string condition)
444 return new ProjectWhenElement (condition, this);
447 public static ProjectRootElement Open (string path)
449 return Open (path, ProjectCollection.GlobalProjectCollection);
452 public static ProjectRootElement Open (string path, ProjectCollection projectCollection)
454 var result = Create (path, projectCollection);
455 using (var reader = XmlReader.Create (path))
456 result.Load (reader);
465 public void Save (Encoding saveEncoding)
467 using (var writer = new StreamWriter (File.Create (FullPath), saveEncoding)) {
472 public void Save (string path)
474 Save (path, Encoding);
477 public void Save (TextWriter writer)
479 using (var xmlWriter = XmlWriter.Create (writer, new XmlWriterSettings { Indent = true,
480 NewLineChars = "\r\n" })) {
485 public void Save (string path, Encoding encoding)
491 public static ProjectRootElement TryOpen (string path)
493 return TryOpen (path, ProjectCollection.GlobalProjectCollection);
496 public static ProjectRootElement TryOpen (string path, ProjectCollection projectCollection)
498 // this should be non-null only if the project is already cached
499 // and caching is not yet implemented
503 internal override void Load (XmlReader reader)
507 } catch (XmlException ex) {
508 throw new InvalidProjectFileException (FullPath, ex.LineNumber, ex.LinePosition, 0, 0,
509 ex.Message, null, null, null);
513 internal override ProjectElement LoadChildElement (string name)
516 case "PropertyGroup":
517 var prop = CreatePropertyGroupElement ();
521 var item = CreateItemGroupElement ();
525 return AddImport (null);
527 return AddTarget (null);
528 case "ItemDefinitionGroup":
529 var def = CreateItemDefinitionGroupElement ();
533 return AddUsingTask (null, null, null);
535 var choose = CreateChooseElement ();
536 AppendChild (choose);
538 case "ProjectExtensions":
539 var ext = CreateProjectExtensionsElement ();
543 throw new InvalidProjectFileException (string.Format (
544 "Child \"{0}\" is not a known node type.", name));
548 internal override void LoadAttribute (string name, string value)
552 ToolsVersion = value;
554 case "DefaultTargets":
555 DefaultTargets = value;
557 case "InitialTargets":
558 InitialTargets = value;
561 base.LoadAttribute (name, value);
566 internal override void Save (XmlWriter writer)
568 writer.WriteStartElement (XmlName, "http://schemas.microsoft.com/developer/msbuild/2003");
570 writer.WriteEndElement ();
573 internal override void SaveValue (XmlWriter writer)
575 SaveAttribute (writer, "ToolsVersion", ToolsVersion);
576 SaveAttribute (writer, "DefaultTargets", DefaultTargets);
577 SaveAttribute (writer, "InitialTargets", InitialTargets);
578 base.SaveValue (writer);
581 internal override string XmlName {
582 get { return "Project"; }