UNPKG

2.36 kBJavaScriptView Raw
1const { exec, spawn } = require('child_process');
2
3/**
4 * wrap child_process.exec with retry. Will throw immediately when return
5 * code not 0; Used for trivial commands since error detail won't be printed.
6 * @param {string} command
7 * @param {structure} execOptoins
8 * @param {number} retryCount
9 */
10async function executeCommand(command, execOptoins = {}, retryCount = 1) {
11 try {
12 const execCommand = command.join(' ');
13 const { stderr, stdout } = await execute(execCommand, execOptoins);
14 if (stderr) process.stderr.write(stderr.toString());
15 if (stdout) process.stderr.write(stdout.toString());
16 } catch (error) {
17 if (retryCount > 0) {
18 await executeCommand(command, execOptoins, --retryCount);
19 } else {
20 throw error;
21 }
22 }
23}
24
25function execute(command, options) {
26 return new Promise((resolve, reject) => {
27 exec(command, options, (err, stdout, stderr) => {
28 if (err) {
29 reject(err);
30 } else {
31 resolve({
32 stdout: stdout,
33 stderr: stderr
34 });
35 }
36 });
37 })
38}
39
40/**
41 * wrap child_process.spawn with retry
42 * @param {string} command
43 * @param {structure} execOptions
44 * @param {number} retryCount
45 */
46async function executeLongProcessCommand(command, execOptions = {}, retryCount = 1) {
47 try {
48 const firstCommand = command[0];
49 const options = command.slice(1);
50 await promisifiedSpawn(firstCommand, options, execOptions);
51 } catch (error) {
52 if (retryCount > 0) {
53 await executeLongProcessCommand(command, execOptions, --retryCount);
54 } else {
55 throw error;
56 }
57 }
58}
59
60function promisifiedSpawn(command, options, execOptions) {
61 return new Promise((resolve, reject) => {
62 const subProcess = spawn(command, options, execOptions);
63 subProcess.stdout.on('data', (data) => {
64 process.stdout.write(data.toString());
65 });
66 subProcess.stderr.on('data', (data) => {
67 process.stderr.write(data.toString());
68 });
69 subProcess.on('error', (err) => {
70 console.error('spawn error: ', err);
71 });
72 subProcess.on('close', (code) => {
73 if (code === 0) {
74 resolve();
75 } else {
76 reject(`"${command} ${options.join(' ')}" exited with code: ${code}`);
77 }
78 });
79 });
80}
81
82module.exports = {
83 execute: executeCommand,
84 executeLongProcess: executeLongProcessCommand,
85}
\No newline at end of file