Merge remote-tracking branch 'upstream/master'
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / BuildTask.cs
1 //
2 // BuildTask.cs: Represents a Task element in a project.
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 // 
7 // (C) 2006 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 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.Reflection;
33 using System.Xml;
34 using Microsoft.Build.Framework;
35 using Microsoft.Build.Utilities;
36
37 namespace Microsoft.Build.BuildEngine {
38         public class BuildTask : IBuildTask {
39         
40                 ITaskHost               hostObject;
41                 Target                  parentTarget;
42                 XmlElement              taskElement;
43                 TaskLoggingHelper       task_logger;
44         
45                 internal BuildTask (XmlElement taskElement, Target parentTarget)
46                 {
47                         if (taskElement == null)
48                                 throw new ArgumentNullException ("taskElement");
49                         if (parentTarget == null)
50                                 throw new ArgumentNullException ("parentTarget");
51
52                         this.taskElement =  taskElement;
53                         this.parentTarget = parentTarget;
54                 }
55                 
56                 [MonoTODO]
57                 public void AddOutputItem (string taskParameter,
58                                            string itemName)
59                 {
60                         XmlElement element = parentTarget.Project.XmlDocument.CreateElement ("Output", Project.XmlNamespace);
61                         taskElement.AppendChild (element);
62                         
63                         if (taskParameter != null)
64                                 element.SetAttribute ("TaskParameter", taskParameter);
65                         if (itemName != null)
66                                 element.SetAttribute ("ItemName", itemName);
67                 }
68                 
69                 [MonoTODO]
70                 public void AddOutputProperty (string taskParameter,
71                                                string propertyName)
72                 {
73                         XmlElement element = parentTarget.Project.XmlDocument.CreateElement ("Output", Project.XmlNamespace);
74                         taskElement.AppendChild (element);
75                         
76                         if (taskParameter != null)
77                                 element.SetAttribute ("TaskParameter", taskParameter);
78                         if (propertyName != null)
79                                 element.SetAttribute ("PropertyName", propertyName);
80                 }
81                 
82                 [MonoTODO]
83                 public bool Execute ()
84                 {
85                         bool            result = false;
86                         TaskEngine      taskEngine;
87
88                         LogTaskStarted ();
89                         ITask task = null;
90
91                         try {
92                                 try {
93                                         task = InitializeTask ();
94                                 } catch (Exception e) {
95                                         LogError ("Error initializing task {0}: {1}", taskElement.LocalName, e.Message);
96                                         LogMessage (MessageImportance.Low, "Error initializing task {0}: {1}",
97                                                         taskElement.LocalName, e.ToString ());
98                                         return false;
99                                 }
100
101                                 try {
102                                         taskEngine = new TaskEngine (parentTarget.Project);
103                                         taskEngine.Prepare (task, this.taskElement, GetParameters (), this.Type);
104                                         result = taskEngine.Execute ();
105                                         if (result)
106                                                 taskEngine.PublishOutput ();
107                                 } catch (Exception e) {
108                                         task_logger.LogError ("Error executing task {0}: {1}", taskElement.LocalName, e.Message);
109                                         task_logger.LogMessage (MessageImportance.Low,
110                                                         "Error executing task {0}: {1}", taskElement.LocalName, e.ToString ());
111                                         result = false;
112                                 }
113                         } finally {
114                                 LogTaskFinished (result);
115                         }
116
117                         return result;
118                 }
119
120
121                 public string[] GetParameterNames ()
122                 {
123                         List <string> tempNames = new List <string> ();
124                         
125                         foreach (XmlAttribute xmlAttribute in taskElement.Attributes) {
126                                 if (xmlAttribute.Name == "Condition" || xmlAttribute.Name == "ContinueOnError")
127                                         continue;
128                                 tempNames.Add (xmlAttribute.Name);
129                         }
130
131                         return tempNames.ToArray ();
132                 }
133                 
134                 public string GetParameterValue (string attributeName)
135                 {
136                         if (attributeName == "Condition")
137                                 throw new ArgumentException ("Condition attribute cannot be accessed using this method.");
138                         if (attributeName == "ContinueOnError")
139                                 throw new ArgumentException ("ContinueOnError attribute cannot be accessed using this method.");
140
141                         return taskElement.GetAttribute (attributeName);
142                 }
143                 
144                 public void SetParameterValue (string parameterName,
145                                                string parameterValue)
146                 {
147                         SetParameterValue (parameterName, parameterValue, false);
148                 }
149                 
150                 public void SetParameterValue (string parameterName,
151                                                string parameterValue,
152                                                bool treatParameterValueAsLiteral)
153                 {
154                         if (treatParameterValueAsLiteral)
155                                 taskElement.SetAttribute (parameterName, Utilities.Escape (parameterValue));
156                         else
157                                 taskElement.SetAttribute (parameterName, parameterValue);
158                 }
159
160                 void LogTaskStarted ()
161                 {
162                         TaskStartedEventArgs tsea = new TaskStartedEventArgs ("Task started.", null,
163                                         parentTarget.Project.FullFileName,
164                                         parentTarget.TargetFile, taskElement.Name);
165                         parentTarget.Project.ParentEngine.EventSource.FireTaskStarted (this, tsea);
166                 }
167                 
168                 void LogTaskFinished (bool succeeded)
169                 {
170                         TaskFinishedEventArgs tfea = new TaskFinishedEventArgs ("Task finished.", null,
171                                         parentTarget.Project.FullFileName,
172                                         parentTarget.TargetFile, taskElement.Name, succeeded);
173                         parentTarget.Project.ParentEngine.EventSource.FireTaskFinished (this, tfea);
174                 }
175
176                 void LogError (string message,
177                                      params object[] messageArgs)
178                 {
179                         parentTarget.Project.ParentEngine.LogError (message, messageArgs);
180                 }
181                 
182                 void LogMessage (MessageImportance importance,
183                                         string message,
184                                         params object[] messageArgs)
185                 {
186                         parentTarget.Project.ParentEngine.LogMessage (importance, message, messageArgs);
187                 }
188
189                 ITask InitializeTask ()
190                 {
191                         ITask task;
192                         
193                         try {
194                                 task = (ITask)Activator.CreateInstance (this.Type);
195                         } catch (InvalidCastException) {
196                                 LogMessage (MessageImportance.Low, "InvalidCastException, ITask: {0} Task type: {1}",
197                                                 typeof (ITask).AssemblyQualifiedName, this.Type.AssemblyQualifiedName);
198                                 throw;
199                         }
200                         parentTarget.Project.ParentEngine.LogMessage (
201                                         MessageImportance.Low,
202                                         "Using task {0} from {1}", Name, this.Type.AssemblyQualifiedName);
203
204                         task.BuildEngine = new BuildEngine (parentTarget.Project.ParentEngine, parentTarget.Project,
205                                                 parentTarget.TargetFile, 0, 0, ContinueOnError);
206                         task_logger = new TaskLoggingHelper (task);
207                         
208                         return task;
209                 }
210                 
211                 IDictionary <string, string> GetParameters ()
212                 {
213                         Dictionary <string, string> parameters = new Dictionary <string, string> ();
214                         
215                         string[] parameterNames = GetParameterNames ();
216                         
217                         foreach (string s in parameterNames)
218                                 parameters.Add (s, GetParameterValue (s));
219                         
220                         return parameters;
221                 }
222                 
223                 public string Condition {
224                         get {
225                                 return taskElement.GetAttribute ("Condition");
226                         }
227                         set {
228                                 taskElement.SetAttribute ("Condition", value);
229                         }
230                 }
231
232                 [MonoTODO]
233                 public bool ContinueOnError {
234                         get {
235                                 string str = taskElement.GetAttribute ("ContinueOnError");
236                                 if (str == String.Empty)
237                                         return false;
238                                 else {
239                                         Expression exp = new Expression ();
240                                         exp.Parse (str, ParseOptions.AllowItemsNoMetadataAndSplit);
241                                         return (bool) exp.ConvertTo (parentTarget.Project, typeof (bool),
242                                                         ExpressionOptions.ExpandItemRefs);
243                                 }
244                         }
245                         set {
246                                 taskElement.SetAttribute ("ContinueOnError", value.ToString ());
247                         }
248                 }
249                 
250                 [MonoTODO]
251                 public ITaskHost HostObject {
252                         get { return hostObject; }
253                         set { hostObject = value; }
254                 }
255                 
256                 public string Name {
257                         get { return taskElement.Name; }
258                 }
259                 
260                 internal Target ParentTarget {
261                         get { return parentTarget; }
262                         set { parentTarget = value; }
263                 }
264                 
265                 internal XmlElement TaskElement {
266                         get { return taskElement; }
267                         set { taskElement = value; }
268                 }
269
270                 [MonoTODO]
271                 public Type Type {
272                         get { return parentTarget.Project.TaskDatabase.GetTypeFromClassName (Name); }
273                 }
274
275                 public IEnumerable<string> GetAttributes ()
276                 {
277                         foreach (XmlAttribute attrib in TaskElement.Attributes)
278                                 yield return attrib.Value;
279                 
280                         foreach (XmlNode xn in TaskElement.ChildNodes) {
281                                 XmlElement xe = xn as XmlElement;
282                                 if (xe == null)
283                                         continue;
284                         
285                                 //FIXME: error on any other child
286                                 if (String.Compare (xe.LocalName, "Output", StringComparison.Ordinal) == 0) {
287                                         foreach (XmlAttribute attrib in xe.Attributes)
288                                                 yield return attrib.Value;
289                                 }
290                         }
291                 }
292
293         }
294 }