Skip to content

Commit c78cd73

Browse files
committed
Refactor process starting and stdout and stderr reading
1 parent edc93df commit c78cd73

File tree

3 files changed

+61
-50
lines changed

3 files changed

+61
-50
lines changed

csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,12 @@ public class SystemBuildActions : IBuildActions
187187

188188
bool IBuildActions.FileExists(string file) => File.Exists(file);
189189

190-
private static ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? workingDirectory, IDictionary<string, string>? environment, bool redirectStandardOutput)
190+
private static ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? workingDirectory, IDictionary<string, string>? environment)
191191
{
192192
var pi = new ProcessStartInfo(exe, arguments)
193193
{
194194
UseShellExecute = false,
195-
RedirectStandardOutput = redirectStandardOutput
195+
RedirectStandardOutput = true
196196
};
197197
if (workingDirectory is not null)
198198
pi.WorkingDirectory = workingDirectory;
@@ -204,40 +204,22 @@ private static ProcessStartInfo GetProcessStartInfo(string exe, string arguments
204204

205205
int IBuildActions.RunProcess(string exe, string args, string? workingDirectory, System.Collections.Generic.IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
206206
{
207-
var pi = GetProcessStartInfo(exe, args, workingDirectory, env, true);
208-
using var p = new Process
209-
{
210-
StartInfo = pi
211-
};
212-
p.StartInfo.RedirectStandardError = true;
213-
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) => onOutput(e.Data));
214-
p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => onError(e.Data));
215-
216-
p.Start();
207+
var pi = GetProcessStartInfo(exe, args, workingDirectory, env);
208+
pi.RedirectStandardError = true;
217209

218-
p.BeginErrorReadLine();
219-
p.BeginOutputReadLine();
220-
221-
p.WaitForExit();
222-
return p.ExitCode;
210+
return pi.ReadOutput(out _, onOut: s => onOutput(s), onError: s => onError(s));
223211
}
224212

225213
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? environment)
226214
{
227-
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false);
228-
using var p = Process.Start(pi);
229-
if (p is null)
230-
{
231-
return -1;
232-
}
233-
p.WaitForExit();
234-
return p.ExitCode;
215+
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment);
216+
return pi.ReadOutput(out _, onOut: Console.WriteLine, onError: null);
235217
}
236218

237219
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? environment, out IList<string> stdOut)
238220
{
239-
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, true);
240-
return pi.ReadOutput(out stdOut, printToConsole: false);
221+
var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment);
222+
return pi.ReadOutput(out stdOut, onOut: null, onError: null);
241223
}
242224

243225
void IBuildActions.DirectoryDelete(string dir, bool recursive) => Directory.Delete(dir, recursive);

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetCliInvoker.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Diagnostics;
34
using Semmle.Util;
@@ -24,7 +25,8 @@ private ProcessStartInfo MakeDotnetStartInfo(string args)
2425
var startInfo = new ProcessStartInfo(Exec, args)
2526
{
2627
UseShellExecute = false,
27-
RedirectStandardOutput = true
28+
RedirectStandardOutput = true,
29+
RedirectStandardError = true
2830
};
2931
// Set the .NET CLI language to English to avoid localized output.
3032
startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"] = "en";
@@ -35,7 +37,16 @@ private bool RunCommandAux(string args, out IList<string> output)
3537
{
3638
progressMonitor.RunningProcess($"{Exec} {args}");
3739
var pi = MakeDotnetStartInfo(args);
38-
var exitCode = pi.ReadOutput(out output, true);
40+
var threadId = $"[{Environment.CurrentManagedThreadId:D3}]";
41+
void onOut(string s)
42+
{
43+
Console.Out.WriteLine($"{threadId} {s}");
44+
}
45+
void onError(string s)
46+
{
47+
Console.Error.WriteLine($"{threadId} {s}");
48+
}
49+
var exitCode = pi.ReadOutput(out output, onOut, onError);
3950
if (exitCode != 0)
4051
{
4152
progressMonitor.CommandFailed(Exec, args, exitCode);

csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,56 @@ public static class ProcessStartInfoExtensions
88
{
99
/// <summary>
1010
/// Runs this process, and returns the exit code, as well as the contents
11-
/// of stdout in <paramref name="stdout"/>. If <paramref name="printToConsole"/>
12-
/// is true, then stdout is printed to the console and each line is prefixed
13-
/// with the thread id.
11+
/// of stdout in <paramref name="stdout"/>.
1412
/// </summary>
15-
public static int ReadOutput(this ProcessStartInfo pi, out IList<string> stdout, bool printToConsole)
13+
public static int ReadOutput(this ProcessStartInfo pi, out IList<string> stdout, Action<string>? onOut, Action<string>? onError)
1614
{
17-
stdout = new List<string>();
18-
using var process = Process.Start(pi);
15+
var @out = new List<string>();
16+
using var process = new Process
17+
{
18+
StartInfo = pi
19+
};
1920

20-
if (process is null)
21+
if (process.StartInfo.RedirectStandardOutput && !pi.UseShellExecute)
2122
{
22-
return -1;
23-
}
23+
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
24+
{
25+
if (e.Data == null)
26+
{
27+
return;
28+
}
2429

25-
if (pi.RedirectStandardOutput && !pi.UseShellExecute)
30+
onOut?.Invoke(e.Data);
31+
@out.Add(e.Data);
32+
});
33+
}
34+
if (process.StartInfo.RedirectStandardError && !pi.UseShellExecute)
2635
{
27-
string? s;
28-
do
36+
process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
2937
{
30-
s = process.StandardOutput.ReadLine();
31-
if (s is not null)
38+
if (e.Data == null)
3239
{
33-
if (printToConsole)
34-
{
35-
Console.WriteLine($"[{Environment.CurrentManagedThreadId:D3}] {s}");
36-
}
37-
stdout.Add(s);
40+
return;
3841
}
39-
}
40-
while (s is not null);
42+
43+
onError?.Invoke(e.Data);
44+
});
4145
}
46+
47+
process.Start();
48+
49+
if (process.StartInfo.RedirectStandardError)
50+
{
51+
process.BeginErrorReadLine();
52+
}
53+
54+
if (process.StartInfo.RedirectStandardOutput)
55+
{
56+
process.BeginOutputReadLine();
57+
}
58+
4259
process.WaitForExit();
60+
stdout = @out;
4361
return process.ExitCode;
4462
}
4563
}

0 commit comments

Comments
 (0)