2 // BuildPropertyGroup.cs: Represents a group of properties
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
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;
30 using System.Collections.Generic;
31 using System.Reflection;
35 namespace Microsoft.Build.BuildEngine {
36 public class BuildPropertyGroup : IEnumerable {
39 ImportedProject importedProject;
40 XmlElement propertyGroup;
41 GroupingCollection parentCollection;
42 Project parentProject;
43 List <BuildProperty> properties;
44 Dictionary <string, BuildProperty> propertiesByName;
47 public BuildPropertyGroup ()
48 : this (null, null, null, false)
52 internal BuildPropertyGroup (XmlElement xmlElement, Project project, ImportedProject importedProject, bool readOnly)
54 this.importedProject = importedProject;
55 this.parentCollection = null;
56 this.parentProject = project;
57 this.propertyGroup = xmlElement;
58 this.read_only = readOnly;
61 this.properties = new List <BuildProperty> ();
62 foreach (XmlNode xn in propertyGroup.ChildNodes) {
63 if (!(xn is XmlElement))
66 XmlElement xe = (XmlElement) xn;
67 BuildProperty bp = new BuildProperty (parentProject, xe);
71 this.propertiesByName = new Dictionary <string, BuildProperty> (StringComparer.OrdinalIgnoreCase);
73 DefinedInFileName = importedProject != null ? importedProject.FullFileName :
74 (project != null ? project.FullFileName : null);
77 public BuildProperty AddNewProperty (string propertyName,
80 return AddNewProperty (propertyName, propertyValue, false);
83 public BuildProperty AddNewProperty (string propertyName,
85 bool treatPropertyValueAsLiteral)
88 throw new InvalidOperationException ("This method is only valid for persisted property groups.");
90 if (treatPropertyValueAsLiteral)
91 propertyValue = Utilities.Escape (propertyValue);
93 XmlElement element = propertyGroup.OwnerDocument.CreateElement (propertyName, Project.XmlNamespace);
94 propertyGroup.AppendChild (element);
96 BuildProperty property = new BuildProperty (parentProject, element);
97 property.Value = propertyValue;
98 AddProperty (property);
100 parentProject.MarkProjectAsDirty ();
101 parentProject.NeedToReevaluate ();
106 internal void AddProperty (BuildProperty property)
109 properties.Add (property);
111 if (propertiesByName.ContainsKey (property.Name)) {
112 BuildProperty existing = propertiesByName [property.Name];
113 if (property.PropertyType <= existing.PropertyType) {
114 propertiesByName.Remove (property.Name);
115 propertiesByName.Add (property.Name, property);
118 propertiesByName.Add (property.Name, property);
125 propertyGroup.RemoveAll ();
126 properties = new List <BuildProperty> ();
128 propertiesByName = new Dictionary <string, BuildProperty> ();
132 public BuildPropertyGroup Clone (bool deepClone)
134 BuildPropertyGroup bpg = new BuildPropertyGroup (propertyGroup, parentProject, importedProject, read_only);
136 foreach (BuildProperty bp in properties) {
138 bpg.AddProperty (bp.Clone (true));
140 bpg.AddNewProperty (bp.Name, bp.FinalValue);
143 foreach (BuildProperty bp in propertiesByName.Values) {
145 bpg.AddProperty (bp.Clone (true));
147 bpg.AddNewProperty (bp.Name, bp.FinalValue);
154 public IEnumerator GetEnumerator ()
157 foreach (BuildProperty bp in properties)
160 foreach (KeyValuePair <string, BuildProperty> kvp in propertiesByName)
161 yield return kvp.Value;
164 public void RemoveProperty (BuildProperty propertyToRemove)
166 if (propertyToRemove == null)
167 throw new ArgumentNullException ("propertyToRemove");
170 if (!propertyToRemove.FromXml)
171 throw new InvalidOperationException ("The specified property does not belong to the current property group.");
173 propertyToRemove.XmlElement.ParentNode.RemoveChild (propertyToRemove.XmlElement);
174 properties.Remove (propertyToRemove);
176 propertiesByName.Remove (propertyToRemove.Name);
179 public void RemoveProperty (string propertyName)
182 foreach (BuildProperty bp in properties)
183 if (bp.Name == propertyName) {
188 propertiesByName.Remove (propertyName);
191 public void SetProperty (string propertyName,
192 string propertyValue)
194 SetProperty (propertyName, propertyValue, false);
197 public void SetProperty (string propertyName,
198 string propertyValue,
199 bool treatPropertyValueAsLiteral)
204 throw new InvalidOperationException (
205 "This method is only valid for virtual property groups, not <PropertyGroup> elements.");
207 if (treatPropertyValueAsLiteral)
208 propertyValue = Utilities.Escape (propertyValue);
210 if (propertiesByName.ContainsKey (propertyName))
211 propertiesByName.Remove (propertyName);
213 BuildProperty bp = new BuildProperty (propertyName, propertyValue);
214 if (Char.IsDigit (propertyName [0]))
215 throw new ArgumentException (String.Format (
216 "The name \"{0}\" contains an invalid character \"{1}\".", propertyName, propertyName [0]));
221 parentProject.NeedToReevaluate ();
224 internal void Evaluate ()
229 foreach (BuildProperty bp in properties)
230 if (ConditionParser.ParseAndEvaluate (bp.Condition, parentProject))
236 public string Condition {
240 return propertyGroup.GetAttribute ("Condition");
244 throw new InvalidOperationException (
245 "Cannot set a condition on an object not represented by an XML element in the project file.");
246 propertyGroup.SetAttribute ("Condition", value);
253 return properties.Count;
255 return propertiesByName.Count;
259 public bool IsImported {
261 return importedProject != null;
265 internal bool FromXml {
267 return propertyGroup != null;
273 return parentProject != null && propertyGroup == null;
277 public BuildProperty this [string propertyName] {
280 throw new InvalidOperationException ("Properties in persisted property groups cannot be accessed by name.");
282 if (propertiesByName.ContainsKey (propertyName))
283 return propertiesByName [propertyName];
288 propertiesByName [propertyName] = value;
292 internal string DefinedInFileName { get; private set; }
294 internal GroupingCollection GroupingCollection {
295 get { return parentCollection; }
296 set { parentCollection = value; }
299 internal XmlElement XmlElement {
300 get { return propertyGroup; }