// This file represents useful wrappers over node:child_process// These wrappers ease error handling and cross-platform compatbility// By using execa, Windows automatically gets shell escaping + BAT / CMD handlingimport { type ExecaError, execa } from 'execa'import { getCwd } from '../utils/cwd.js'import { logError } from './log.js'export { execSyncWithDefaults_DEPRECATED } from './execFileNoThrowPortable.js'const MS_IN_SECOND = 1000const SECONDS_IN_MINUTE = 60type ExecFileOptions = {abortSignal?: AbortSignaltimeout?: numberpreserveOutputOnError?: boolean// Setting useCwd=false avoids circular dependencies during initialization// getCwd() -> PersistentShell -> logEvent() -> execFileNoThrowuseCwd?: booleanenv?: NodeJS.ProcessEnvstdin?: 'ignore' | 'inherit' | 'pipe'input?: string}export function execFileNoThrow(file: string,args: string[],options: ExecFileOptions = {timeout: 10 * SECONDS_IN_MINUTE * MS_IN_SECOND,preserveOutputOnError: true,useCwd: true,},): Promise<{ stdout: string; stderr: string; code: number; error?: string }> {return execFileNoThrowWithCwd(file, args, {abortSignal: options.abortSignal,timeout: options.timeout,preserveOutputOnError: options.preserveOutputOnError,cwd: options.useCwd ? getCwd() : undefined,env: options.env,stdin: options.stdin,input: options.input,})}type ExecFileWithCwdOptions = {abortSignal?: AbortSignaltimeout?: numberpreserveOutputOnError?: booleanmaxBuffer?: numbercwd?: stringenv?: NodeJS.ProcessEnvshell?: boolean | string | undefinedstdin?: 'ignore' | 'inherit' | 'pipe'input?: string}type ExecaResultWithError = {shortMessage?: stringsignal?: string}/*** Extracts a human-readable error message from an execa result.** Priority order:* 1. shortMessage - execa's human-readable error (e.g., "Command failed with exit code 1: ...")* This is preferred because it already includes signal info when a process is killed,* making it more informative than just the signal name.* 2. signal - the signal that killed the process (e.g., "SIGTERM")* 3. errorCode - fallback to just the numeric exit code*/function getErrorMessage(result: ExecaResultWithError,errorCode: number,): string {if (result.shortMessage) {return result.shortMessage}if (typeof result.signal === 'string') {return result.signal}return String(errorCode)}/*** execFile, but always resolves (never throws)*/export function execFileNoThrowWithCwd(file: string,args: string[],{abortSignal,timeout: finalTimeout = 10 * SECONDS_IN_MINUTE * MS_IN_SECOND,preserveOutputOnError: finalPreserveOutput = true,cwd: finalCwd,env: finalEnv,maxBuffer,shell,stdin: finalStdin,input: finalInput,}: ExecFileWithCwdOptions = {timeout: 10 * SECONDS_IN_MINUTE * MS_IN_SECOND,preserveOutputOnError: true,maxBuffer: 1_000_000,},): Promise<{ stdout: string; stderr: string; code: number; error?: string }> {return new Promise(resolve => {// Use execa for cross-platform .bat/.cmd compatibility on Windowsexeca(file, args, {maxBuffer,cancelSignal: abortSignal,timeout: finalTimeout,cwd: finalCwd,env: finalEnv,shell,stdin: finalStdin,input: finalInput,reject: false, // Don't throw on non-zero exit codes}).then(result => {if (result.failed) {if (finalPreserveOutput) {const errorCode = result.exitCode ?? 1void resolve({stdout: result.stdout || '',stderr: result.stderr || '',code: errorCode,error: getErrorMessage(result as unknown as ExecaResultWithError,errorCode,),})} else {void resolve({ stdout: '', stderr: '', code: result.exitCode ?? 1 })}} else {void resolve({stdout: result.stdout,stderr: result.stderr,code: 0,})}}).catch((error: ExecaError) => {logError(error)void resolve({ stdout: '', stderr: '', code: 1 })})})}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。