ea4e29db8f88b721fa6647f99586194204e6d272
[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                                         xmlElement = (XmlElement) xmlNode;
112                                         
113                                         if (xmlElement.Name != "Output")
114                                                 throw new InvalidProjectFileException ("Only Output elements can be Task's child nodes.");
115                                         if (xmlElement.GetAttribute ("ItemName") != String.Empty && xmlElement.GetAttribute ("PropertyName") != String.Empty)
116                                                 throw new InvalidProjectFileException ("Only one of ItemName and ProperytyName attributes can be specified.");
117                                         if (xmlElement.GetAttribute ("TaskParameter") == String.Empty)
118                                                 throw new InvalidProjectFileException ("TaskParameter attribute must be specified.");
119                                                 
120                                         taskParameter = xmlElement.GetAttribute ("TaskParameter");
121                                         itemName = xmlElement.GetAttribute ("ItemName");
122                                         propertyName = xmlElement.GetAttribute ("PropertyName");
123                                         
124                                         propertyInfo = taskType.GetProperty (taskParameter);
125                                         if (propertyInfo == null)
126                                                 throw new Exception ("Could not get property info.");
127                                         if (propertyInfo.IsDefined (outputAttribute, false) == false)
128                                                 throw new Exception ("This is not output property.");
129                                         
130                                         o = propertyInfo.GetValue (task, null);
131                                         if (o == null)
132                                                 continue;
133                                         
134                                         if (itemName != String.Empty) {
135                                                 PublishItemGroup (propertyInfo, o, itemName);
136                                         } else {
137                                                 PublishProperty (propertyInfo, o, propertyName);
138                                         }
139                                 }
140                         }
141                 }
142                 
143                 private void InitializeParameter (PropertyInfo propertyInfo, object value)
144                 {
145                         propertyInfo.SetValue (task, value, null);
146                 }
147
148                 private void PublishItemGroup (PropertyInfo propertyInfo,
149                                                object o,
150                                                string itemName)
151                 {
152                         BuildItemGroup newItems = CollectItemGroup (propertyInfo, o, itemName);
153                         if (parentProject.EvaluatedItemsByName.Contains (itemName)) {
154                                 BuildItemGroup big = (BuildItemGroup) parentProject.EvaluatedItemsByName [itemName];
155                                 big.Clear ();
156                                 parentProject.EvaluatedItemsByName.Remove (itemName);
157                                 parentProject.EvaluatedItemsByName.Add (itemName, newItems);
158                         } else {
159                                 parentProject.EvaluatedItemsByName.Add (itemName, newItems);
160                         }
161                 }
162                 
163                 private void PublishProperty (PropertyInfo propertyInfo,
164                                               object o,
165                                               string propertyName)
166                 {
167                         BuildProperty bp = CollectProperty (propertyInfo, o, propertyName);
168                         parentProject.EvaluatedProperties.AddProperty (bp);
169                 }
170                 
171                 private BuildProperty CollectProperty (PropertyInfo propertyInfo, object o, string name)
172                 {
173                         string output = null;
174                         BuildProperty bp;
175                         
176                         if (propertyInfo == null)
177                                 throw new ArgumentNullException ("propertyInfo");
178                         if (o == null)
179                                 throw new ArgumentNullException ("o");
180                         if (name == null)
181                                 throw new ArgumentNullException ("name");
182                         
183                         if (propertyInfo.PropertyType == typeof (ITaskItem)) {
184                                 ITaskItem item = (ITaskItem) o;
185                                 bp = ChangeType.TransformToBuildProperty (name, item);
186                         } else if (propertyInfo.PropertyType == typeof (ITaskItem[])) {
187                                 ITaskItem[] items = (ITaskItem[]) o;
188                                 bp = ChangeType.TransformToBuildProperty (name, items);
189                         } else {
190                                 if (propertyInfo.PropertyType.IsArray == true) {
191                                         output = ChangeType.TransformToString ((object[])o, propertyInfo.PropertyType);
192                         } else {
193                                         output = ChangeType.TransformToString (o, propertyInfo.PropertyType);
194                                 }
195                                 bp = ChangeType.TransformToBuildProperty (name, output);
196                         }
197                         return bp;
198                 }
199                 
200                 private BuildItemGroup CollectItemGroup (PropertyInfo propertyInfo, object o, string name)
201                 {
202                         BuildItemGroup big;
203                         string temp;
204                         
205                         if (propertyInfo == null)
206                                 throw new ArgumentNullException ("propertyInfo");
207                         if (o == null)
208                                 throw new ArgumentNullException ("o");
209                         if (name == null)
210                                 throw new ArgumentNullException ("name");
211                                 
212                         if (propertyInfo.PropertyType == typeof (ITaskItem)) {
213                                 ITaskItem item = (ITaskItem) o;
214                                 big = ChangeType.TransformToBuildItemGroup (name, item);
215                         } else if (propertyInfo.PropertyType == typeof (ITaskItem[])) {
216                                 ITaskItem[] items = (ITaskItem[]) o;
217                                 big = ChangeType.TransformToBuildItemGroup (name, items);
218                         } else {
219                                 if (propertyInfo.PropertyType.IsArray == true) {
220                                         temp = ChangeType.TransformToString ((object[]) o, propertyInfo.PropertyType);
221                                 } else {
222                                         temp = ChangeType.TransformToString (o, propertyInfo.PropertyType);
223                                 }
224                                 big = ChangeType.TransformToBuildItemGroup (name, temp);
225                         }
226                         return big;     
227                 }
228                                 
229                 private object GetObjectFromString (string raw, Type type)
230                 {
231                         OldExpression e;
232                         object result;
233                         
234                         e = new OldExpression (parentProject);
235                         e.ParseSource (raw);
236                         
237                         if ((string) e.ConvertTo (typeof (string)) == String.Empty)
238                                 return null;
239                         
240                         result = e.ConvertTo (type);
241                         
242                         return result;
243                 }
244         }
245 }
246
247 #endif