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.
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Diagnostics;
38 using System.Text.RegularExpressions;
39 using System.Threading;
40 using Microsoft.Build.Framework;
41 using Microsoft.Build.Utilities;
43 namespace Microsoft.Build.Tasks {
44 public class Exec : ToolTaskExtension {
49 string stdErrEncoding;
50 string stdOutEncoding;
51 string workingDirectory;
55 Func<string, bool> errorMatcher, warningMatcher;
60 ignoreExitCode = false;
63 protected internal override void AddCommandLineCommands (CommandLineBuilderExtension commandLine)
65 if (IsRunningOnWindows)
66 commandLine.AppendSwitch ("/q /c");
68 if (!String.IsNullOrEmpty (command)) {
69 scriptFile = Path.GetTempFileName ();
70 if (IsRunningOnWindows)
71 scriptFile = scriptFile + ".bat";
72 using (StreamWriter sw = new StreamWriter (scriptFile)) {
75 commandLine.AppendFileNameIfNotNull (scriptFile);
77 base.AddCommandLineCommands (commandLine);
80 protected override int ExecuteTool (string pathToTool,
81 string responseFileCommands,
82 string commandLineCommands)
86 errorMatcher = GetTryMatchRegexFunc (CustomErrorRegularExpression, true);
87 warningMatcher = GetTryMatchRegexFunc (CustomWarningRegularExpression, false);
89 return base.ExecuteTool (pathToTool, responseFileCommands, commandLineCommands);
91 if (scriptFile != null)
92 DeleteTempFile (scriptFile);
97 protected override string GenerateFullPathToTool ()
99 return IsRunningOnWindows ? "cmd.exe" : "sh";
102 protected override string GetWorkingDirectory ()
104 return workingDirectory;
107 protected override bool HandleTaskExecutionErrors ()
110 Log.LogError ("Command '{0}' exited with code: {1}.", Command, ExitCode);
112 return ExitCode == 0 || ignoreExitCode;
116 protected override void LogPathToTool (string toolName,
122 protected override void LogToolCommand (string message)
124 Log.LogMessage (MessageImportance.Normal, "Executing: " + command);
127 protected override void LogEventsFromTextOutput (string singleLine, MessageImportance importance)
130 if (IgnoreStandardErrorWarningFormat ||
131 (!errorMatcher (singleLine) && !warningMatcher (singleLine)))
133 Log.LogMessage (importance, singleLine);
137 // @is_error_type - log as errors, else warnings
138 Func<string, bool> GetTryMatchRegexFunc (string regex_str, bool is_error_type)
142 return (singleLine) => {
143 if (String.IsNullOrEmpty (regex_str) || is_bad)
148 regex = new Regex (regex_str, RegexOptions.Compiled);
149 } catch (ArgumentException ae) {
150 Log.LogError ("The regular expression specified for '{0}' is invalid : {1}",
151 is_error_type ? "errors" : "warnings", ae.Message);
152 Log.LogMessage (MessageImportance.Low, "The regular expression specified for '{0}' is invalid : {1}",
153 is_error_type ? "errors" : "warnings", ae.ToString ());
159 if (!regex.Match (singleLine).Success)
163 Log.LogError (singleLine);
165 Log.LogWarning (singleLine);
172 protected override bool ValidateParameters ()
178 public string Command {
179 get { return command; }
182 if (Path.DirectorySeparatorChar == '/')
183 command = command.Replace ("\r\n", "\n");
187 public bool IgnoreExitCode {
188 get { return ignoreExitCode; }
189 set { ignoreExitCode = value; }
193 public ITaskItem[] Outputs {
194 get { return outputs; }
195 set { outputs = value; }
198 protected override Encoding StandardErrorEncoding {
199 get { return base.StandardErrorEncoding; }
202 protected override MessageImportance StandardErrorLoggingImportance {
203 get { return base.StandardErrorLoggingImportance; }
206 protected override Encoding StandardOutputEncoding {
207 get { return base.StandardOutputEncoding; }
210 protected override MessageImportance StandardOutputLoggingImportance {
211 get { return base.StandardOutputLoggingImportance; }
215 public bool IgnoreStandardErrorWarningFormat { get; set; }
217 public string CustomErrorRegularExpression { get; set; }
219 public string CustomWarningRegularExpression { get; set; }
224 public string StdOutEncoding {
225 get { return stdOutEncoding; }
226 set { stdOutEncoding = value; }
231 public string StdErrEncoding {
232 get { return stdErrEncoding; }
233 set { stdErrEncoding = value; }
237 protected override string ToolName {
238 get { return String.Empty; }
241 public string WorkingDirectory {
242 get { return workingDirectory; }
243 set { workingDirectory = value; }
246 static bool IsRunningOnWindows {
248 PlatformID pid = Environment.OSVersion.Platform;
249 return ((int) pid != 128 && (int) pid != 4 && (int) pid != 6);