| 70 | } |
| 71 | |
| 72 | async function _exec(cmd: string, options?: { logLevel?: LogLevel; logOutput?: boolean | 'continuous' | 'silent'; stdin?: Buffer }) { |
| 73 | const text = `Run in ${hostName.toLowerCase()}: ${cmd.replace(/\n.*/g, '')}`; |
| 74 | let start: number; |
| 75 | if (options?.logOutput !== 'silent') { |
| 76 | start = output.start(text, options?.logLevel); |
| 77 | } |
| 78 | if (p.stdin.destroyed) { |
| 79 | output.write('Stdin closed!'); |
| 80 | const { code, signal } = await p.exit; |
| 81 | return Promise.reject({ message: `Shell server terminated (code: ${code}, signal: ${signal})`, code, signal }); |
| 82 | } |
| 83 | if (platform === 'win32') { |
| 84 | p.stdin.write(`[Console]::Write('${EOT}'); ( ${cmd} ); [Console]::Write("${EOT}$LastExitCode ${EOT}"); [Console]::Error.Write('${EOT}')\n`); |
| 85 | } else { |
| 86 | p.stdin.write(`echo -n ${EOT}; ( ${cmd} ); echo -n ${EOT}$?${EOT}; echo -n ${EOT} >&2\n`); |
| 87 | } |
| 88 | const [stdoutP0, stdoutP] = read(p.stdout, [1, 2], options?.logOutput === 'continuous' ? (str, i, j) => { |
| 89 | if (i === 1 && j === 0) { |
| 90 | output.write(str, options?.logLevel); |
| 91 | } |
| 92 | } : () => undefined); |
| 93 | const stderrP = read(p.stderr, [1], options?.logOutput === 'continuous' ? (str, i, j) => { |
| 94 | if (i === 0 && j === 0) { |
| 95 | output.write(str, options?.logLevel); // TODO |
| 96 | } |
| 97 | } : () => undefined)[0]; |
| 98 | if (options?.stdin) { |
| 99 | await stdoutP0; // Wait so `cmd` has its stdin set up. |
| 100 | p.stdin.write(options?.stdin); |
| 101 | } |
| 102 | const [stdout, codeStr] = await stdoutP; |
| 103 | const [stderr] = await stderrP; |
| 104 | const code = parseInt(codeStr, 10) || 0; |
| 105 | if (options?.logOutput === undefined || options?.logOutput === true) { |
| 106 | output.write(stdout, options?.logLevel); |
| 107 | output.write(stderr, options?.logLevel); // TODO |
| 108 | if (code) { |
| 109 | output.write(`Exit code ${code}`, options?.logLevel); |
| 110 | } |
| 111 | } |
| 112 | if (options?.logOutput === 'continuous' && code) { |
| 113 | output.write(`Exit code ${code}`, options?.logLevel); |
| 114 | } |
| 115 | if (options?.logOutput !== 'silent') { |
| 116 | output.stop(text, start!, options?.logLevel); |
| 117 | } |
| 118 | if (code) { |
| 119 | return Promise.reject({ message: `Command in ${hostName.toLowerCase()} failed: ${cmd}`, code, stdout, stderr }); |
| 120 | } |
| 121 | return { stdout, stderr }; |
| 122 | } |
| 123 | |
| 124 | return { exec, process: p, platform, path: platformDispatch(platform, path) }; |
| 125 | } |