New test.
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / BuildItem.cs
1 //
2 // BuildItem.cs:
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 #if NET_2_0
29
30 using System;
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.IO;
34 using System.Text;
35 using System.Xml;
36 using Microsoft.Build.Framework;
37 using Microsoft.Build.Utilities;
38 using Mono.XBuild.Utilities;
39
40 namespace Microsoft.Build.BuildEngine {
41         public class BuildItem {
42
43                 XmlElement      itemElement;
44                 string          finalItemSpec;
45                 bool            isImported;
46                 string          itemInclude;
47                 string          name;
48                 BuildItemGroup  parentItemGroup;
49                 string          recursiveDir;
50                 IDictionary     evaluatedMetadata;
51                 IDictionary     unevaluatedMetadata;
52
53                 private BuildItem ()
54                 {
55                 }
56                 
57                 public BuildItem (string itemName, ITaskItem taskItem)
58                 {
59                         this.name = itemName;
60                         this.finalItemSpec = taskItem.ItemSpec;
61                         this.itemInclude = Utilities.Escape (taskItem.ItemSpec);
62                         this.evaluatedMetadata = (Hashtable) taskItem.CloneCustomMetadata ();
63                         this.unevaluatedMetadata = (Hashtable) taskItem.CloneCustomMetadata ();
64                 }
65
66                 public BuildItem (string itemName, string itemInclude)
67                 {
68                         this.name = itemName;
69                         this.finalItemSpec = itemInclude;
70                         this.unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable ();
71                         this.evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable ();
72                 }
73                 
74                 internal BuildItem (XmlElement itemElement, BuildItemGroup parentItemGroup)
75                 {
76                         this.isImported = false;
77                         this.unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable ();
78                         this.evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable ();
79                         this.parentItemGroup = parentItemGroup;
80                         BindToXml (itemElement);
81                 }
82                 
83                 private BuildItem (BuildItem parent)
84                 {
85                         this.isImported = parent.isImported;
86                         this.name = parent.name;
87                         this.parentItemGroup = parent.parentItemGroup;
88                         this.unevaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (parent.unevaluatedMetadata);
89                         this.evaluatedMetadata = CollectionsUtil.CreateCaseInsensitiveHashtable (parent.evaluatedMetadata);
90                 }
91                 
92                 public void CopyCustomMetadataTo (BuildItem destinationItem)
93                 {
94                         foreach (DictionaryEntry de in unevaluatedMetadata)
95                                 destinationItem.SetMetadata ((string) de.Key, (string) de.Value);
96                 }
97                 
98                 [MonoTODO]
99                 public BuildItem Clone ()
100                 {
101                         return (BuildItem) this.MemberwiseClone ();
102                 }
103
104                 public string GetEvaluatedMetadata (string metadataName)
105                 {
106                         if (evaluatedMetadata.Contains (metadataName))
107                                 return (string) evaluatedMetadata [metadataName];
108                         else
109                                 return String.Empty;
110                 }
111
112                 public string GetMetadata (string metadataName)
113                 {
114                         if (ReservedNameUtils.IsReservedMetadataName (metadataName))
115                                 return ReservedNameUtils.GetReservedMetadata (FinalItemSpec, metadataName);
116                         else if (evaluatedMetadata.Contains (metadataName) == true)
117                                 return (string) evaluatedMetadata [metadataName];
118                         else
119                                 return String.Empty;
120                 }
121                 
122                 public bool HasMetadata (string metadataName)
123                 {
124                         return evaluatedMetadata.Contains (metadataName);
125                 }
126
127                 public void RemoveMetadata (string metadataName)
128                 {
129                         if (metadataName == null)
130                                 throw new ArgumentNullException ("metadataName");
131                         
132                         if (ReservedNameUtils.IsReservedMetadataName (metadataName))
133                                 throw new ArgumentException ("Can't remove reserved metadata.");
134                         
135                         if (evaluatedMetadata.Contains (metadataName))
136                                 evaluatedMetadata.Remove (metadataName);
137                         
138                         if (unevaluatedMetadata.Contains (metadataName))
139                                 unevaluatedMetadata.Remove (metadataName);
140                 }
141
142                 public void SetMetadata (string metadataName,
143                                          string metadataValue)
144                 {
145                         SetMetadata (metadataName, metadataValue, false);
146                 }
147                 
148                 // FIXME: don't use expression when we treat it as literal
149                 [MonoTODO]
150                 public void SetMetadata (string metadataName,
151                                          string metadataValue,
152                                          bool treatMetadataValueAsLiteral)
153                 {
154                         if (metadataName == null)
155                                 throw new ArgumentNullException ("metadataName");
156                         
157                         if (metadataValue == null)
158                                 throw new ArgumentNullException ("metadataValue");
159                         
160                         if (ReservedNameUtils.IsReservedMetadataName (metadataName))
161                                 throw new ArgumentException ("Can't modify reserved metadata.");
162                         
163                         RemoveMetadata (metadataName);
164                         
165                         unevaluatedMetadata.Add (metadataName, metadataValue);
166                                 
167                         if (parentItemGroup != null && treatMetadataValueAsLiteral == false) {  
168                                 OldExpression finalValue = new OldExpression (parentItemGroup.Project);
169                                 finalValue.ParseSource (metadataValue);
170                                 evaluatedMetadata.Add (metadataName, (string) finalValue.ConvertTo (typeof (string)));
171                         } else
172                                 evaluatedMetadata.Add (metadataName, metadataValue);
173                 }
174                 
175                 private void BindToXml (XmlElement xmlElement)
176                 {
177                         if (xmlElement == null)
178                                 throw new ArgumentNullException ("xmlElement");
179                         
180                         this.itemElement = xmlElement;
181                         this.name = xmlElement.Name;
182                         
183                         if (Include == String.Empty)
184                                 throw new InvalidProjectFileException ("Item must have Include attribute.");
185                         
186                         foreach (XmlElement xe in xmlElement.ChildNodes) {
187                                 this.SetMetadata (xe.Name, xe.InnerText);
188                         }
189                 }
190
191                 internal void Evaluate ()
192                 {
193                         DirectoryScanner directoryScanner;
194                         OldExpression includeExpr, excludeExpr;
195                         string includes, excludes;
196
197                         includeExpr = new OldExpression (parentItemGroup.Project);
198                         includeExpr.ParseSource (Include);
199                         excludeExpr = new OldExpression (parentItemGroup.Project);
200                         excludeExpr.ParseSource (Exclude);
201                         
202                         includes = (string) includeExpr.ConvertTo (typeof (string));
203                         excludes = (string) excludeExpr.ConvertTo (typeof (string));
204
205                         this.finalItemSpec = includes;
206                         
207                         directoryScanner = new DirectoryScanner ();
208                         
209                         directoryScanner.Includes = includes;
210                         directoryScanner.Excludes = excludes;
211                         if (parentItemGroup.Project.FullFileName != String.Empty) {
212                                 directoryScanner.BaseDirectory = new DirectoryInfo (Path.GetDirectoryName (parentItemGroup.Project.FullFileName));
213                         } else {
214                                 directoryScanner.BaseDirectory = new DirectoryInfo (Directory.GetCurrentDirectory ());
215                         }
216                         
217                         directoryScanner.Scan ();
218                         
219                         foreach (string matchedFile in directoryScanner.MatchedFilenames) {
220                                 AddEvaluatedItem (matchedFile);
221                         }
222                 }
223                 
224                 private void AddEvaluatedItem (string itemSpec)
225                 {
226                         Project project = this.parentItemGroup.Project;
227                         
228                         BuildItem bi = new BuildItem (this);
229                         bi.finalItemSpec = itemSpec;
230                         project.EvaluatedItems.AddItem (bi);
231                         if (project.EvaluatedItemsByName.Contains (bi.name) == false) {
232                                 BuildItemGroup big = new BuildItemGroup (null, project);
233                                 project.EvaluatedItemsByName.Add (bi.name, big);
234                                 big.AddItem (bi);
235                         } else {
236                                 ((BuildItemGroup) project.EvaluatedItemsByName [bi.name]).AddItem (bi);
237                         }
238                 }
239                 
240                 internal string ConvertToString (OldExpression transform)
241                 {
242                         return GetItemSpecFromTransform (transform);
243                 }
244                 
245                 internal ITaskItem ConvertToITaskItem (OldExpression transform)
246                 {
247                         TaskItem taskItem;
248                         taskItem = new TaskItem (GetItemSpecFromTransform (transform), evaluatedMetadata);
249                         return taskItem;
250                 }
251
252                 private string GetItemSpecFromTransform (OldExpression transform)
253                 {
254                         StringBuilder sb;
255                 
256                         if (transform == null)
257                                 return finalItemSpec;
258                         else {
259                                 sb = new StringBuilder ();
260                                 foreach (object o in transform.Collection) {
261                                         if (o is string) {
262                                                 sb.Append ((string)o);
263                                         } else if (o is PropertyReference) {
264                                                 sb.Append (((PropertyReference)o).ConvertToString ());
265                                         } else if (o is ItemReference) {
266                                                 sb.Append (((ItemReference)o).ConvertToString ());
267                                         } else if (o is MetadataReference) {
268                                                 sb.Append (GetMetadata (((MetadataReference)o).MetadataName));
269                                         }
270                                 }
271                                 return sb.ToString ();
272                         }
273                 }
274
275                 public string Condition {
276                         get {
277                                 if (FromXml)
278                                         return itemElement.GetAttribute ("Condition");
279                                 else
280                                         return String.Empty;
281                         }
282                         set {
283                                 if (FromXml)
284                                         itemElement.SetAttribute ("Condition", value);
285                         }
286                 }
287
288                 public string Exclude {
289                         get {
290                                 if (FromXml)
291                                         return itemElement.GetAttribute ("Exclude");
292                                 else
293                                         return String.Empty;
294                         }
295                         set {
296                                 if (FromXml)
297                                         itemElement.SetAttribute ("Exclude", value);
298                         }
299                 }
300
301                 public string FinalItemSpec {
302                         get { return finalItemSpec; }
303                 }
304
305                 public string Include {
306                         get {
307                                 if (FromXml)
308                                         return itemElement.GetAttribute ("Include");
309                                 else if (itemInclude != null)
310                                         return itemInclude;
311                                 else
312                                         return finalItemSpec;
313                         }
314                         set {
315                                 if (FromXml)
316                                         itemElement.SetAttribute ("Include", value);
317                         }
318                 }
319
320                 public bool IsImported {
321                         get { return isImported; }
322                 }
323
324                 public string Name {
325                         get { return name; }
326                         set { name = value; }
327                 }
328                 
329                 internal bool FromXml {
330                         get {
331                                 return itemElement != null;
332                         }
333                 }
334         }
335 }
336
337 #endif