Files
orca/src/main/git/command-runner/command-exec-file.ts
T
NeilandNeil 822087c8ec refactor(git): split runner.ts into focused command-runner modules (#16395)
* refactor(git): split runner.ts into focused command-runner modules

* chore(ratchets): repoint child_process and wsl.exe allowlists at the split modules

---------

Co-authored-by: Neil <n@example.com>
2026-08-25 02:34:11 -07:00

69 lines
2.2 KiB
TypeScript

import { isWindowsBatchScript, resolveWindowsCommand } from '../../win32-utils'
import { resolveCommand, type ResolvedCommand } from './wsl-command-resolution'
import { execFileCapture } from './exec-file-capture'
import { spawnCommandCapture, type CommandExecOptions } from './spawn-command-capture'
function isMissingCommandError(error: unknown): boolean {
return Boolean(
error && typeof error === 'object' && (error as { code?: unknown }).code === 'ENOENT'
)
}
function hasPathSeparator(command: string): boolean {
return command.includes('/') || command.includes('\\')
}
function shouldRetryWindowsCommandShim(error: unknown, resolved: ResolvedCommand): boolean {
return (
process.platform === 'win32' &&
resolved.wsl === null &&
isMissingCommandError(error) &&
!hasPathSeparator(resolved.binary) &&
!/\.[A-Za-z0-9]+$/.test(resolved.binary)
)
}
/**
* Async command execution with the same WSL cwd translation as repo-scoped git.
* Keep this for fixed binary+argv call sites; never pass shell fragments.
*/
export async function commandExecFileAsync(
command: string,
args: string[],
options: CommandExecOptions = {}
): Promise<{ stdout: string; stderr: string }> {
const { wslDistro, ...execOptions } = options
const resolved = resolveCommand(command, args, options.cwd, wslDistro)
const binary =
resolved.wsl === null ? resolveWindowsCommand(resolved.binary, options.env) : resolved.binary
if (isWindowsBatchScript(binary)) {
return spawnCommandCapture(binary, resolved.args, {
...execOptions,
cwd: resolved.cwd
})
}
try {
const { stdout, stderr } = await execFileCapture(binary, resolved.args, {
cwd: resolved.cwd,
encoding: execOptions.encoding ?? 'utf-8',
maxBuffer: execOptions.maxBuffer,
timeout: execOptions.timeout,
env: execOptions.env,
signal: execOptions.signal
})
return { stdout: stdout as string, stderr: stderr as string }
} catch (error) {
if (shouldRetryWindowsCommandShim(error, resolved)) {
return spawnCommandCapture(
resolveWindowsCommand(`${resolved.binary}.cmd`, options.env),
resolved.args,
{
...execOptions,
cwd: resolved.cwd
}
)
}
throw error
}
}