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