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 ?? String.Empty; }
67 internal 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 ?? "4.0"; }
174 set { toolsVersion = value; }
177 public ICollection<ProjectUsingTaskElement> UsingTasks {
178 get { return new CollectionFromEnumerable<ProjectUsingTaskElement> (
179 new FilteredEnumerable<ProjectUsingTaskElement> (Children)); }
186 ProjectRootElement (ProjectCollection projectCollection)
190 public static ProjectRootElement Create ()
192 return Create (ProjectCollection.GlobalProjectCollection);
195 public static ProjectRootElement Create (ProjectCollection projectCollection)
197 return new ProjectRootElement (projectCollection);
200 public static ProjectRootElement Create (string path)
202 return Create (path, ProjectCollection.GlobalProjectCollection);
205 public static ProjectRootElement Create (XmlReader xmlReader)
207 return Create (xmlReader, ProjectCollection.GlobalProjectCollection);
210 public static ProjectRootElement Create (string path, ProjectCollection projectCollection)
212 var result = Create (projectCollection);
213 result.FullPath = path;
217 public static ProjectRootElement Create (XmlReader xmlReader, ProjectCollection projectCollection)
219 // yes, this should create en empty project
220 var result = Create (projectCollection);
224 public ProjectImportElement AddImport (string project)
226 var import = CreateImportElement (project);
227 AppendChild (import);
231 public ProjectImportGroupElement AddImportGroup ()
233 var importGroup = CreateImportGroupElement ();
234 AppendChild (importGroup);
238 public ProjectItemElement AddItem (string itemType, string include)
240 return AddItem (itemType, include, null);
243 public ProjectItemElement AddItem (string itemType, string include,
244 IEnumerable<KeyValuePair<string, string>> metadata)
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).
252 @group = AddItemGroup ();
253 return @group.AddItem (itemType, include, metadata);
256 public ProjectItemDefinitionElement AddItemDefinition (string itemType)
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).
264 @group = AddItemDefinitionGroup ();
265 return @group.AddItemDefinition (itemType);
268 public ProjectItemDefinitionGroupElement AddItemDefinitionGroup ()
270 var @group = CreateItemDefinitionGroupElement ();
271 ProjectElementContainer last = ItemDefinitionGroupsReversed.FirstOrDefault ();
273 last = PropertyGroupsReversed.FirstOrDefault ();
274 InsertAfterChild (@group, last);
278 public ProjectItemGroupElement AddItemGroup ()
280 var @group = CreateItemGroupElement ();
281 ProjectElementContainer last = ItemGroupsReversed.FirstOrDefault ();
283 last = PropertyGroupsReversed.FirstOrDefault ();
284 InsertAfterChild (@group, last);
288 public ProjectPropertyElement AddProperty (string name, string value)
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)).
299 if (property != null) {
300 property.Value = value;
305 if (parentGroup == null)
306 parentGroup = AddPropertyGroup ();
307 return parentGroup.AddProperty (name, value);
310 public ProjectPropertyGroupElement AddPropertyGroup ()
312 var @group = CreatePropertyGroupElement ();
313 var last = PropertyGroupsReversed.FirstOrDefault ();
314 InsertAfterChild (@group, last);
318 public ProjectTargetElement AddTarget (string name)
320 var target = CreateTargetElement (name);
321 AppendChild (target);
325 public ProjectUsingTaskElement AddUsingTask (string name, string assemblyFile, string assemblyName)
327 var usingTask = CreateUsingTaskElement (name, assemblyFile, assemblyName);
328 AppendChild (usingTask);
332 public ProjectChooseElement CreateChooseElement ()
334 return new ProjectChooseElement (this);
337 public ProjectImportElement CreateImportElement (string project)
339 return new ProjectImportElement (project, this);
342 public ProjectImportGroupElement CreateImportGroupElement ()
344 return new ProjectImportGroupElement (this);
347 public ProjectItemDefinitionElement CreateItemDefinitionElement (string itemType)
349 return new ProjectItemDefinitionElement (itemType, this);
352 public ProjectItemDefinitionGroupElement CreateItemDefinitionGroupElement ()
354 return new ProjectItemDefinitionGroupElement (this);
357 public ProjectItemElement CreateItemElement (string itemType)
359 return new ProjectItemElement (itemType, this);
362 public ProjectItemElement CreateItemElement (string itemType, string include)
364 var item = CreateItemElement (itemType);
365 item.Include = include;
369 public ProjectItemGroupElement CreateItemGroupElement ()
371 return new ProjectItemGroupElement (this);
374 public ProjectMetadataElement CreateMetadataElement (string name)
376 return new ProjectMetadataElement (name, this);
379 public ProjectMetadataElement CreateMetadataElement (string name, string unevaluatedValue)
381 var metadata = CreateMetadataElement (name);
382 metadata.Value = unevaluatedValue;
386 public ProjectOnErrorElement CreateOnErrorElement (string executeTargets)
388 return new ProjectOnErrorElement (executeTargets, this);
391 public ProjectOtherwiseElement CreateOtherwiseElement ()
393 return new ProjectOtherwiseElement (this);
396 public ProjectOutputElement CreateOutputElement (string taskParameter, string itemType,
399 return new ProjectOutputElement (taskParameter, itemType, propertyName, this);
402 public ProjectExtensionsElement CreateProjectExtensionsElement ()
404 return new ProjectExtensionsElement (this);
407 public ProjectPropertyElement CreatePropertyElement (string name)
409 return new ProjectPropertyElement (name, this);
412 public ProjectPropertyGroupElement CreatePropertyGroupElement ()
414 return new ProjectPropertyGroupElement (this);
417 public ProjectTargetElement CreateTargetElement (string name)
419 return new ProjectTargetElement (name, this);
422 public ProjectTaskElement CreateTaskElement (string name)
424 return new ProjectTaskElement (name, this);
427 public ProjectUsingTaskBodyElement CreateUsingTaskBodyElement (string evaluate, string body)
429 return new ProjectUsingTaskBodyElement (evaluate, body, this);
432 public ProjectUsingTaskElement CreateUsingTaskElement (string taskName, string assemblyFile,
435 return new ProjectUsingTaskElement (taskName, assemblyFile, assemblyName, this);
438 public ProjectUsingTaskParameterElement CreateUsingTaskParameterElement (string name, string output,
440 string parameterType)
442 return new ProjectUsingTaskParameterElement (name, output, required, parameterType, this);
445 public UsingTaskParameterGroupElement CreateUsingTaskParameterGroupElement ()
447 return new UsingTaskParameterGroupElement (this);
450 public ProjectWhenElement CreateWhenElement (string condition)
452 return new ProjectWhenElement (condition, this);
455 public static ProjectRootElement Open (string path)
457 return Open (path, ProjectCollection.GlobalProjectCollection);
460 public static ProjectRootElement Open (string path, ProjectCollection projectCollection)
462 var result = Create (path, projectCollection);
463 using (var reader = XmlReader.Create (path))
464 result.Load (reader);
473 public void Save (Encoding saveEncoding)
475 using (var writer = new StreamWriter (File.Create (FullPath), saveEncoding)) {
480 public void Save (string path)
482 Save (path, Encoding);
485 public void Save (TextWriter writer)
487 using (var xmlWriter = XmlWriter.Create (writer, new XmlWriterSettings { Indent = true,
488 NewLineChars = "\r\n" })) {
493 public void Save (string path, Encoding encoding)
499 public static ProjectRootElement TryOpen (string path)
501 return TryOpen (path, ProjectCollection.GlobalProjectCollection);
504 public static ProjectRootElement TryOpen (string path, ProjectCollection projectCollection)
506 // this should be non-null only if the project is already cached
507 // and caching is not yet implemented
511 internal override void Load (XmlReader reader)
515 } catch (XmlException ex) {
516 throw new InvalidProjectFileException (FullPath, ex.LineNumber, ex.LinePosition, 0, 0,
517 ex.Message, null, null, null);
521 internal override ProjectElement LoadChildElement (string name)
524 case "PropertyGroup":
525 var prop = CreatePropertyGroupElement ();
529 var item = CreateItemGroupElement ();
533 return AddImport (null);
535 return AddTarget (null);
536 case "ItemDefinitionGroup":
537 var def = CreateItemDefinitionGroupElement ();
541 return AddUsingTask (null, null, null);
543 var choose = CreateChooseElement ();
544 AppendChild (choose);
546 case "ProjectExtensions":
547 var ext = CreateProjectExtensionsElement ();
551 throw new InvalidProjectFileException (string.Format (
552 "Child \"{0}\" is not a known node type.", name));
556 internal override void LoadAttribute (string name, string value)
560 ToolsVersion = value;
562 case "DefaultTargets":
563 DefaultTargets = value;
565 case "InitialTargets":
566 InitialTargets = value;
569 base.LoadAttribute (name, value);
574 internal override void Save (XmlWriter writer)
576 writer.WriteStartElement (XmlName, "http://schemas.microsoft.com/developer/msbuild/2003");
578 writer.WriteEndElement ();
581 internal override void SaveValue (XmlWriter writer)
583 SaveAttribute (writer, "ToolsVersion", ToolsVersion);
584 SaveAttribute (writer, "DefaultTargets", DefaultTargets);
585 SaveAttribute (writer, "InitialTargets", InitialTargets);
586 base.SaveValue (writer);
589 internal override string XmlName {
590 get { return "Project"; }