8fc30896db
Former-commit-id: c477e03582759447177c6d4bf412cd2355aad476
147 lines
4.2 KiB
C#
147 lines
4.2 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace ILLink.Tests
|
|
{
|
|
public class CommandRunner
|
|
{
|
|
protected readonly ITestOutputHelper outputHelper;
|
|
|
|
private string command;
|
|
private string args;
|
|
private string workingDir;
|
|
private string additionalPath;
|
|
private int timeout = Int32.MaxValue;
|
|
private string terminatingOutput;
|
|
|
|
public CommandRunner(string command, ITestOutputHelper outputHelper) {
|
|
this.command = command;
|
|
this.outputHelper = outputHelper;
|
|
}
|
|
|
|
public CommandRunner WithArguments(string args) {
|
|
this.args = args;
|
|
return this;
|
|
}
|
|
|
|
public CommandRunner WithWorkingDir(string workingDir) {
|
|
this.workingDir = workingDir;
|
|
return this;
|
|
}
|
|
|
|
public CommandRunner WithAdditionalPath(string additionalPath) {
|
|
this.additionalPath = additionalPath;
|
|
return this;
|
|
}
|
|
|
|
public CommandRunner WithTimeout(int timeout) {
|
|
this.timeout = timeout;
|
|
return this;
|
|
}
|
|
|
|
public CommandRunner WithTerminatingOutput(string terminatingOutput) {
|
|
this.terminatingOutput = terminatingOutput;
|
|
return this;
|
|
}
|
|
|
|
public int Run()
|
|
{
|
|
return Run(out string commandOutputUnused);
|
|
}
|
|
|
|
public int Run(out string commandOutput)
|
|
{
|
|
if (String.IsNullOrEmpty(command)) {
|
|
throw new Exception("No command was specified specified.");
|
|
}
|
|
if (outputHelper == null) {
|
|
throw new Exception("No output helper present.");
|
|
}
|
|
var psi = new ProcessStartInfo
|
|
{
|
|
FileName = command,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
};
|
|
outputHelper.WriteLine($"caller working directory: {Environment.CurrentDirectory}");
|
|
if (!String.IsNullOrEmpty(args)) {
|
|
psi.Arguments = args;
|
|
outputHelper.WriteLine($"{command} {args}");
|
|
} else {
|
|
outputHelper.WriteLine($"{command}");
|
|
}
|
|
if (!String.IsNullOrEmpty(workingDir)) {
|
|
outputHelper.WriteLine($"working directory: {workingDir}");
|
|
psi.WorkingDirectory = workingDir;
|
|
}
|
|
if (!String.IsNullOrEmpty(additionalPath)) {
|
|
string path = psi.Environment["PATH"];
|
|
psi.Environment["PATH"] = path + ";" + additionalPath;
|
|
}
|
|
var process = new Process();
|
|
process.StartInfo = psi;
|
|
|
|
// dotnet sets some environment variables that
|
|
// may cause problems in the child process.
|
|
psi.Environment.Remove("MSBuildExtensionsPath");
|
|
psi.Environment.Remove("MSBuildLoadMicrosoftTargetsReadOnly");
|
|
psi.Environment.Remove("MSBuildSDKsPath");
|
|
psi.Environment.Remove("VbcToolExe");
|
|
psi.Environment.Remove("CscToolExe");
|
|
psi.Environment.Remove("MSBUILD_EXE_PATH");
|
|
|
|
outputHelper.WriteLine("environment:");
|
|
foreach (var item in psi.Environment) {
|
|
outputHelper.WriteLine($"\t{item.Key}={item.Value}");
|
|
}
|
|
|
|
StringBuilder processOutput = new StringBuilder();
|
|
DataReceivedEventHandler handler = (sender, e) => {
|
|
processOutput.Append(e.Data);
|
|
processOutput.AppendLine();
|
|
};
|
|
StringBuilder processError = new StringBuilder();
|
|
DataReceivedEventHandler ehandler = (sender, e) => {
|
|
processError.Append(e.Data);
|
|
processError.AppendLine();
|
|
};
|
|
process.OutputDataReceived += handler;
|
|
process.ErrorDataReceived += ehandler;
|
|
|
|
// terminate process if output contains specified string
|
|
if (!String.IsNullOrEmpty(terminatingOutput)) {
|
|
DataReceivedEventHandler terminatingOutputHandler = (sender, e) => {
|
|
if (!String.IsNullOrEmpty(e.Data) && e.Data.Contains(terminatingOutput)) {
|
|
process.Kill();
|
|
}
|
|
};
|
|
process.OutputDataReceived += terminatingOutputHandler;
|
|
}
|
|
|
|
// start the process
|
|
process.Start();
|
|
process.BeginOutputReadLine();
|
|
process.BeginErrorReadLine();
|
|
if (!process.WaitForExit(timeout)) {
|
|
outputHelper.WriteLine($"killing process after {timeout} ms");
|
|
process.Kill();
|
|
}
|
|
// WaitForExit with timeout doesn't guarantee
|
|
// that the async output handlers have been
|
|
// called, so WaitForExit needs to be called
|
|
// afterwards.
|
|
process.WaitForExit();
|
|
string processOutputStr = processOutput.ToString();
|
|
string processErrorStr = processError.ToString();
|
|
outputHelper.WriteLine(processOutputStr);
|
|
outputHelper.WriteLine(processErrorStr);
|
|
commandOutput = processOutputStr;
|
|
return process.ExitCode;
|
|
}
|
|
}
|
|
}
|