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;
56 protected ToolTask (ResourceManager taskResources)
57 : this (taskResources, null)
61 protected ToolTask (ResourceManager taskResources,
62 string helpKeywordPrefix)
64 this.TaskResources = taskResources;
65 this.HelpKeywordPrefix = helpKeywordPrefix;
66 this.toolPath = MonoLocationHelper.GetBinDir ();
73 + @"(((?<ORIGIN>(((\d+>)?[a-zA-Z]?:[^:]*)|([^:]*))):)"
75 + "(?<SUBCATEGORY>(()|([^:]*? )))"
76 + "(?<CATEGORY>(error|warning)) "
79 RegexOptions.IgnoreCase);
82 protected virtual bool CallHostObjectToExecute ()
87 public override bool Execute ()
89 string arguments, toolFilename;
91 arguments = String.Concat (GenerateCommandLineCommands (), " ", GenerateResponseFileCommands ());
92 toolFilename = GenerateFullPathToTool ();
93 return RealExecute (toolFilename, arguments);
96 private bool RealExecute (string filename, string arguments)
100 if (filename == null)
101 throw new ArgumentNullException ("filename");
102 if (arguments == null)
103 throw new ArgumentNullException ("arguments");
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;
113 Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution started with arguments: {1}",
114 filename, arguments));
117 process.WaitForExit ();
119 while ((line = process.StandardError.ReadLine ()) != null) {
123 Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution finished.", filename));
125 return !Log.HasLoggedErrors;
128 private void HandleError (string line)
130 string filename, origin, category, code, subcategory, text;
131 int lineNumber, columnNumber, endLineNumber, endColumnNumber;
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;
140 ParseOrigin (origin, out filename, out lineNumber, out columnNumber, out endLineNumber, out endColumnNumber);
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);
151 private void ParseOrigin (string origin, out string filename,
152 out int lineNumber, out int columnNumber,
153 out int endLineNumber, out int endColumnNumber)
157 string[] left, right;
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]);
170 } else if (left.Length == 2) {
171 lineNumber = Int32.Parse (left [0]);
173 endLineNumber = Int32.Parse (left [1]);
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]);
181 if (right.Length == 1) {
182 columnNumber = Int32.Parse (right [0]);
184 } else if (right.Length == 2) {
185 columnNumber = Int32.Parse (right [0]);
186 endColumnNumber = Int32.Parse (right [0]);
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]);
195 throw new Exception ("Invalid line/column format.");
205 protected virtual string GenerateCommandLineCommands ()
210 protected abstract string GenerateFullPathToTool ();
212 protected virtual string GenerateResponseFileCommands ()
217 protected virtual string GetResponseFileSwitch (string responseFilePath)
219 return String.Format ("@{0}", responseFilePath);
222 protected virtual bool HandleTaskExecutionErrors (int exitCode,
223 bool hasTaskLoggedErrors)
228 protected virtual bool InitializeHostObject (out bool appropriateHostObjectExists,
229 out bool continueBuild)
231 appropriateHostObjectExists = (HostObject != null) ? true : false;
232 continueBuild = true;
236 protected virtual void LogToolCommand (string message)
240 protected virtual bool SkipTaskExecution()
245 protected virtual bool ValidateParameters()
250 protected virtual StringDictionary EnvironmentOverride
252 get { return environmentOverride; }
255 protected virtual Encoding ResponseFileEncoding
257 get { return Encoding.UTF8; }
260 protected virtual Encoding StandardErrorEncoding
262 get { return Console.Error.Encoding; }
265 protected virtual Encoding StandardOutputEncoding
267 get { return Console.Out.Encoding; }
272 get { return timeout; }
273 set { timeout = value; }
276 protected abstract string ToolName
281 public string ToolPath
283 get { return toolPath; }
284 set { toolPath = value; }