Пример #1
0
        public static async Task <ProcessExecutionResult> RunAsync(this Process process, TextWriter log, TextWriter StdoutStream, TextWriter StderrStream, TimeSpan?timeout = null, Dictionary <string, string> environment_variables = null, CancellationToken?cancellation_token = null)
        {
            var stdout_completion = new TaskCompletionSource <bool> ();
            var stderr_completion = new TaskCompletionSource <bool> ();
            var exit_completion   = new TaskCompletionSource <bool> ();
            var rv = new ProcessExecutionResult();

            process.StartInfo.RedirectStandardError  = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.UseShellExecute        = false;

            if (environment_variables != null)
            {
                foreach (var kvp in environment_variables)
                {
                    process.StartInfo.EnvironmentVariables [kvp.Key] = kvp.Value;
                }
            }

            process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                if (e.Data != null)
                {
                    lock (StdoutStream) {
                        StdoutStream.WriteLine(e.Data);
                        StdoutStream.Flush();
                    }
                }
                else
                {
                    stdout_completion.SetResult(true);
                }
            };

            process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                if (e.Data != null)
                {
                    lock (StderrStream) {
                        StderrStream.WriteLine(e.Data);
                        StderrStream.Flush();
                    }
                }
                else
                {
                    stderr_completion.SetResult(true);
                }
            };


            log.WriteLine("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
            process.Start();

            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            cancellation_token?.Register(() => {
                if (!exit_completion.Task.IsCompleted)
                {
                    StderrStream.WriteLine($"Execution was cancelled.");
                    ProcessHelper.kill(process.Id, 9);
                }
            });

            new Thread(() =>
            {
                if (timeout.HasValue)
                {
                    if (!process.WaitForExit((int)timeout.Value.TotalMilliseconds))
                    {
                        ProcessHelper.kill(process.Id, 9);
                        process.WaitForExit((int)TimeSpan.FromSeconds(5).TotalMilliseconds);                            // Wait 5s for the kill to work
                        rv.TimedOut = true;
                        lock (StderrStream)
                            log.WriteLine($"Execution timed out after {timeout.Value.TotalSeconds} seconds and the process was killed.");
                    }
                }
                else
                {
                    process.WaitForExit();
                }
                exit_completion.TrySetResult(true);
            })
            {
                IsBackground = true,
            }.Start();

            await Task.WhenAll(stderr_completion.Task, stdout_completion.Task, exit_completion.Task);

            rv.ExitCode = process.ExitCode;
            return(rv);
        }
Пример #2
0
		public static async Task<ProcessExecutionResult> RunAsync (this Process process, Log log, TextWriter StdoutStream, TextWriter StderrStream, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null)
		{
			var stdout_completion = new TaskCompletionSource<bool> ();
			var stderr_completion = new TaskCompletionSource<bool> ();
			var rv = new ProcessExecutionResult ();

			process.StartInfo.RedirectStandardError = true;
			process.StartInfo.RedirectStandardOutput = true;
			process.StartInfo.UseShellExecute = false;

			if (environment_variables != null) {
				foreach (var kvp in environment_variables)
					process.StartInfo.EnvironmentVariables [kvp.Key] = kvp.Value;
			}

			process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
			{
				if (e.Data != null) {
					lock (StdoutStream) {
						StdoutStream.WriteLine (e.Data);
						StdoutStream.Flush ();
					}
				} else {
					stdout_completion.TrySetResult (true);
				}
			};

			process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
			{
				if (e.Data != null) {
					lock (StderrStream) {
						StderrStream.WriteLine (e.Data);
						StderrStream.Flush ();
					}
				} else {
					stderr_completion.TrySetResult (true);
				}
			};

			var sb = new StringBuilder ();
			if (process.StartInfo.EnvironmentVariables != null) {
				var currentEnvironment = Environment.GetEnvironmentVariables ().Cast<System.Collections.DictionaryEntry> ().ToDictionary ((v) => (string) v.Key, (v) => (string) v.Value, StringComparer.Ordinal);
				var processEnvironment = process.StartInfo.EnvironmentVariables.Cast<System.Collections.DictionaryEntry> ().ToDictionary ((v) => (string) v.Key, (v) => (string) v.Value, StringComparer.Ordinal);
				var allKeys = currentEnvironment.Keys.Union (processEnvironment.Keys).Distinct ();
				foreach (var key in allKeys) {
					string a = null, b = null;
					currentEnvironment.TryGetValue (key, out a);
					processEnvironment.TryGetValue (key, out b);
					if (a != b)
						sb.Append ($"{key}={StringUtils.Quote (b)} ");
				}
			}
			sb.Append ($"{StringUtils.Quote (process.StartInfo.FileName)} {process.StartInfo.Arguments}");
			log.WriteLine (sb);

			process.Start ();
			var pid = process.Id;

			process.BeginErrorReadLine ();
			process.BeginOutputReadLine ();

			cancellation_token?.Register (() => {
				if (!process.HasExited) {
					StderrStream.WriteLine ($"Execution was cancelled.");
					ProcessHelper.kill (process.Id, 9);
				}
			});

			if (timeout.HasValue) {
				if (!await process.WaitForExitAsync (timeout.Value)) {
					await process.KillTreeAsync (log, diagnostics ?? true);
					rv.TimedOut = true;
					lock (StderrStream)
						log.WriteLine ($"{pid} Execution timed out after {timeout.Value.TotalSeconds} seconds and the process was killed.");
				}
			}
			await process.WaitForExitAsync ();
			Task.WaitAll (new Task [] { stderr_completion.Task, stdout_completion.Task }, TimeSpan.FromSeconds (1));

			try {
				rv.ExitCode = process.ExitCode;
			} catch (Exception e) {
				rv.ExitCode = 12345678;
				log.WriteLine ($"Failed to get ExitCode: {e}");
			}
			return rv;
		}