merge -r 53370:58178
[mono.git] / mcs / class / Microsoft.Build.Utilities / Microsoft.Build.Utilities / ToolTask.cs
1 //
2 // ToolTask.cs: Base class for command line tool tasks. 
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.Diagnostics;
32 using System.Collections.Specialized;
33 using System.IO;
34 using System.Resources;
35 using System.Text;
36 using System.Text.RegularExpressions;
37 using Microsoft.Build.Framework;
38 using Mono.XBuild.Utilities;
39
40 namespace Microsoft.Build.Utilities
41 {
42         public abstract class ToolTask : Task
43         {
44                 StringDictionary        environmentOverride;
45                 int                     timeout;
46                 string                  toolPath;
47                 Process                 process;
48                 
49                 static Regex            regex;
50                 
51                 protected ToolTask ()
52                         : this (null, null)
53                 {
54                 }
55
56                 protected ToolTask (ResourceManager taskResources)
57                         : this (taskResources, null)
58                 {
59                 }
60
61                 protected ToolTask (ResourceManager taskResources,
62                                    string helpKeywordPrefix)
63                 {
64                         this.TaskResources = taskResources;
65                         this.HelpKeywordPrefix = helpKeywordPrefix;
66                         this.toolPath = MonoLocationHelper.GetBinDir ();
67                 }
68
69                 static ToolTask ()
70                 {
71                         regex = new Regex (
72                                 @"^\s*"
73                                 + @"(((?<ORIGIN>(((\d+>)?[a-zA-Z]?:[^:]*)|([^:]*))):)"
74                                 + "|())"
75                                 + "(?<SUBCATEGORY>(()|([^:]*? )))"
76                                 + "(?<CATEGORY>(error|warning)) "
77                                 + "(?<CODE>[^:]*):"
78                                 + "(?<TEXT>.*)$",
79                                 RegexOptions.IgnoreCase);
80                 }
81
82                 protected virtual bool CallHostObjectToExecute ()
83                 {
84                         return true;
85                 }
86
87                 public override bool Execute ()
88                 {
89                         string arguments, toolFilename;
90                         
91                         arguments = String.Concat (GenerateCommandLineCommands (), " ", GenerateResponseFileCommands ());
92                         toolFilename = GenerateFullPathToTool (); 
93                         return RealExecute (toolFilename, arguments);
94                 }
95                 
96                 private bool RealExecute (string filename, string arguments)
97                 {
98                         string line;
99                 
100                         if (filename == null)
101                                 throw new ArgumentNullException ("filename");
102                         if (arguments == null)
103                                 throw new ArgumentNullException ("arguments");
104                         
105                         process = new Process ();
106                         process.StartInfo.Arguments = arguments;
107                         process.StartInfo.CreateNoWindow = true;
108                         process.StartInfo.FileName = filename;
109                         process.StartInfo.RedirectStandardError = true;
110                         process.StartInfo.RedirectStandardOutput = true;
111                         process.StartInfo.UseShellExecute = false;
112                         
113                         Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution started with arguments: {1}",
114                                 filename, arguments));
115                         
116                         process.Start ();
117                         process.WaitForExit ();
118                         
119                         while ((line = process.StandardError.ReadLine ()) != null) {
120                                 HandleError (line);
121                         }
122                         
123                         Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution finished.", filename));
124                         
125                         return !Log.HasLoggedErrors;
126                 }
127                 
128                 private void HandleError (string line)
129                 {
130                         string filename, origin, category, code, subcategory, text;
131                         int lineNumber, columnNumber, endLineNumber, endColumnNumber;
132                 
133                         Match m = regex.Match (line);
134                         origin = m.Groups [regex.GroupNumberFromName ("ORIGIN")].Value;
135                         category = m.Groups [regex.GroupNumberFromName ("CATEGORY")].Value;
136                         code = m.Groups [regex.GroupNumberFromName ("CODE")].Value;
137                         subcategory = m.Groups [regex.GroupNumberFromName ("SUBCATEGORY")].Value;
138                         text = m.Groups [regex.GroupNumberFromName ("TEXT")].Value;
139                         
140                         ParseOrigin (origin, out filename, out lineNumber, out columnNumber, out endLineNumber, out endColumnNumber);
141                         
142                         if (category == "warning") {
143                                 Log.LogWarning (subcategory, code, null, filename, lineNumber, columnNumber, endLineNumber,
144                                         endColumnNumber, text, null);
145                         } else if (category == "error") {
146                                 Log.LogError (subcategory, code, null, filename, lineNumber, columnNumber, endLineNumber,
147                                         endColumnNumber, text, null);
148                         }
149                 }
150                 
151                 private void ParseOrigin (string origin, out string filename,
152                                      out int lineNumber, out int columnNumber,
153                                      out int endLineNumber, out int endColumnNumber)
154                 {
155                         int lParen;
156                         string[] temp;
157                         string[] left, right;
158                         
159                         if (origin.IndexOf ('(') != -1 ) {
160                                 lParen = origin.IndexOf ('(');
161                                 filename = origin.Substring (0, lParen);
162                                 temp = origin.Substring (lParen + 1, origin.Length - lParen - 2).Split (',');
163                                 if (temp.Length == 1) {
164                                         left = temp [0].Split ('-');
165                                         if (left.Length == 1) {
166                                                 lineNumber = Int32.Parse (left [0]);
167                                                 columnNumber = 0;
168                                                 endLineNumber = 0;
169                                                 endColumnNumber = 0;
170                                         } else if (left.Length == 2) {
171                                                 lineNumber = Int32.Parse (left [0]);
172                                                 columnNumber = 0;
173                                                 endLineNumber = Int32.Parse (left [1]);
174                                                 endColumnNumber = 0;
175                                         } else
176                                                 throw new Exception ("Invalid line/column format.");
177                                 } else if (temp.Length == 2) {
178                                         right = temp [1].Split ('-');
179                                         lineNumber = Int32.Parse (temp [0]);
180                                         endLineNumber = 0;
181                                         if (right.Length == 1) {
182                                                 columnNumber = Int32.Parse (right [0]);
183                                                 endColumnNumber = 0;
184                                         } else if (right.Length == 2) {
185                                                 columnNumber = Int32.Parse (right [0]);
186                                                 endColumnNumber = Int32.Parse (right [0]);
187                                         } else
188                                                 throw new Exception ("Invalid line/column format.");
189                                 } else if (temp.Length == 4) {
190                                         lineNumber = Int32.Parse (temp [0]);
191                                         endLineNumber = Int32.Parse (temp [2]);
192                                         columnNumber = Int32.Parse (temp [1]);
193                                         endColumnNumber = Int32.Parse (temp [3]);
194                                 } else
195                                         throw new Exception ("Invalid line/column format.");
196                         } else {
197                                 filename = origin;
198                                 lineNumber = 0;
199                                 columnNumber = 0;
200                                 endLineNumber = 0;
201                                 endColumnNumber = 0;
202                         }
203                 }
204
205                 protected virtual string GenerateCommandLineCommands ()
206                 {
207                         return null;
208                 }
209
210                 protected abstract string GenerateFullPathToTool ();
211
212                 protected virtual string GenerateResponseFileCommands ()
213                 {
214                         return null;
215                 }
216
217                 protected virtual string GetResponseFileSwitch (string responseFilePath)
218                 {
219                         return String.Format ("@{0}", responseFilePath);
220                 }
221
222                 protected virtual bool HandleTaskExecutionErrors (int exitCode,
223                                                                  bool hasTaskLoggedErrors)
224                 {
225                         return true;
226                 }
227
228                 protected virtual bool InitializeHostObject (out bool appropriateHostObjectExists,
229                                                             out bool continueBuild)
230                 {
231                         appropriateHostObjectExists = (HostObject != null) ? true : false;
232                         continueBuild = true;
233                         return true;
234                 }
235
236                 protected virtual void LogToolCommand (string message)
237                 {
238                 }
239
240                 protected virtual bool SkipTaskExecution()
241                 {
242                         return false;
243                 }
244
245                 protected virtual bool ValidateParameters()
246                 {
247                         return true;
248                 }
249
250                 protected virtual StringDictionary EnvironmentOverride
251                 {
252                         get { return environmentOverride; }
253                 }
254
255                 protected virtual Encoding ResponseFileEncoding
256                 {
257                         get { return Encoding.UTF8; }
258                 }
259
260                 protected virtual Encoding StandardErrorEncoding
261                 {
262                         get { return Console.Error.Encoding; }
263                 }
264
265                 protected virtual Encoding StandardOutputEncoding
266                 {
267                         get { return Console.Out.Encoding; }
268                 }
269
270                 public int Timeout
271                 {
272                         get { return timeout; }
273                         set { timeout = value; }
274                 }
275
276                 protected abstract string ToolName
277                 {
278                         get;
279                 }
280
281                 public string ToolPath
282                 {
283                         get { return toolPath; }
284                         set { toolPath  = value; }
285                 }
286         }
287 }
288
289 #endif