2016-06-06 13:48:53 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace xharness
|
|
|
|
|
{
|
|
|
|
|
public static class Process_Extensions
|
|
|
|
|
{
|
|
|
|
|
public static async Task RunAsync (this Process process, LogFile log)
|
|
|
|
|
{
|
|
|
|
|
using (var stream = new StreamWriter (log.Path, false))
|
|
|
|
|
await RunAsync (process, stream, stream);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-10 21:56:48 +03:00
|
|
|
|
public static async Task RunAsync (this Process process, string outputFile, bool append, TimeSpan? timeout = null)
|
2016-06-06 13:48:53 +03:00
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory (Path.GetDirectoryName (outputFile));
|
2016-06-10 21:56:48 +03:00
|
|
|
|
using (var fs = new FileStream (outputFile, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.Read)) {
|
|
|
|
|
using (var stream = new StreamWriter (fs))
|
|
|
|
|
await RunAsync (process, stream, stream, timeout);
|
|
|
|
|
}
|
2016-06-06 13:48:53 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-10 21:56:48 +03:00
|
|
|
|
public static async Task RunAsync (this Process process, StreamWriter StdoutStream, StreamWriter StderrStream, TimeSpan? timeout = null)
|
2016-06-06 13:48:53 +03:00
|
|
|
|
{
|
|
|
|
|
var stdout_completion = new TaskCompletionSource<bool> ();
|
|
|
|
|
var stderr_completion = new TaskCompletionSource<bool> ();
|
|
|
|
|
var exit_completion = new TaskCompletionSource<bool> ();
|
|
|
|
|
|
|
|
|
|
process.StartInfo.RedirectStandardError = true;
|
|
|
|
|
process.StartInfo.RedirectStandardOutput = true;
|
|
|
|
|
process.StartInfo.UseShellExecute = false;
|
|
|
|
|
|
|
|
|
|
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
|
|
|
|
|
{
|
|
|
|
|
if (e.Data != null) {
|
2016-06-10 21:56:48 +03:00
|
|
|
|
lock (StdoutStream) {
|
|
|
|
|
StdoutStream.WriteLine (e.Data);
|
|
|
|
|
StdoutStream.Flush ();
|
|
|
|
|
}
|
2016-06-06 13:48:53 +03:00
|
|
|
|
} else {
|
|
|
|
|
stdout_completion.SetResult (true);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
|
|
|
|
|
{
|
|
|
|
|
if (e.Data != null) {
|
2016-06-10 21:56:48 +03:00
|
|
|
|
lock (StderrStream) {
|
2016-06-06 13:48:53 +03:00
|
|
|
|
StderrStream.WriteLine (e.Data);
|
2016-06-10 21:56:48 +03:00
|
|
|
|
StderrStream.Flush ();
|
|
|
|
|
}
|
2016-06-06 13:48:53 +03:00
|
|
|
|
} else {
|
|
|
|
|
stderr_completion.SetResult (true);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
process.Start ();
|
|
|
|
|
|
|
|
|
|
process.BeginErrorReadLine ();
|
|
|
|
|
process.BeginOutputReadLine ();
|
|
|
|
|
|
|
|
|
|
new Thread (() =>
|
|
|
|
|
{
|
2016-06-10 21:56:48 +03:00
|
|
|
|
if (timeout.HasValue) {
|
|
|
|
|
if (!process.WaitForExit ((int) timeout.Value.TotalMilliseconds)) {
|
|
|
|
|
process.Kill ();
|
|
|
|
|
process.WaitForExit ((int) 5); // Wait 5s for the kill to work, just
|
|
|
|
|
exit_completion.SetException (new TimeoutException { Timeout = timeout.Value });
|
|
|
|
|
} else {
|
|
|
|
|
exit_completion.SetResult (true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
process.WaitForExit ();
|
|
|
|
|
exit_completion.SetResult (true);
|
|
|
|
|
}
|
2016-06-06 13:48:53 +03:00
|
|
|
|
}) {
|
|
|
|
|
IsBackground = true,
|
|
|
|
|
}.Start ();
|
|
|
|
|
|
|
|
|
|
await Task.WhenAll (stderr_completion.Task, stdout_completion.Task, exit_completion.Task);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-10 21:56:48 +03:00
|
|
|
|
|
|
|
|
|
class TimeoutException : Exception
|
|
|
|
|
{
|
|
|
|
|
public TimeSpan Timeout;
|
|
|
|
|
}
|
2016-06-06 13:48:53 +03:00
|
|
|
|
}
|