2 // ToolTask.cs: Base class for command line tool tasks.
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
31 using System.Diagnostics;
32 using System.Collections.Specialized;
34 using System.Resources;
36 using System.Text.RegularExpressions;
37 using Microsoft.Build.Framework;
38 using Mono.XBuild.Utilities;
40 namespace Microsoft.Build.Utilities
42 public abstract class ToolTask : Task
44 StringDictionary environmentOverride;
49 MessageImportance standardErrorLoggingImportance;
50 MessageImportance standardOutputLoggingImportance;
57 this.standardErrorLoggingImportance = MessageImportance.High;
58 this.standardOutputLoggingImportance = MessageImportance.Normal;
61 protected ToolTask (ResourceManager taskResources)
62 : this (taskResources, null)
66 protected ToolTask (ResourceManager taskResources,
67 string helpKeywordPrefix)
69 this.TaskResources = taskResources;
70 this.HelpKeywordPrefix = helpKeywordPrefix;
71 this.toolPath = MonoLocationHelper.GetBinDir ();
78 + @"(((?<ORIGIN>(((\d+>)?[a-zA-Z]?:[^:]*)|([^:]*))):)"
80 + "(?<SUBCATEGORY>(()|([^:]*? )))"
81 + "(?<CATEGORY>(error|warning)) "
84 RegexOptions.IgnoreCase);
87 protected virtual bool CallHostObjectToExecute ()
92 protected virtual int ExecuteTool (string pathToTool,
93 string responseFileCommands,
94 string commandLineCommands)
99 arguments = String.Concat (commandLineCommands, " ", responseFileCommands);
101 success = RealExecute (pathToTool, arguments);
109 public override bool Execute ()
113 result = ExecuteTool (GenerateFullPathToTool (), GenerateResponseFileCommands (),
114 GenerateCommandLineCommands ());
122 protected virtual string GetWorkingDirectory ()
127 private bool RealExecute (string filename, string arguments)
131 if (filename == null)
132 throw new ArgumentNullException ("filename");
133 if (arguments == null)
134 throw new ArgumentNullException ("arguments");
136 process = new Process ();
137 process.StartInfo.Arguments = arguments;
138 process.StartInfo.CreateNoWindow = true;
139 process.StartInfo.FileName = filename;
140 process.StartInfo.RedirectStandardError = true;
141 process.StartInfo.RedirectStandardOutput = true;
142 process.StartInfo.UseShellExecute = false;
144 Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution started with arguments: {1}",
145 filename, arguments));
148 process.WaitForExit ();
150 while ((line = process.StandardError.ReadLine ()) != null) {
151 LogEventsFromTextOutput (line, MessageImportance.Normal);
154 Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution finished.", filename));
156 return !Log.HasLoggedErrors;
160 // FIXME: use importance
162 protected virtual void LogEventsFromTextOutput (string singleLine,
163 MessageImportance importance)
165 string filename, origin, category, code, subcategory, text;
166 int lineNumber, columnNumber, endLineNumber, endColumnNumber;
168 Match m = regex.Match (singleLine);
169 origin = m.Groups [regex.GroupNumberFromName ("ORIGIN")].Value;
170 category = m.Groups [regex.GroupNumberFromName ("CATEGORY")].Value;
171 code = m.Groups [regex.GroupNumberFromName ("CODE")].Value;
172 subcategory = m.Groups [regex.GroupNumberFromName ("SUBCATEGORY")].Value;
173 text = m.Groups [regex.GroupNumberFromName ("TEXT")].Value;
175 ParseOrigin (origin, out filename, out lineNumber, out columnNumber, out endLineNumber, out endColumnNumber);
177 if (category == "warning") {
178 Log.LogWarning (subcategory, code, null, filename, lineNumber, columnNumber, endLineNumber,
179 endColumnNumber, text, null);
180 } else if (category == "error") {
181 Log.LogError (subcategory, code, null, filename, lineNumber, columnNumber, endLineNumber,
182 endColumnNumber, text, null);
186 private void ParseOrigin (string origin, out string filename,
187 out int lineNumber, out int columnNumber,
188 out int endLineNumber, out int endColumnNumber)
192 string[] left, right;
194 if (origin.IndexOf ('(') != -1 ) {
195 lParen = origin.IndexOf ('(');
196 filename = origin.Substring (0, lParen);
197 temp = origin.Substring (lParen + 1, origin.Length - lParen - 2).Split (',');
198 if (temp.Length == 1) {
199 left = temp [0].Split ('-');
200 if (left.Length == 1) {
201 lineNumber = Int32.Parse (left [0]);
205 } else if (left.Length == 2) {
206 lineNumber = Int32.Parse (left [0]);
208 endLineNumber = Int32.Parse (left [1]);
211 throw new Exception ("Invalid line/column format.");
212 } else if (temp.Length == 2) {
213 right = temp [1].Split ('-');
214 lineNumber = Int32.Parse (temp [0]);
216 if (right.Length == 1) {
217 columnNumber = Int32.Parse (right [0]);
219 } else if (right.Length == 2) {
220 columnNumber = Int32.Parse (right [0]);
221 endColumnNumber = Int32.Parse (right [0]);
223 throw new Exception ("Invalid line/column format.");
224 } else if (temp.Length == 4) {
225 lineNumber = Int32.Parse (temp [0]);
226 endLineNumber = Int32.Parse (temp [2]);
227 columnNumber = Int32.Parse (temp [1]);
228 endColumnNumber = Int32.Parse (temp [3]);
230 throw new Exception ("Invalid line/column format.");
240 protected virtual string GenerateCommandLineCommands ()
245 protected abstract string GenerateFullPathToTool ();
247 protected virtual string GenerateResponseFileCommands ()
252 protected virtual string GetResponseFileSwitch (string responseFilePath)
254 return String.Format ("@{0}", responseFilePath);
258 protected virtual bool HandleTaskExecutionErrors ()
263 protected virtual HostObjectInitializationStatus InitializeHostObject ()
265 return HostObjectInitializationStatus.NoActionReturnSuccess;
269 protected virtual void LogToolCommand (string message)
274 protected virtual void LogPathToTool (string toolName,
279 protected virtual bool SkipTaskExecution()
284 protected virtual bool ValidateParameters()
289 protected virtual StringDictionary EnvironmentOverride
291 get { return environmentOverride; }
296 public int ExitCode {
297 get { return exitCode; }
300 protected virtual Encoding ResponseFileEncoding
302 get { return Encoding.UTF8; }
305 protected virtual Encoding StandardErrorEncoding
307 get { return Console.Error.Encoding; }
310 protected virtual MessageImportance StandardErrorLoggingImportance {
311 get { return standardErrorLoggingImportance; }
314 protected virtual Encoding StandardOutputEncoding
316 get { return Console.Out.Encoding; }
319 protected virtual MessageImportance StandardOutputLoggingImportance {
320 get { return standardOutputLoggingImportance; }
323 public virtual int Timeout
325 get { return timeout; }
326 set { timeout = value; }
329 protected abstract string ToolName
334 public string ToolPath
336 get { return toolPath; }
337 set { toolPath = value; }