/// <inheritdoc /> public async Task Run( string command, string workingDirectory = "", bool streamOutputToInteractiveService = true, Action <TryRunResult>?onComplete = null, bool redirectIO = true, IDictionary <string, string>?environmentVariables = null, CancellationToken cancelToken = default, bool needAwsCredentials = false) { StringBuilder strOutput = new StringBuilder(); StringBuilder strError = new StringBuilder(); var processStartInfo = new ProcessStartInfo { FileName = GetSystemShell(), Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"/c {command}" : $"-c \"{command}\"", RedirectStandardInput = redirectIO, RedirectStandardOutput = redirectIO, RedirectStandardError = redirectIO, UseShellExecute = false, CreateNoWindow = redirectIO, WorkingDirectory = workingDirectory }; // If the command output is not being redirected check to see if // the output should go to a separate console window. This is important when run from // an IDE which won't have a console window by default. if (!streamOutputToInteractiveService && !redirectIO) { processStartInfo.UseShellExecute = _useSeparateWindow; } UpdateEnvironmentVariables(processStartInfo, environmentVariables); if (needAwsCredentials) { _processStartInfoAction?.Invoke(processStartInfo); } var process = Process.Start(processStartInfo); if (null == process) { throw new Exception("Process.Start failed to return a non-null process"); } if (redirectIO) { process.OutputDataReceived += (sender, e) => { if (streamOutputToInteractiveService) { _interactiveService.LogMessageLine(e.Data); } strOutput.Append(e.Data); }; process.ErrorDataReceived += (sender, e) => { if (streamOutputToInteractiveService) { _interactiveService.LogMessageLine(e.Data); } strError.Append(e.Data); }; process.BeginOutputReadLine(); process.BeginErrorReadLine(); } // poll for process to prevent blocking the main thread // as opposed to using process.WaitForExit() // in .net5 we can use process.WaitForExitAsync() while (true) { if (process.HasExited) { break; } await Task.Delay(TimeSpan.FromMilliseconds(50), cancelToken); } if (onComplete != null) { var result = new TryRunResult { ExitCode = process.ExitCode }; if (redirectIO) { result.StandardError = strError.ToString(); result.StandardOut = strOutput.ToString(); } onComplete(result); } }
/// <inheritdoc /> public async Task Run( string command, string workingDirectory = "", bool streamOutputToInteractiveService = true, Action <TryRunResult> onComplete = null, bool redirectIO = true, CancellationToken cancelToken = default) { StringBuilder strOutput = new StringBuilder(); StringBuilder strError = new StringBuilder(); var credentials = await _awsCredentials.GetCredentialsAsync(); var processStartInfo = new ProcessStartInfo { FileName = GetSystemShell(), Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"/c {command}" : $"-c \"{command}\"", RedirectStandardInput = redirectIO, RedirectStandardOutput = redirectIO, RedirectStandardError = redirectIO, UseShellExecute = false, CreateNoWindow = redirectIO, WorkingDirectory = workingDirectory }; // environment variables could already be set at the machine level, // use this syntax to make sure we don't create duplicate entries processStartInfo.EnvironmentVariables["AWS_ACCESS_KEY_ID"] = credentials.AccessKey; processStartInfo.EnvironmentVariables["AWS_SECRET_ACCESS_KEY"] = credentials.SecretKey; processStartInfo.EnvironmentVariables["AWS_REGION"] = _awsRegion; if (credentials.UseToken) { processStartInfo.EnvironmentVariables["AWS_SESSION_TOKEN"] = credentials.Token; } var process = Process.Start(processStartInfo); if (null == process) { throw new Exception("Process.Start failed to return a non-null process"); } if (redirectIO && streamOutputToInteractiveService) { process.OutputDataReceived += (sender, e) => { _interactiveService.LogMessageLine(e.Data); strOutput.Append(e.Data); }; process.ErrorDataReceived += (sender, e) => { _interactiveService.LogMessageLine(e.Data); strError.Append(e.Data); }; process.BeginOutputReadLine(); process.BeginErrorReadLine(); } // poll for process to prevent blocking the main thread // as opposed to using process.WaitForExit() // in .net5 we can use process.WaitForExitAsync() while (true) { if (process.HasExited) { break; } await Task.Delay(TimeSpan.FromMilliseconds(50), cancelToken); } if (onComplete != null) { var result = new TryRunResult { ExitCode = process.ExitCode }; if (redirectIO) { result.StandardError = streamOutputToInteractiveService ? strError.ToString() : await process.StandardError.ReadToEndAsync(); result.StandardOut = streamOutputToInteractiveService ? strOutput.ToString() : await process.StandardOutput.ReadToEndAsync(); } onComplete(result); } }