public static async Task <EasyExecResult> ExecAsync(string cmdName, string?arguments = null, string?currentDirectory = null, ExecFlags flags = ExecFlags.Default | ExecFlags.EasyInputOutputMode, int easyOutputMaxSize = Consts.Numbers.DefaultLargeBufferSize, string?easyInputStr = null, int?timeout = null, CancellationToken cancel = default, bool debug = false, bool throwOnErrorExitCode = true, string printTag = "", Func <string, Task <bool> >?easyOneLineRecvCallbackAsync = null, Func <ReadOnlyMemory <byte>, ReadOnlyMemory <byte>, Task <bool> >?easyRealtimeRecvBufCallbackAsync = null, int easyRealtimeRecvBufCallbackDelayTickMsecs = 0, StrDictionary <string>?additionalEnvVars = null) { if (timeout <= 0) { timeout = Timeout.Infinite; } ExecOptions opt = new ExecOptions(cmdName, arguments, currentDirectory, flags, easyOutputMaxSize, easyInputStr, printTag, easyOneLineRecvCallbackAsync, easyRealtimeRecvBufCallbackAsync, easyRealtimeRecvBufCallbackDelayTickMsecs, additionalEnvVars); if (debug) { Dbg.WriteLine($"ExecAsync: --- Starting process \"{cmdName}{(arguments._IsFilled() ? " " : "")}{arguments}\" ---"); } EasyExecResult result; try { using ExecInstance exec = new ExecInstance(opt); try { await exec.WaitForExitAsync(timeout._NormalizeTimeout(CoresConfig.Timeouts.DefaultEasyExecTimeout), cancel); } finally { await exec.CancelAsync(); } result = new EasyExecResult(exec); } catch (Exception ex) { Dbg.WriteLine($"Error on starting process \"{cmdName}{(arguments._IsFilled() ? " " : "")}{arguments}\". Exception: {ex.Message}"); throw; } if (debug) { Dbg.WriteLine($"ExecAsync: The result of process \"{cmdName}{(arguments._IsFilled() ? " " : "")}{arguments}\": " + result.ToString(Str.GetCrlfStr(), false)); } if (throwOnErrorExitCode) { result.ThrowExceptionIfError(); } return(result); }
public static async Task <EasyExecResult> ExecBashAsync(string command, string?currentDirectory = null, ExecFlags flags = ExecFlags.Default | ExecFlags.EasyInputOutputMode, int easyOutputMaxSize = Consts.Numbers.DefaultLargeBufferSize, string?easyInputStr = null, int?timeout = null, CancellationToken cancel = default, bool debug = false, bool throwOnErrorExitCode = true) { if (timeout <= 0) { timeout = Timeout.Infinite; } List <string> args = new List <string>(); args.Add("-c"); args.Add(command); ExecOptions opt = new ExecOptions(Consts.LinuxCommands.Bash, args, currentDirectory, flags, easyOutputMaxSize, easyInputStr); if (debug) { Dbg.WriteLine($"ExecBashAsync: --- Starting bash command \"{command}\" ---"); } EasyExecResult result; try { using ExecInstance exec = new ExecInstance(opt); try { await exec.WaitForExitAsync(timeout._NormalizeTimeout(CoresConfig.Timeouts.DefaultEasyExecTimeout), cancel); } finally { exec.Cancel(); } result = new EasyExecResult(exec); } catch (Exception ex) { Dbg.WriteLine($"Error on bash process \"{command}\". Exception: {ex.Message}"); throw; } if (debug) { Dbg.WriteLine($"ExecAsync: The result of bash \"{command}\": " + result.ToString(Str.GetCrlfStr(), false)); } if (throwOnErrorExitCode) { result.ThrowExceptionIfError(); } return(result); }
public static async Task <EasyExecResult> ExecAsync(string fileName, string?arguments = null, string?currentDirectory = null, ExecFlags flags = ExecFlags.Default | ExecFlags.EasyInputOutputMode, int easyOutputMaxSize = Consts.Numbers.DefaultLargeBufferSize, string?easyInputStr = null, int?timeout = null, CancellationToken cancel = default, bool debug = false, bool throwOnErrorExitCode = true) { if (timeout <= 0) { timeout = Timeout.Infinite; } ExecOptions opt = new ExecOptions(fileName, arguments, currentDirectory, flags, easyOutputMaxSize, easyInputStr); if (debug) { Dbg.WriteLine($"ExecAsync: --- Starting process \"{fileName}{(arguments._IsFilled() ? " " : "")}{arguments}\" ---"); } EasyExecResult result; try { using ExecInstance exec = new ExecInstance(opt); try { await exec.WaitForExitAsync(timeout._NormalizeTimeout(CoresConfig.Timeouts.DefaultEasyExecTimeout), cancel); } finally { exec.Cancel(); } result = new EasyExecResult(exec); } catch (Exception ex) { Dbg.WriteLine($"Error on starting process \"{fileName}{(arguments._IsFilled() ? " " : "")}{arguments}\". Exception: {ex.Message}"); throw; } if (debug) { Dbg.WriteLine($"ExecAsync: The result of process \"{fileName}{(arguments._IsFilled() ? " " : "")}{arguments}\": " + result.ToString(Str.GetCrlfStr(), false)); } if (throwOnErrorExitCode) { result.ThrowExceptionIfError(); } return(result); }
public ExecInstance(ExecOptions options) { try { this.InputEncoding = Console.OutputEncoding; this.OutputEncoding = this.ErrorEncoding = Console.InputEncoding; this.Options = options._NullCheck(); ProcessStartInfo info = new ProcessStartInfo() { FileName = options.FileName, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, CreateNoWindow = true, WorkingDirectory = options.CurrentDirectory._NullIfEmpty() !, }; if (this.Options.AdditionalEnvVars != null) { foreach (var kv in this.Options.AdditionalEnvVars) { if (kv.Key._IsFilled() && kv.Value._IsFilled()) { info.EnvironmentVariables.Add(kv.Key, kv.Value); } } } if (options.ArgumentsList != null) { options.ArgumentsList._DoForEach(a => info.ArgumentList.Add(a._NonNull())); } else { info.Arguments = options.Arguments._NullIfZeroLen() !; } StartTick = Time.HighResTick64; Proc = Process.Start(info) !; Proc._FixProcessObjectHandleLeak(); // メモリリーク解消 this.ProcessId = Proc.Id; // 標準入出力を接続する this.StandardPipePoint_MySide = PipePoint.NewDuplexPipeAndGetOneSide(PipePointSide.A_LowerSide); this._InputOutputPipePoint = this.StandardPipePoint_MySide.CounterPart._NullCheck(); this.StandardPipeWrapper = new PipePointStreamWrapper(StandardPipePoint_MySide, Proc.StandardOutput.BaseStream, Proc.StandardInput.BaseStream); // 標準エラー出力を接続する this.ErrorPipePoint_MySide = PipePoint.NewDuplexPipeAndGetOneSide(PipePointSide.A_LowerSide); this._ErrorPipePoint = this.ErrorPipePoint_MySide.CounterPart._NullCheck(); this.ErrorPipeWrapper = new PipePointStreamWrapper(ErrorPipePoint_MySide, Proc.StandardError.BaseStream, Stream.Null); if (options.Flags.Bit(ExecFlags.EasyInputOutputMode)) { this.EasyInputOutputStub = this._InputOutputPipePoint.GetNetAppProtocolStub(noCheckDisconnected: true); this.EasyInputOutputStream = this.EasyInputOutputStub.GetStream(); this.EasyErrorStub = this._ErrorPipePoint.GetNetAppProtocolStub(noCheckDisconnected: true); this.EasyErrorStream = this.EasyErrorStub.GetStream(); if (options.EasyInputStr != null && options.EasyInputStr.Length >= 1) { // 標準入力の注入タスク this.EasyInputTask = this.EasyInputOutputStream.SendAsync(this.Options.EasyInputStr !._GetBytes(this.InputEncoding), this.GrandCancel)._LeakCheck(); } // 標準出力の読み出しタスク this.EasyOutputTask = this.EasyInputOutputStream._ReadWithMaxBufferSizeAsync(this.Options.EasyOutputMaxSize, this.GrandCancel, async(data, cancel) => await EasyPrintRealTimeRecvDataCallbackAsync(data, false, cancel))._LeakCheck(); // 標準エラー出力の読み出しタスク this.EasyErrorTask = this.EasyErrorStream._ReadWithMaxBufferSizeAsync(this.Options.EasyOutputMaxSize, this.GrandCancel, async(data, cancel) => await EasyPrintRealTimeRecvDataCallbackAsync(data, true, cancel))._LeakCheck(); // リアルタイムバッファ監視タスク if (Options.EasyRealtimeRecvBufCallbackAsync != null) { this.EasyRealtimeBufferMainteTask = EasyRealtimeBufferMainteTaskAsync(this.GrandCancel)._LeakCheck(); } } this.StartMainLoop(MainLoopAsync); } catch { this._DisposeSafe(); throw; } }
public ExecInstance(ExecOptions options) { try { this.InputEncoding = Console.OutputEncoding; this.OutputEncoding = this.ErrorEncoding = Console.InputEncoding; this.Options = options._NullCheck(); ProcessStartInfo info = new ProcessStartInfo() { FileName = options.FileName, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, CreateNoWindow = true, WorkingDirectory = options.CurrentDirectory._NullIfEmpty(), }; if (options.ArgumentsList != null) { options.ArgumentsList._DoForEach(a => info.ArgumentList.Add(a._NonNull())); } else { info.Arguments = options.Arguments._NullIfZeroLen(); } StartTick = Time.HighResTick64; Proc = Process.Start(info); this.ProcessId = Proc.Id; // 標準入出力を接続する this.StandardPipePoint_MySide = PipePoint.NewDuplexPipeAndGetOneSide(PipePointSide.A_LowerSide); this._InputOutputPipePoint = this.StandardPipePoint_MySide.CounterPart._NullCheck(); this.StandardPipeWrapper = new PipePointStreamWrapper(StandardPipePoint_MySide, Proc.StandardOutput.BaseStream, Proc.StandardInput.BaseStream); // 標準エラー出力を接続する this.ErrorPipePoint_MySide = PipePoint.NewDuplexPipeAndGetOneSide(PipePointSide.A_LowerSide); this._ErrorPipePoint = this.ErrorPipePoint_MySide.CounterPart._NullCheck(); this.ErrorPipeWrapper = new PipePointStreamWrapper(ErrorPipePoint_MySide, Proc.StandardError.BaseStream, Stream.Null); if (options.Flags.Bit(ExecFlags.EasyInputOutputMode)) { this.EasyInputOutputStub = this._InputOutputPipePoint.GetNetAppProtocolStub(noCheckDisconnected: true); this.EasyInputOutputStream = this.EasyInputOutputStub.GetStream(); this.EasyErrorStub = this._ErrorPipePoint.GetNetAppProtocolStub(noCheckDisconnected: true); this.EasyErrorStream = this.EasyErrorStub.GetStream(); if (options.EasyInputStr != null) { // 標準入力の注入タスク this.EasyInputTask = this.EasyInputOutputStream.SendAsync(this.Options.EasyInputStr !._GetBytes(this.InputEncoding), this.GrandCancel)._LeakCheck(); } // 標準出力の読み出しタスク this.EasyOutputTask = this.EasyInputOutputStream._ReadWithMaxBufferSizeAsync(this.Options.EasyOutputMaxSize, this.GrandCancel)._LeakCheck(); // 標準エラー出力の読み出しタスク this.EasyErrorTask = this.EasyErrorStream._ReadWithMaxBufferSizeAsync(this.Options.EasyOutputMaxSize, this.GrandCancel)._LeakCheck(); } this.StartMainLoop(MainLoopAsync); } catch { this._DisposeSafe(); throw; } }