Drop usage of execSync, switch to $ util
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
interface ShellOptions {
|
||||
cwd?: string;
|
||||
encoding?:
|
||||
| "utf-8"
|
||||
| "utf8"
|
||||
| "ascii"
|
||||
| "base64"
|
||||
| "base64url"
|
||||
| "hex"
|
||||
| "latin1"
|
||||
| "ucs-2"
|
||||
| "ucs2"
|
||||
| "utf16le";
|
||||
log?: boolean;
|
||||
onError?: (result: { status: number; stdout: string; stderr: string }) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a shell command safely using spawnSync with argument arrays.
|
||||
* Prevents shell injection by avoiding string interpolation in shell commands.
|
||||
*
|
||||
* @param cmd - The command to execute
|
||||
* @param args - Array of arguments to pass to the command
|
||||
* @param options - Optional configuration (cwd, encoding, onError)
|
||||
* @returns The trimmed stdout output
|
||||
* @throws Error if command fails and no onError handler is provided
|
||||
*/
|
||||
export function $(cmd: string, args: string[], options?: ShellOptions): string {
|
||||
const encoding = options?.encoding ?? "utf-8";
|
||||
const result = spawnSync(cmd, args, {
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
encoding,
|
||||
cwd: options?.cwd,
|
||||
});
|
||||
|
||||
const stdout = result.stdout ?? "";
|
||||
const stderr = result.stderr ?? "";
|
||||
|
||||
// Write output to process streams so it behaves like stdio: "inherit"
|
||||
// Only log if log option is not explicitly set to false
|
||||
if (options?.log !== false) {
|
||||
if (stdout) {
|
||||
process.stdout.write(stdout);
|
||||
}
|
||||
if (stderr) {
|
||||
process.stderr.write(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
if (result.status !== 0) {
|
||||
const errorResult = {
|
||||
status: result.status ?? -1,
|
||||
stdout,
|
||||
stderr,
|
||||
};
|
||||
|
||||
if (options?.onError) {
|
||||
options.onError(errorResult);
|
||||
return stdout.trim();
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Command failed with exit code ${errorResult.status}: ${stderr || "Unknown error"}`
|
||||
);
|
||||
}
|
||||
|
||||
return stdout.trim();
|
||||
}
|
||||
Reference in New Issue
Block a user