85 lines
2.3 KiB
JavaScript
85 lines
2.3 KiB
JavaScript
const { exec, spawn } = require('child_process');
|
|
|
|
/**
|
|
* wrap child_process.exec with retry. Will throw immediately when return
|
|
* code not 0; Used for trivial commands since error detail won't be printed.
|
|
* @param {string} command
|
|
* @param {structure} execOptoins
|
|
* @param {number} retryCount
|
|
*/
|
|
async function executeCommand(command, execOptoins = {}, retryCount = 1) {
|
|
try {
|
|
const execCommand = command.join(' ');
|
|
const { stderr, stdout } = await execute(execCommand, execOptoins);
|
|
if (stderr) process.stderr.write(stderr.toString());
|
|
if (stdout) process.stderr.write(stdout.toString());
|
|
} catch (error) {
|
|
if (retryCount > 0) {
|
|
await executeCommand(command, execOptoins, --retryCount);
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
function execute(command, options) {
|
|
return new Promise((resolve, reject) => {
|
|
exec(command, options, (err, stdout, stderr) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve({
|
|
stdout: stdout,
|
|
stderr: stderr
|
|
});
|
|
}
|
|
});
|
|
})
|
|
}
|
|
|
|
/**
|
|
* wrap child_process.spawn with retry
|
|
* @param {string} command
|
|
* @param {structure} execOptions
|
|
* @param {number} retryCount
|
|
*/
|
|
async function executeLongProcessCommand(command, execOptions = {}, retryCount = 1) {
|
|
try {
|
|
const firstCommand = command[0];
|
|
const options = command.slice(1);
|
|
await promisifiedSpawn(firstCommand, options, execOptions);
|
|
} catch (error) {
|
|
if (retryCount > 0) {
|
|
await executeLongProcessCommand(command, execOptions, --retryCount);
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
function promisifiedSpawn(command, options, execOptions) {
|
|
return new Promise((resolve, reject) => {
|
|
const subProcess = spawn(command, options, execOptions);
|
|
subProcess.stdout.on('data', (data) => {
|
|
process.stdout.write(data.toString());
|
|
});
|
|
subProcess.stderr.on('data', (data) => {
|
|
process.stderr.write(data.toString());
|
|
});
|
|
subProcess.on('error', (err) => {
|
|
console.error('spawn error: ', err);
|
|
});
|
|
subProcess.on('close', (code) => {
|
|
if (code === 0) {
|
|
resolve();
|
|
} else {
|
|
reject(`"${command} ${options.join(' ')}" exited with code: ${code}`);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
execute: executeCommand,
|
|
executeLongProcess: executeLongProcessCommand,
|
|
} |