2 // Exec.cs: Task that executes commands.
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
6 // Ankit Jain (jankit@novell.com)
8 // (C) 2005 Marek Sieradzki
9 // Copyright 2009 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Diagnostics;
36 using System.Text.RegularExpressions;
37 using System.Threading;
38 using Microsoft.Build.Framework;
39 using Microsoft.Build.Utilities;
41 namespace Microsoft.Build.Tasks {
42 public class Exec : ToolTaskExtension {
47 string stdErrEncoding;
48 string stdOutEncoding;
49 string workingDirectory;
53 Func<string, bool> errorMatcher, warningMatcher;
58 ignoreExitCode = false;
61 protected internal override void AddCommandLineCommands (CommandLineBuilderExtension commandLine)
63 if (IsRunningOnWindows)
64 commandLine.AppendSwitch ("/q /c");
66 if (!String.IsNullOrEmpty (command)) {
67 scriptFile = Path.GetTempFileName ();
68 if (IsRunningOnWindows)
69 scriptFile = scriptFile + ".bat";
70 using (StreamWriter sw = new StreamWriter (scriptFile)) {
73 commandLine.AppendFileNameIfNotNull (scriptFile);
75 base.AddCommandLineCommands (commandLine);
78 protected override int ExecuteTool (string pathToTool,
79 string responseFileCommands,
80 string commandLineCommands)
84 errorMatcher = GetTryMatchRegexFunc (CustomErrorRegularExpression, true);
85 warningMatcher = GetTryMatchRegexFunc (CustomWarningRegularExpression, false);
87 return base.ExecuteTool (pathToTool, responseFileCommands, commandLineCommands);
89 if (scriptFile != null)
90 DeleteTempFile (scriptFile);
95 protected override string GenerateFullPathToTool ()
97 return IsRunningOnWindows ? "cmd.exe" : "sh";
100 protected override string GetWorkingDirectory ()
102 return workingDirectory;
105 protected override bool HandleTaskExecutionErrors ()
108 Log.LogError ("Command '{0}' exited with code: {1}.", Command, ExitCode);
110 return ExitCode == 0 || ignoreExitCode;
114 protected override void LogPathToTool (string toolName,
120 protected override void LogToolCommand (string message)
122 Log.LogMessage (MessageImportance.Normal, "Executing: " + command);
125 protected override void LogEventsFromTextOutput (string singleLine, MessageImportance importance)
128 if (IgnoreStandardErrorWarningFormat ||
129 (!errorMatcher (singleLine) && !warningMatcher (singleLine)))
131 Log.LogMessage (importance, singleLine);
135 // @is_error_type - log as errors, else warnings
136 Func<string, bool> GetTryMatchRegexFunc (string regex_str, bool is_error_type)
140 return (singleLine) => {
141 if (String.IsNullOrEmpty (regex_str) || is_bad)
146 regex = new Regex (regex_str, RegexOptions.Compiled);
147 } catch (ArgumentException ae) {
148 Log.LogError ("The regular expression specified for '{0}' is invalid : {1}",
149 is_error_type ? "errors" : "warnings", ae.Message);
150 Log.LogMessage (MessageImportance.Low, "The regular expression specified for '{0}' is invalid : {1}",
151 is_error_type ? "errors" : "warnings", ae.ToString ());
157 if (!regex.Match (singleLine).Success)
161 Log.LogError (singleLine);
163 Log.LogWarning (singleLine);
170 protected override bool ValidateParameters ()
176 public string Command {
177 get { return command; }
180 if (Path.DirectorySeparatorChar == '/')
181 command = command.Replace ("\r\n", "\n");
185 public bool IgnoreExitCode {
186 get { return ignoreExitCode; }
187 set { ignoreExitCode = value; }
191 public ITaskItem[] Outputs {
192 get { return outputs; }
193 set { outputs = value; }
196 protected override Encoding StandardErrorEncoding {
197 get { return base.StandardErrorEncoding; }
200 protected override MessageImportance StandardErrorLoggingImportance {
201 get { return base.StandardErrorLoggingImportance; }
204 protected override Encoding StandardOutputEncoding {
205 get { return base.StandardOutputEncoding; }
208 protected override MessageImportance StandardOutputLoggingImportance {
209 get { return base.StandardOutputLoggingImportance; }
213 public bool IgnoreStandardErrorWarningFormat { get; set; }
215 public string CustomErrorRegularExpression { get; set; }
217 public string CustomWarningRegularExpression { get; set; }
222 public string StdOutEncoding {
223 get { return stdOutEncoding; }
224 set { stdOutEncoding = value; }
229 public string StdErrEncoding {
230 get { return stdErrEncoding; }
231 set { stdErrEncoding = value; }
235 protected override string ToolName {
236 get { return String.Empty; }
239 public string WorkingDirectory {
240 get { return workingDirectory; }
241 set { workingDirectory = value; }
244 static bool IsRunningOnWindows {
246 PlatformID pid = Environment.OSVersion.Platform;
247 return ((int) pid != 128 && (int) pid != 4 && (int) pid != 6);