wabbajack/Wabbajack.Common/ProcessHelper.cs

107 lines
3.0 KiB
C#
Raw Permalink Normal View History

2021-09-27 12:42:46 +00:00
using System;
2020-03-19 12:13:57 +00:00
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
2021-09-27 12:42:46 +00:00
using Wabbajack.Paths;
2020-03-19 12:13:57 +00:00
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Common;
public class ProcessHelper
2020-03-19 12:13:57 +00:00
{
2021-10-23 16:51:17 +00:00
public enum StreamType
2020-03-19 12:13:57 +00:00
{
2021-10-23 16:51:17 +00:00
Output,
Error
}
2021-10-23 16:51:17 +00:00
public readonly Subject<(StreamType Type, string Line)> Output = new Subject<(StreamType Type, string)>();
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public AbsolutePath Path { get; set; }
public IEnumerable<object> Arguments { get; set; } = Enumerable.Empty<object>();
2020-03-19 12:13:57 +00:00
2021-10-23 16:51:17 +00:00
public bool LogError { get; set; } = true;
2021-10-23 16:51:17 +00:00
public bool ThrowOnNonZeroExitCode { get; set; } = false;
2021-10-23 16:51:17 +00:00
public async Task<int> Start()
{
var args = Arguments.Select(arg =>
2020-03-19 12:13:57 +00:00
{
2021-10-23 16:51:17 +00:00
return arg switch
2020-03-19 12:13:57 +00:00
{
2021-10-23 16:51:17 +00:00
AbsolutePath abs => $"\"{abs}\"",
RelativePath rel => $"\"{rel}\"",
_ => arg.ToString()
2020-03-19 12:13:57 +00:00
};
2021-10-23 16:51:17 +00:00
});
var info = new ProcessStartInfo
{
FileName = Path.ToString(),
Arguments = string.Join(" ", args),
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
var finished = new TaskCompletionSource<int>();
var p = new Process
{
StartInfo = info,
EnableRaisingEvents = true
};
EventHandler Exited = (sender, args) => { finished.SetResult(p.ExitCode); };
p.Exited += Exited;
2020-03-19 12:13:57 +00:00
2021-10-23 16:51:17 +00:00
DataReceivedEventHandler OutputDataReceived = (sender, data) =>
{
if (string.IsNullOrEmpty(data.Data)) return;
Output.OnNext((StreamType.Output, data.Data));
};
p.OutputDataReceived += OutputDataReceived;
2020-03-19 12:13:57 +00:00
2021-10-23 16:51:17 +00:00
DataReceivedEventHandler ErrorEventHandler = (sender, data) =>
{
if (string.IsNullOrEmpty(data.Data)) return;
Output.OnNext((StreamType.Error, data.Data));
};
p.ErrorDataReceived += ErrorEventHandler;
2020-03-19 12:13:57 +00:00
2021-10-23 16:51:17 +00:00
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
2021-07-15 13:35:26 +00:00
2021-10-23 16:51:17 +00:00
ChildProcessTracker.AddProcess(p);
2020-03-19 12:13:57 +00:00
2021-10-23 16:51:17 +00:00
try
{
p.PriorityClass = ProcessPriorityClass.BelowNormal;
}
catch (Exception)
{
// ignored
}
2020-03-19 12:13:57 +00:00
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
var result = await finished.Task;
// Do this to make sure everything flushes
p.WaitForExit();
p.CancelErrorRead();
p.CancelOutputRead();
p.OutputDataReceived -= OutputDataReceived;
p.ErrorDataReceived -= ErrorEventHandler;
p.Exited -= Exited;
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
Output.OnCompleted();
2021-10-23 16:51:17 +00:00
if (result != 0 && ThrowOnNonZeroExitCode)
throw new Exception(
$"Error executing {Path} - Exit Code {result} - Check the log for more information - {string.Join(" ", args.Select(a => a!.ToString()))}");
return result;
2020-03-19 12:13:57 +00:00
}
2021-09-27 12:42:46 +00:00
}