2007-01-10 Marek Sieradzki <marek.sieradzki@gmail.com>
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / TaskEngine.cs
1 //
2 // TaskEngine.cs: Class that executes each task.
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.Generic;
32 using System.Collections.Specialized;
33 using System.Reflection;
34 using System.Xml;
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
37
38 namespace Microsoft.Build.BuildEngine {
39         internal class TaskEngine {
40                 
41                 ITask           task;
42                 XmlElement      taskElement;
43                 Type            taskType;
44                 Project         parentProject;
45                 
46                 static Type     requiredAttribute;
47                 static Type     outputAttribute;
48                 
49                 static TaskEngine ()
50                 {
51                         requiredAttribute = typeof (Microsoft.Build.Framework.RequiredAttribute);
52                         outputAttribute = typeof (Microsoft.Build.Framework.OutputAttribute);
53                 }
54
55                 public TaskEngine (Project project)
56                 {
57                         parentProject = project;
58                 }
59                 
60                 public void Prepare (ITask task, XmlElement taskElement,
61                                      IDictionary <string, string> parameters, Type taskType)
62                 {
63                         Dictionary <string, object>     values;
64                         PropertyInfo    currentProperty;
65                         PropertyInfo[]  properties;
66                         object          value;
67                         
68                         this.task = task;
69                         this.taskElement = taskElement;
70                         this.taskType = taskType;
71                         values = new Dictionary <string, object> ();
72                         
73                         foreach (KeyValuePair <string, string> de in parameters) {
74                                 currentProperty = taskType.GetProperty (de.Key);
75                                 if (currentProperty == null)
76                                         throw new InvalidProjectFileException (String.Format ("Task does not have property \"{0}\" defined",
77                                                 de.Key));
78                                 
79                                 value = GetObjectFromString (de.Value, currentProperty.PropertyType);           
80                                 
81                                 if (value != null)
82                                         values.Add (de.Key, value);
83                         }
84                         
85                         properties = taskType.GetProperties ();
86                         foreach (PropertyInfo pi in properties) {
87                                 if (pi.IsDefined (requiredAttribute, false) && values.ContainsKey (pi.Name) == false)
88                                         throw new InvalidProjectFileException ("Required property not set.");
89                                 
90                                 if (values.ContainsKey (pi.Name))
91                                         InitializeParameter (pi, values [pi.Name]);
92                         }
93                 }
94                 
95                 public bool Execute ()
96                 {
97                         return task.Execute ();
98                 }
99                 
100                 public void PublishOutput ()
101                 {
102                         XmlElement      xmlElement;
103                         PropertyInfo    propertyInfo;
104                         string          propertyName;
105                         string          taskParameter;
106                         string          itemName;
107                         object          o;
108                 
109                         foreach (XmlNode xmlNode in taskElement.ChildNodes) {
110                                 if (!(xmlNode is XmlElement))
111                                         continue;
112                         
113                                 xmlElement = (XmlElement) xmlNode;
114                                 
115                                 if (xmlElement.Name != "Output")
116                                         throw new InvalidProjectFileException ("Only Output elements can be Task's child nodes.");
117                                 if (xmlElement.GetAttribute ("ItemName") != String.Empty && xmlElement.GetAttribute ("PropertyName") != String.Empty)
118                                         throw new InvalidProjectFileException ("Only one of ItemName and PropertyName attributes can be specified.");
119                                 if (xmlElement.GetAttribute ("TaskParameter") == String.Empty)
120                                         throw new InvalidProjectFileException ("TaskParameter attribute must be specified.");
121                                         
122                                 taskParameter = xmlElement.GetAttribute ("TaskParameter");
123                                 itemName = xmlElement.GetAttribute ("ItemName");
124                                 propertyName = xmlElement.GetAttribute ("PropertyName");
125                                 
126                                 propertyInfo = taskType.GetProperty (taskParameter);
127                                 if (propertyInfo == null)
128                                         throw new Exception ("Could not get property info.");
129                                 if (!propertyInfo.IsDefined (outputAttribute, false))
130                                         throw new Exception ("This is not output property.");
131                                 
132                                 o = propertyInfo.GetValue (task, null);
133                                 if (o == null)
134                                         continue;
135                                 
136                                 if (itemName != String.Empty) {
137                                         PublishItemGroup (propertyInfo, o, itemName);
138                                 } else {
139                                         PublishProperty (propertyInfo, o, propertyName);
140                                 }
141                         }
142                 }
143                 
144                 void InitializeParameter (PropertyInfo propertyInfo, object value)
145                 {
146                         propertyInfo.SetValue (task, value, null);
147                 }
148
149                 void PublishItemGroup (PropertyInfo propertyInfo,
150                                                object o,
151                                                string itemName)
152                 {
153                         BuildItemGroup newItems = CollectItemGroup (propertyInfo, o, itemName);
154                         
155                         if (parentProject.EvaluatedItemsByName.ContainsKey (itemName)) {
156                                 BuildItemGroup big = parentProject.EvaluatedItemsByName [itemName];
157                                 big.Clear ();
158                                 parentProject.EvaluatedItemsByName.Remove (itemName);
159                                 parentProject.EvaluatedItemsByName.Add (itemName, newItems);
160                         } else {
161                                 parentProject.EvaluatedItemsByName.Add (itemName, newItems);
162                         }
163                         foreach (BuildItem bi in newItems)
164                                 parentProject.EvaluatedItems.AddItem (bi);
165                 }
166                 
167                 void PublishProperty (PropertyInfo propertyInfo,
168                                               object o,
169                                               string propertyName)
170                 {
171                         BuildProperty bp = CollectProperty (propertyInfo, o, propertyName);
172                         parentProject.EvaluatedProperties.AddProperty (bp);
173                 }
174                 
175                 BuildProperty CollectProperty (PropertyInfo propertyInfo, object o, string name)
176                 {
177                         string output = null;
178                         BuildProperty bp;
179                         
180                         if (propertyInfo == null)
181                                 throw new ArgumentNullException ("propertyInfo");
182                         if (o == null)
183                                 throw new ArgumentNullException ("o");
184                         if (name == null)
185                                 throw new ArgumentNullException ("name");
186                         
187                         if (propertyInfo.PropertyType == typeof (ITaskItem)) {
188                                 ITaskItem item = (ITaskItem) o;
189                                 bp = ChangeType.TransformToBuildProperty (name, item);
190                         } else if (propertyInfo.PropertyType == typeof (ITaskItem[])) {
191                                 ITaskItem[] items = (ITaskItem[]) o;
192                                 bp = ChangeType.TransformToBuildProperty (name, items);
193                         } else {
194                                 if (propertyInfo.PropertyType.IsArray == true) {
195                                         output = ChangeType.TransformToString ((object[])o, propertyInfo.PropertyType);
196                         } else {
197                                         output = ChangeType.TransformToString (o, propertyInfo.PropertyType);
198                                 }
199                                 bp = ChangeType.TransformToBuildProperty (name, output);
200                         }
201                         return bp;
202                 }
203                 
204                 BuildItemGroup CollectItemGroup (PropertyInfo propertyInfo, object o, string name)
205                 {
206                         BuildItemGroup big;
207                         string temp;
208                         
209                         if (propertyInfo == null)
210                                 throw new ArgumentNullException ("propertyInfo");
211                         if (o == null)
212                                 throw new ArgumentNullException ("o");
213                         if (name == null)
214                                 throw new ArgumentNullException ("name");
215                                 
216                         if (propertyInfo.PropertyType == typeof (ITaskItem)) {
217                                 ITaskItem item = (ITaskItem) o;
218                                 big = ChangeType.TransformToBuildItemGroup (name, item);
219                         } else if (propertyInfo.PropertyType == typeof (ITaskItem[])) {
220                                 ITaskItem[] items = (ITaskItem[]) o;
221                                 big = ChangeType.TransformToBuildItemGroup (name, items);
222                         } else {
223                                 if (propertyInfo.PropertyType.IsArray == true) {
224                                         temp = ChangeType.TransformToString ((object[]) o, propertyInfo.PropertyType);
225                                 } else {
226                                         temp = ChangeType.TransformToString (o, propertyInfo.PropertyType);
227                                 }
228                                 big = ChangeType.TransformToBuildItemGroup (name, temp);
229                         }
230                         return big;     
231                 }
232                                 
233                 object GetObjectFromString (string raw, Type type)
234                 {
235                         Expression e;
236                         object result;
237                         
238                         e = new Expression ();
239                         e.Parse (raw);
240                         
241                         if ((string) e.ConvertTo (parentProject, typeof (string)) == String.Empty)
242                                 return null;
243                         
244                         result = e.ConvertTo (parentProject, type);
245                         
246                         return result;
247                 }
248         }
249 }
250
251 #endif