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
|
|
|
|
}
|
2020-04-03 23:23:13 +00:00
|
|
|
|
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;
|
2020-04-10 12:58:55 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public bool ThrowOnNonZeroExitCode { get; set; } = false;
|
2020-04-10 12:58:55 +00:00
|
|
|
|
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-07-15 21:03:59 +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();
|
2020-04-10 12:58:55 +00:00
|
|
|
|
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
|
|
|
}
|