mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-01 17:27:14 +02:00
84 lines
2.0 KiB
TypeScript
84 lines
2.0 KiB
TypeScript
import { spawn, type SpawnOptions, type StdioOptions } from 'node:child_process';
|
|
|
|
import { detectPackageManager } from './package-manager';
|
|
|
|
export class ChildProcessError extends Error {
|
|
constructor(
|
|
message: string,
|
|
public code: number | null,
|
|
public signal: NodeJS.Signals | null,
|
|
) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
export async function runCommand(
|
|
cmd: string,
|
|
args: string[] = [],
|
|
opts: {
|
|
cwd?: string;
|
|
env?: NodeJS.ProcessEnv;
|
|
stdio?: StdioOptions;
|
|
context?: 'local' | 'global';
|
|
printOutput?: (options: { stdout: Buffer[]; stderr: Buffer[] }) => void;
|
|
} = {},
|
|
): Promise<void> {
|
|
const packageManager = (await detectPackageManager()) ?? 'npm';
|
|
|
|
return await new Promise((resolve, reject) => {
|
|
const options: SpawnOptions = {
|
|
cwd: opts.cwd,
|
|
env: { ...process.env, ...opts.env },
|
|
stdio: opts.stdio ?? ['ignore', 'pipe', 'pipe'],
|
|
shell: process.platform === 'win32',
|
|
};
|
|
const child =
|
|
opts.context === 'local'
|
|
? spawn(packageManager, ['exec', '--', cmd, ...args], options)
|
|
: spawn(cmd, args, options);
|
|
|
|
const stdoutBuffers: Buffer[] = [];
|
|
const stderrBuffers: Buffer[] = [];
|
|
|
|
child.stdout?.on('data', (data: Buffer) => {
|
|
stdoutBuffers.push(data);
|
|
});
|
|
child.stderr?.on('data', (data: Buffer) => {
|
|
stderrBuffers.push(data);
|
|
});
|
|
|
|
function printOutput() {
|
|
if (opts.printOutput) {
|
|
opts.printOutput({ stdout: stdoutBuffers, stderr: stderrBuffers });
|
|
return;
|
|
}
|
|
for (const buffer of stdoutBuffers) {
|
|
process.stdout.write(buffer);
|
|
}
|
|
for (const buffer of stderrBuffers) {
|
|
process.stderr.write(buffer);
|
|
}
|
|
}
|
|
|
|
child.on('error', (error) => {
|
|
printOutput();
|
|
reject(new ChildProcessError(error.message, null, null));
|
|
});
|
|
|
|
child.on('close', (code, signal) => {
|
|
if (code === 0) {
|
|
resolve();
|
|
} else {
|
|
printOutput();
|
|
reject(
|
|
new ChildProcessError(
|
|
`${cmd} exited with code ${code}${signal ? ` (signal: ${signal})` : ''}`,
|
|
code,
|
|
signal,
|
|
),
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|