isaacscript
Version:
A command line tool for managing Isaac mods written in TypeScript.
113 lines • 4.03 kB
JavaScript
import chalk from "chalk";
import { fatalError } from "complete-node";
import { execFileSync, execSync, spawnSync } from "node:child_process";
import { CWD } from "./constants.js";
export function execExe(path, args, verbose, cwd = CWD) {
if (verbose) {
console.log(`Executing binary: ${path}`);
}
let stdout;
try {
const buffer = execFileSync(path, args, {
cwd,
});
stdout = buffer.toString().trim();
}
catch (error) {
fatalError(`Failed to run "${chalk.green(path)}":`, error);
}
if (verbose) {
console.log(`Executed binary: ${path}`);
}
return stdout;
}
export function execPowershell(command, verbose = false, cwd = CWD) {
if (verbose) {
console.log(`Executing PowerShell command: ${command}`);
}
let stdout;
try {
const buffer = execSync(command, {
shell: "powershell.exe",
cwd,
});
stdout = buffer.toString().trim();
}
catch (error) {
fatalError(`Failed to run PowerShell command "${chalk.green(command)}":`, error);
}
if (verbose) {
console.log(`Executed PowerShell command: ${command}`);
}
return stdout;
}
/**
* Returns a tuple of exit status and stdout. The stdout is trimmed for convenience.
*
* @param command The command to run.
* @param args Default is [].
* @param verbose Default is false.
* @param allowFailure Default is false.
* @param cwd Default is CWD.
*/
export function execShell(command, args = [], verbose = false, allowFailure = false, cwd = CWD) {
// On Windows, "spawnSync()" will not account for spaces in arguments. Thus, wrap everything in a
// double quote. This will cause arguments that naturally have double quotes to fail.
if (command.includes("'") || command.includes('"')) {
fatalError("execShell cannot execute commands with single quotes or double quotes in the command.");
}
const argsHasDoubleQuotes = args.some((arg) => arg.includes('"'));
if (argsHasDoubleQuotes) {
fatalError("execShell cannot execute commands with double quotes in the arguments.");
}
const quotedArgs = args.map((arg) => `"${arg}"`);
const commandDescription = `${command} ${quotedArgs.join(" ")}`.trim();
if (verbose) {
console.log(`Executing command: ${commandDescription}`);
}
let spawnSyncReturns;
try {
spawnSyncReturns = spawnSync(command, quotedArgs, {
shell: true,
cwd,
});
}
catch (error) {
fatalError(`Failed to run the "${chalk.green(commandDescription)}" command:`, error);
}
if (verbose) {
console.log(`Executed command: ${commandDescription}`);
}
const exitStatus = spawnSyncReturns.status;
if (exitStatus === null) {
fatalError(`Failed to get the return status of command: ${commandDescription}`);
}
const stdout = spawnSyncReturns.output.join("\n").trim();
if (exitStatus !== 0) {
if (allowFailure) {
return { exitStatus, stdout };
}
console.error(`Failed to run the "${chalk.green(commandDescription)}" command with an exit code of ${exitStatus}.`);
console.error("The output was as follows:");
console.error(stdout);
process.exit(1);
}
return { exitStatus, stdout };
}
/**
* Same as `execShell`, but accepts the command as a string instead of an array of arguments.
*
* @param commandString The command to run.
* @param verbose Default is false.
* @param allowFailure Default is false.
* @param cwd Default is CWD.
*/
export function execShellString(commandString, verbose = false, allowFailure = false, cwd = CWD) {
const args = commandString.split(" ");
const command = args.shift();
if (command === undefined) {
fatalError(`execShellString failed to parse the command of: ${commandString}`);
}
return execShell(command, args, verbose, allowFailure, cwd);
}
//# sourceMappingURL=exec.js.map