-
Notifications
You must be signed in to change notification settings - Fork 12
/
ProcessExtensions.cs
140 lines (129 loc) · 5.29 KB
/
ProcessExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace YetiCommon
{
/// <summary>
/// Indicates that a process exited with a non-zero exit code.
/// </summary>
public class ProcessExecutionException : ProcessException
{
/// <summary>
/// The non-zero exit code which caused the process to exit.
/// </summary>
public int ExitCode { get; private set; }
/// <summary>
/// Optional process output captured during its execution.
/// </summary>
public List<string> OutputLines { get; private set; } = new List<string>();
/// <summary>
/// Optional process error output captured during its execution.
/// </summary>
public List<string> ErrorLines { get; private set; } = new List<string>();
public ProcessExecutionException(string message, int exitCode) : base(message)
{
ExitCode = exitCode;
}
public ProcessExecutionException(string message, int exitCode, List<string> outputLines,
List<string> errorLines) : base(message)
{
ExitCode = exitCode;
OutputLines = outputLines;
ErrorLines = errorLines;
}
}
public static class ProcessExtensions
{
/// <summary>
/// Attempts to start the process and returns a task that is completed when the process
/// exits with an exit code of zero (success).
/// </summary>
/// <exception cref="ProcessException">
/// Thrown if the process cannot be started, or if it does not exit within the timeout
/// period that was specified when the process was created.
/// </exception>
/// <exception cref="ProcessExecutionException">
/// Thrown if the process exits with a non-zero exit code.
/// </exception>
/// <remarks>
/// Output and error data handlers are guaranteed to be called before this task completes.
/// </remarks>
public static async Task RunToExitWithSuccessAsync(this IProcess process)
{
int code = await process.RunToExitAsync();
process.CheckExitCode(code);
}
/// <summary>
/// Checks exit code of the process. If it is non-zero it throws
/// the ProcessExecutionException.
/// </summary>
/// <exception cref="ProcessExecutionException">
/// Thrown if the process exits with a non-zero exit code.
/// </exception>
/// <param name="code">Exit code of the process.</param>
public static void CheckExitCode(this IProcess process, int code)
{
if (code != 0)
{
throw new ProcessExecutionException(
ErrorStrings.ProcessExitedWithError(process.ProcessName, code, null), code);
}
}
/// <summary>
/// Attempts to start the process and returns a task that is completed when the process
/// exits with an exit code of zero (success). Standard output and error output are
/// captured.
/// </summary>
/// <returns>A task evaluates to the output of the process.</returns>
/// <exception cref="ProcessException">
/// Thrown if the process cannot be started, or if it does not exit within the timeout
/// period that was specified when the process was created.
/// </exception>
/// <exception cref="ProcessExecutionException">
/// Thrown if the process exits with a non-zero exit code. Use the OutputLines and
/// ErrorLines properties to get the process output and error text, respectively.
/// </exception>
public static async Task<List<string>> RunToExitWithSuccessCapturingOutputAsync(
this IProcess process)
{
List<string> outputLines = new List<string>();
List<string> errorLines = new List<string>();
process.OutputDataReceived += (obj, args) =>
{
if (args.Text != null)
{
outputLines.Add(args.Text);
}
};
process.ErrorDataReceived += (obj, args) =>
{
if (args.Text != null)
{
errorLines.Add(args.Text);
}
};
var code = await process.RunToExitAsync();
if (code != 0)
{
throw new ProcessExecutionException(
ErrorStrings.ProcessExitedWithError(process.ProcessName, code, errorLines),
code, outputLines, errorLines);
}
return outputLines;
}
}
}