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;
52 Func<string, bool> errorMatcher, warningMatcher;
56 ignoreExitCode = false;
59 protected internal override void AddCommandLineCommands (CommandLineBuilderExtension commandLine)
61 if (IsRunningOnWindows)
62 commandLine.AppendSwitch ("/q /c");
64 if (!String.IsNullOrEmpty (command)) {
65 scriptFile = Path.GetTempFileName ();
66 if (IsRunningOnWindows)
67 scriptFile = scriptFile + ".bat";
68 using (StreamWriter sw = new StreamWriter (scriptFile)) {
71 commandLine.AppendFileNameIfNotNull (scriptFile);
73 base.AddCommandLineCommands (commandLine);
76 protected override int ExecuteTool (string pathToTool,
77 string responseFileCommands,
78 string commandLineCommands)
81 errorMatcher = GetTryMatchRegexFunc (CustomErrorRegularExpression, true);
82 warningMatcher = GetTryMatchRegexFunc (CustomWarningRegularExpression, false);
83 return base.ExecuteTool (pathToTool, responseFileCommands, commandLineCommands);
85 if (scriptFile != null)
86 DeleteTempFile (scriptFile);
91 protected override string GenerateFullPathToTool ()
93 return IsRunningOnWindows ? "cmd.exe" : "sh";
96 protected override string GetWorkingDirectory ()
98 return workingDirectory;
101 protected override bool HandleTaskExecutionErrors ()
104 Log.LogError ("Command '{0}' exited with code: {1}.", Command, ExitCode);
106 return ExitCode == 0 || ignoreExitCode;
110 protected override void LogPathToTool (string toolName,
116 protected override void LogToolCommand (string message)
118 Log.LogMessage (MessageImportance.Normal, "Executing: " + command);
121 protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
123 if (IgnoreStandardErrorWarningFormat ||
124 (!errorMatcher (singleLine) && !warningMatcher (singleLine)))
125 Log.LogMessage (messageImportance, singleLine);
128 // @is_error_type - log as errors, else warnings
129 Func<string, bool> GetTryMatchRegexFunc (string regex_str, bool is_error_type)
133 return (singleLine) => {
134 if (String.IsNullOrEmpty (regex_str) || is_bad)
139 regex = new Regex (regex_str, RegexOptions.Compiled);
140 } catch (ArgumentException ae) {
141 Log.LogError ("The regular expression specified for '{0}' is invalid : {1}",
142 is_error_type ? "errors" : "warnings", ae.Message);
143 Log.LogMessage (MessageImportance.Low, "The regular expression specified for '{0}' is invalid : {1}",
144 is_error_type ? "errors" : "warnings", ae.ToString ());
150 if (!regex.Match (singleLine).Success)
154 Log.LogError (singleLine);
156 Log.LogWarning (singleLine);
162 protected override bool ValidateParameters ()
168 public string Command {
169 get { return command; }
172 if (Path.DirectorySeparatorChar == '/')
173 command = command.Replace ("\r\n", "\n");
177 public bool IgnoreExitCode {
178 get { return ignoreExitCode; }
179 set { ignoreExitCode = value; }
183 public ITaskItem[] Outputs {
184 get { return outputs; }
185 set { outputs = value; }
188 protected override Encoding StandardErrorEncoding {
189 get { return base.StandardErrorEncoding; }
192 protected override MessageImportance StandardErrorLoggingImportance {
193 get { return base.StandardErrorLoggingImportance; }
196 protected override Encoding StandardOutputEncoding {
197 get { return base.StandardOutputEncoding; }
200 protected override MessageImportance StandardOutputLoggingImportance {
201 get { return base.StandardOutputLoggingImportance; }
204 public bool IgnoreStandardErrorWarningFormat { get; set; }
206 public string CustomErrorRegularExpression { get; set; }
208 public string CustomWarningRegularExpression { get; set; }
212 public string StdOutEncoding {
213 get { return stdOutEncoding; }
214 set { stdOutEncoding = value; }
219 public string StdErrEncoding {
220 get { return stdErrEncoding; }
221 set { stdErrEncoding = value; }
225 protected override string ToolName {
226 get { return String.Empty; }
229 public string WorkingDirectory {
230 get { return workingDirectory; }
231 set { workingDirectory = value; }
234 static bool IsRunningOnWindows {
236 PlatformID pid = Environment.OSVersion.Platform;
237 return ((int) pid != 128 && (int) pid != 4 && (int) pid != 6);