Merge remote-tracking branch 'joncham/sgen-msvc2'
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / BuildItemGroup.cs
1 //
2 // BuildItemGroup.cs: Represents a group of build items.
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 // 
7 // (C) 2005 Marek Sieradzki
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 using System;
29 using System.Reflection;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Xml;
33 using Microsoft.Build.Framework;
34 using Microsoft.Build.Utilities;
35
36 namespace Microsoft.Build.BuildEngine {
37         public class BuildItemGroup : IEnumerable {
38         
39                 List <BuildItem>        buildItems;
40                 ImportedProject         importedProject;
41                 XmlElement              itemGroupElement;
42                 GroupingCollection      parentCollection;
43                 Project                 parentProject;
44                 bool                    read_only;
45                 bool evaluated;
46
47                 public BuildItemGroup ()
48                         : this (null, null, null, false)
49                 {
50                 }
51
52                 internal BuildItemGroup (Project project)
53                         : this (null, project, null, false)
54                 {
55                 }
56
57                 internal BuildItemGroup (XmlElement xmlElement, Project project, ImportedProject importedProject, bool readOnly)
58                 {
59                         this.buildItems = new List <BuildItem> ();
60                         this.importedProject = importedProject;
61                         this.itemGroupElement = xmlElement;
62                         this.parentProject = project;
63                         this.read_only = readOnly;
64                         
65                         if (!FromXml)
66                                 return;
67
68                         foreach (XmlNode xn in xmlElement.ChildNodes) {
69                                 if (!(xn is XmlElement))
70                                         continue;
71                                         
72                                 XmlElement xe = (XmlElement) xn;
73                                 BuildItem bi = new BuildItem (xe, this);
74                                 buildItems.Add (bi);
75                                 project.LastItemGroupContaining [bi.Name] = this;
76                         }
77
78                         DefinedInFileName = importedProject != null ? importedProject.FullFileName :
79                                                 project != null ? project.FullFileName : null;
80                 }
81
82                 public BuildItem AddNewItem (string itemName,
83                                              string itemInclude)
84                 {
85                         return AddNewItem (itemName, itemInclude, false);
86                 }
87                 
88                 [MonoTODO]
89                 public BuildItem AddNewItem (string itemName,
90                                              string itemInclude,
91                                              bool treatItemIncludeAsLiteral)
92                 {
93                         BuildItem item;
94
95                         if (treatItemIncludeAsLiteral)
96                                 itemInclude = Utilities.Escape (itemInclude);
97
98                         if (FromXml) {
99                                 XmlElement element = itemGroupElement.OwnerDocument.CreateElement (itemName, Project.XmlNamespace);
100                                 itemGroupElement.AppendChild (element);
101                                 element.SetAttribute ("Include", itemInclude);
102                                 item = new BuildItem (element, this);
103                         } else {
104                                 item = new BuildItem (itemName, itemInclude);
105                                 item.ParentItemGroup = this;
106                         }
107
108                         item.Evaluate (null, true);
109
110                         if (!read_only)
111                                 buildItems.Add (item);
112
113                         if (parentProject != null) {
114                                 parentProject.MarkProjectAsDirty ();
115                                 parentProject.NeedToReevaluate ();
116                         }
117
118                         return item;
119                 }
120                 
121                 public void Clear ()
122                 {
123                         if (FromXml)
124                                 itemGroupElement.RemoveAll ();
125                         
126                         buildItems = new List <BuildItem> ();
127
128                         if (parentProject != null) {
129                                 parentProject.MarkProjectAsDirty ();
130                                 parentProject.NeedToReevaluate ();
131                         }
132                 }
133
134                 [MonoTODO]
135                 public BuildItemGroup Clone (bool deepClone)
136                 {
137                         if (deepClone) {
138                                 if (FromXml)
139                                         throw new NotImplementedException ();
140                                 else
141                                         throw new NotImplementedException ();
142                         } else {
143                                 if (FromXml)
144                                         throw new InvalidOperationException ("A shallow clone of this object cannot be created.");
145                                 else
146                                         throw new NotImplementedException ();
147                         }
148                 }
149
150                 public IEnumerator GetEnumerator ()
151                 {
152                         return buildItems.GetEnumerator ();
153                 }
154
155                 public void RemoveItem (BuildItem itemToRemove)
156                 {
157                         if (itemToRemove == null)
158                                 return;
159
160                         itemToRemove.Detach ();
161
162                         buildItems.Remove (itemToRemove);
163                 }
164
165                 public void RemoveItemAt (int index)
166                 {
167                         BuildItem item = buildItems [index];
168
169                         RemoveItem (item);
170                 }
171
172                 public BuildItem[] ToArray ()
173                 {
174                         return buildItems.ToArray ();
175                 }
176
177                 internal void AddItem (BuildItem buildItem)
178                 {
179                         buildItems.Add (buildItem);
180                 }
181
182                 internal void AddItem (string name, ITaskItem taskItem)
183                 {
184                         BuildItem buildItem;
185                         buildItem = new BuildItem (name, taskItem);
186                         buildItem.ParentItemGroup = this;
187                         buildItems.Add (buildItem);
188                 }
189
190                 // In eval phase, any ref'ed item would've already been expanded
191                 // or it doesnt exist, so dont expand again
192                 // In non-eval, items have _already_ been expanded, so dont expand again
193                 // So, ignore @options
194                 internal string ConvertToString (Expression transform,
195                                                  Expression separator, ExpressionOptions options)
196                 {
197                         string separatorString;
198                         
199                         // Item refs are not expanded for separator or transform
200                         if (separator == null)
201                                 separatorString = ";";
202                         else
203                                 separatorString = (string) separator.ConvertTo (parentProject, typeof (string),
204                                                                 ExpressionOptions.DoNotExpandItemRefs);
205                 
206                         string[] items = new string [buildItems.Count];
207                         int i = 0;
208                         foreach (BuildItem bi in  buildItems)
209                                 items [i++] = bi.ConvertToString (transform, ExpressionOptions.DoNotExpandItemRefs);
210                         return String.Join (separatorString, items);
211                 }
212
213                 // In eval phase, any ref'ed item would've already been expanded
214                 // or it doesnt exist, so dont expand again
215                 // In non-eval, items have _already_ been expanded, so dont expand again
216                 // So, ignore @options
217                 internal ITaskItem[] ConvertToITaskItemArray (Expression transform, Expression separator, ExpressionOptions options)
218                 {
219                         if (separator != null)
220                                 // separator present, so return as a single "join'ed" string
221                                 return new ITaskItem [] {
222                                         new TaskItem (ConvertToString (transform, separator, options))
223                                 };
224
225                         ITaskItem[] array = new ITaskItem [buildItems.Count];
226                         int i = 0;
227                         foreach (BuildItem item in buildItems)
228                                 array [i++] = item.ConvertToITaskItem (transform, ExpressionOptions.DoNotExpandItemRefs);
229                         return array;
230                 }
231
232                 internal void Detach ()
233                 {
234                         if (!FromXml)
235                                 throw new InvalidOperationException ();
236
237                         itemGroupElement.ParentNode.RemoveChild (itemGroupElement);
238                 }
239
240                 internal void Evaluate ()
241                 {
242                         if (evaluated)
243                                 return;
244                         foreach (BuildItem bi in buildItems) {
245                                 if (bi.Condition == String.Empty)
246                                         bi.Evaluate (parentProject, true);
247                                 else {
248                                         ConditionExpression ce = ConditionParser.ParseCondition (bi.Condition);
249                                         bi.Evaluate (parentProject, ce.BoolEvaluate (parentProject));
250                                 }
251                         }
252                         evaluated = true;
253                 }               
254
255                 internal void ReplaceWith (BuildItem item, List <BuildItem> list)
256                 {
257                         int index = buildItems.IndexOf (item);
258                         buildItems.RemoveAt (index);
259                         buildItems.InsertRange (index, list);
260                 }
261                 
262                 public string Condition {
263                         get {
264                                 if (FromXml)
265                                         return itemGroupElement.GetAttribute ("Condition");
266                                 else
267                                         return String.Empty;
268                         }
269                         set {
270                                 if (FromXml)
271                                         itemGroupElement.SetAttribute ("Condition", value);
272                                 else
273                                         throw new InvalidOperationException ("Cannot set a condition on an object not represented by an XML element in the project file.");
274                         }
275                 }
276
277                 public int Count {
278                         get { return buildItems.Count; }
279                 }
280
281                 public bool IsImported {
282                         get { return importedProject != null; }
283                 }
284
285                 
286                 [MonoTODO]
287                 public BuildItem this [int index] {
288                         get {
289                                 return buildItems [index];
290                         }
291                 }
292                 
293                 internal GroupingCollection GroupingCollection {
294                         get { return parentCollection; }
295                         set { parentCollection = value; }
296                 }
297                 
298                 internal Project ParentProject {
299                         get { return parentProject; }
300                         set {
301                                 if (parentProject != null)
302                                         throw new InvalidOperationException ("parentProject is already set");
303                                 parentProject = value;
304                         }
305                 }
306
307                 internal string DefinedInFileName { get; private set; }
308
309                 internal bool FromXml {
310                         get {
311                                 return itemGroupElement != null;
312                         }
313                 }
314
315                 internal XmlElement XmlElement {
316                         get {
317                                 return itemGroupElement;
318                         }       
319                 }
320         }
321 }