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