UNPKG

runscript

Version:
166 lines 13.8 kB
import { debuglog } from 'node:util'; import assert from 'node:assert'; import path from 'node:path'; import { spawn, spawnSync } from 'node:child_process'; import { isWritable } from 'is-type-of'; const debug = debuglog('runscript'); function isCmd() { if (process.platform !== 'win32') { return false; } try { const result = spawnSync('ls', { stdio: 'pipe', }); return result.error !== undefined; } catch (err) { return true; } } export class RunScriptError extends Error { stdio; exitcode; constructor(message, stdio, exitcode, options) { super(message, options); this.name = this.constructor.name; this.stdio = stdio; this.exitcode = exitcode; Error.captureStackTrace(this, this.constructor); } } export class RunScriptTimeoutError extends Error { stdio; timeout; constructor(message, stdio, timeout, options) { super(message, options); this.name = this.constructor.name; this.stdio = stdio; this.timeout = timeout; Error.captureStackTrace(this, this.constructor); } } /** * Run shell script in child process * Support OSX, Linux and Windows * @param {String} script - full script string, like `git clone https://github.com/node-modules/runscript.git` * @param {Object} [options] - spawn options * @see https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options * @param {Object} [extraOptions] - extra options for running * - {Number} [extraOptions.timeout] - child process running timeout * @return {Object} stdio object, will contains stdio.stdout and stdio.stderr buffer. */ export function runScript(script, options = {}, extraOptions = {}) { return new Promise((resolve, reject) => { options.env = options.env || Object.assign({}, process.env); options.cwd = options.cwd || process.cwd(); if (typeof options.cwd === 'object') { // convert URL object to string options.cwd = String(options.cwd); } options.stdio = options.stdio || 'inherit'; if (options.stdout) { assert(isWritable(options.stdout), 'options.stdout should be writable stream'); } if (options.stderr) { assert(isWritable(options.stderr), 'options.stderr should be writable stream'); } let sh = 'sh'; let shFlag = '-c'; if (process.platform === 'win32') { sh = process.env.comspec || 'cmd'; shFlag = '/d /s /c'; options.windowsVerbatimArguments = true; if (script.indexOf('./') === 0 || script.indexOf('.\\') === 0 || script.indexOf('../') === 0 || script.indexOf('..\\') === 0) { const splits = script.split(' '); // in bash C:\Windows\system32 -> C:\\Windows\\system32 splits[0] = path.join(isCmd() ? options.cwd : path.normalize(options.cwd), splits[0]); script = splits.join(' '); } } debug('%s %s %s, %j, %j', sh, shFlag, script, options, extraOptions); const proc = spawn(sh, [shFlag, script], options); const stdout = []; const stderr = []; let isEnd = false; let timeoutTimer; if (proc.stdout) { proc.stdout.on('data', (buf) => { debug('stdout %d bytes', buf.length); stdout.push(buf); }); if (options.stdout) { proc.stdout.pipe(options.stdout); } } if (proc.stderr) { proc.stderr.on('data', (buf) => { debug('stderr %d bytes', buf.length); stderr.push(buf); }); if (options.stderr) { proc.stderr.pipe(options.stderr); } } proc.on('error', err => { debug('proc emit error: %s', err); if (isEnd) { return; } isEnd = true; clearTimeout(timeoutTimer); reject(err); }); proc.on('exit', code => { debug('proc emit exit: %s', code); if (isEnd) { return; } isEnd = true; clearTimeout(timeoutTimer); const stdio = { stdout: null, stderr: null, }; if (stdout.length > 0) { stdio.stdout = Buffer.concat(stdout); } if (stderr.length > 0) { stdio.stderr = Buffer.concat(stderr); } if (code !== 0) { const err = new RunScriptError(`Run "${sh} ${shFlag} ${script}" error, exit code ${code}`, stdio, code); return reject(err); } return resolve(stdio); }); proc.on('close', code => { debug('proc emit close: %s', code); }); if (typeof extraOptions.timeout === 'number' && extraOptions.timeout > 0) { const timeout = extraOptions.timeout; // start timer timeoutTimer = setTimeout(() => { debug('proc run timeout: %dms', timeout); isEnd = true; debug('kill child process %s', proc.pid); proc.kill(); const stdio = { stdout: null, stderr: null, }; if (stdout.length > 0) { stdio.stdout = Buffer.concat(stdout); } if (stderr.length > 0) { stdio.stderr = Buffer.concat(stderr); } const err = new RunScriptTimeoutError(`Run "${sh} ${shFlag} ${script}" timeout in ${extraOptions.timeout}ms`, stdio, timeout); return reject(err); }, timeout); } }); } export const runscript = runScript; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDakMsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFxQixNQUFNLG9CQUFvQixDQUFDO0FBRXpFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFeEMsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBRXBDLFNBQVMsS0FBSztJQUNaLElBQUksT0FBTyxDQUFDLFFBQVEsS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUNqQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsSUFBSSxFQUFFO1lBQzdCLEtBQUssRUFBRSxNQUFNO1NBQ2QsQ0FBQyxDQUFDO1FBRUgsT0FBTyxNQUFNLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQztJQUNwQyxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztBQUNILENBQUM7QUFvQkQsTUFBTSxPQUFPLGNBQWUsU0FBUSxLQUFLO0lBQ3ZDLEtBQUssQ0FBUTtJQUNiLFFBQVEsQ0FBZ0I7SUFFeEIsWUFBWSxPQUFlLEVBQUUsS0FBWSxFQUFFLFFBQXVCLEVBQUUsT0FBc0I7UUFDeEYsS0FBSyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN4QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUks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