diff options
author | Maayan Hanin <maayan.asa.hanin@gmail.com> | 2020-07-09 22:06:51 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-09 21:06:51 +0200 |
commit | edb7a0eead3604316b3cca2ac9122c5599445a63 (patch) | |
tree | e8d7fe06992decf52c81678b4c000a6edeb922fd /cli/tests/DenoWinRunner.cs | |
parent | 202e7fa6ad366ee56a6d070e94eaecb6dbc745bf (diff) |
fix(cli): panic when stdio is null on windows (#6528)
Fixes: #6409
Diffstat (limited to 'cli/tests/DenoWinRunner.cs')
-rw-r--r-- | cli/tests/DenoWinRunner.cs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/cli/tests/DenoWinRunner.cs b/cli/tests/DenoWinRunner.cs new file mode 100644 index 000000000..7879d146d --- /dev/null +++ b/cli/tests/DenoWinRunner.cs @@ -0,0 +1,127 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +[Flags] +public enum DenoConstraints : int +{ + None = 0, + NoStdin = 1, + NoStdout = 2, + NoStderr = 4 +} + +public class DenoWinRunner +{ + private const int STD_INPUT_HANDLE = -10; + private const int STD_OUTPUT_HANDLE = -11; + private const int STD_ERROR_HANDLE = -12; + + private const int FILE_NOT_FOUND = 2; + private const int WAIT_TIMEOUT = 258; + + [DllImport("kernel32.dll")] + private static extern void SetStdHandle(int nStdHandle, IntPtr handle); + + /// <summary> + /// Runs Deno.exe under the specified constraints + /// </summary> + /// <param name="pathToDenoExe">Path to the Deno.exe file. Can be absolute or relative</param> + /// <param name="pathToTestScript">Path to the script file Deno should run.</param> + /// <param name="constraints">The contrainsts to apply to the Deno process</param> + /// <param name="timeoutMilliseconds">How long to wait for the Deno process to exit</param> + /// <returns>The deno.exe exit code, or an exit code provided by the test runner</returns> + public static int RunDenoScript(string pathToDenoExe, string pathToTestScript, DenoConstraints constraints, uint timeoutMilliseconds = 1000) + { + try + { + if (!File.Exists(pathToDenoExe)) + { + Console.Error.WriteLine("Cannot find Deno.exe at " + pathToDenoExe); + return FILE_NOT_FOUND; + } + + if (!File.Exists(pathToTestScript)) + { + Console.Error.WriteLine("Cannot find test script at " + pathToTestScript); + return FILE_NOT_FOUND; + } + + ProcessStartInfo startInfo = new ProcessStartInfo(pathToDenoExe) + { + ErrorDialog = false, + UseShellExecute = false, + Arguments = @"run -A " + pathToTestScript, + RedirectStandardInput = !constraints.HasFlag(DenoConstraints.NoStdin), + RedirectStandardOutput = !constraints.HasFlag(DenoConstraints.NoStdout), + RedirectStandardError = !constraints.HasFlag(DenoConstraints.NoStderr) + }; + + startInfo.Environment.Add("RUST_BACKTRACE", "1"); + + if (constraints.HasFlag(DenoConstraints.NoStdin)) + { + SetStdHandle(STD_INPUT_HANDLE, (IntPtr)null); + } + + if (constraints.HasFlag(DenoConstraints.NoStdout)) + { + SetStdHandle(STD_OUTPUT_HANDLE, (IntPtr)null); + } + + if (constraints.HasFlag(DenoConstraints.NoStderr)) + { + SetStdHandle(STD_ERROR_HANDLE, (IntPtr)null); + } + + Process process = new Process { StartInfo = startInfo }; + process.Start(); + + Task<string> stdErrTask = startInfo.RedirectStandardError ? + process.StandardError.ReadToEndAsync() : Task.FromResult<string>(null); + Task<string> stdOutTask = startInfo.RedirectStandardOutput ? + process.StandardOutput.ReadToEndAsync() : Task.FromResult<string>(null); + + if (!process.WaitForExit((int)timeoutMilliseconds)) + { + Console.Error.WriteLine("Timed out waiting for Deno process to exit"); + try + { + process.Kill(); + } + catch + { + // Kill might fail, either because the process already exited or due to some other error + Console.Error.WriteLine("Failure killing the Deno process - possible Zombie Deno.exe process"); + } + return WAIT_TIMEOUT; + } + + // If the Deno process wrote to STDERR - append it to our STDERR + if (!constraints.HasFlag(DenoConstraints.NoStderr)) + { + string error = stdErrTask.Result; + if (!string.IsNullOrWhiteSpace(error)) + { + Console.Error.WriteLine(error); + } + } + + return process.ExitCode; + + } + catch (Win32Exception ex) + { + Console.Error.WriteLine("Win32Exception: code = " + ex.ErrorCode + ", message: " + ex.Message); + return ex.NativeErrorCode; + } + catch (Exception ex) + { + Console.Error.WriteLine("Exception: message: " + ex.Message); + return -1; + } + } +}
\ No newline at end of file |