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