forked from nuintun/node-adodb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspawn.js
133 lines (112 loc) · 3.43 KB
/
spawn.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* @module spawn
* @license MIT
* @version 2018/04/28
* @see https://github.com/panosoft/spawn-promise
*/
'use strict';
let transcode = require('buffer').transcode;
const childProcess = require('child_process');
// Hack transcode
if (!transcode) {
/**
* @function toBuffer
* @param {string} string
* @param {string} encoding
* @returns {Buffer}
*/
const toBuffer =
Buffer.from ||
function(string, encoding) {
return new Buffer(string, encoding);
};
/**
* @function transcode
* @param {Buffer} source
* @param {string} fromEncoding
* @param {string} toEncoding
* @returns {Buffer}
*/
transcode = function(source, fromEncoding, toEncoding) {
// Same encoding
if (fromEncoding === toEncoding) return source;
// Transcode
return toBuffer(source.toString(fromEncoding), toEncoding);
};
}
// Exit messages
const exitMessages = {
1: 'Uncaught Fatal Exception',
3: 'Internal JavaScript Parse Error',
4: 'Internal JavaScript Evaluation Failure',
5: 'Fatal Error',
6: 'Non-function Internal Exception Handler',
7: 'Internal Exception Handler Run-Time Failure',
9: 'Invalid Argument',
10: 'Internal JavaScript Run-Time Failure',
12: 'Invalid Debug Argument'
};
/**
* @function isEmpty
* @description Is object empty
* @param {Object} object
* @returns {boolean}
*/
const isEmpty = object => Object.keys(object).length === 0;
/**
* @function spawn
* @description Spawn a child process and receive output via a Promise interface.
* @param {string} command Command to spawn.
* @param {string[]} args Array of arguments to run command with.
* @param {string|Buffer} input Input to pass command via stdin.
* @param {Object} options Spawn configure
* @returns {Promise} Resolved with buffer of stdout or rejected with error
*/
const spawn = function(command, args, input, options) {
return new Promise((resolve, reject) => {
// Options normalize
options = Object.assign({ encoding: 'utf8', windowsHide: true }, options);
// Vars
const stderrOutput = [];
const encoding = options.encoding;
const errors = Object.create(null);
// Delete options encoding
delete options.encoding;
// Spawn command
const child = childProcess.spawn(command, args, options);
// Capture errors
child.on('error', error => (errors.spawn = error));
child.stdin.on('error', error => (errors.stdin = error));
child.stdout.on('error', error => (errors.stdout = error));
child.stderr.on('error', error => (errors.stderr = error));
child.stderr.on('data', data => stderrOutput.push(data));
// Capture output
const buffers = [];
// Capture data
child.stdout.on('data', data => buffers.push(data));
// Spawn close
child.on('close', exitCode => {
// Exit code not 0
if (exitCode !== 0) {
errors.exitMessage = exitMessages[exitCode];
}
// Stderr output
if (stderrOutput.length) {
errors.process = Buffer.concat(stderrOutput).toString(encoding);
}
// Errors not empty
if (!isEmpty(errors)) {
// Set exit code
errors.exitCode = exitCode;
// Reject error
return reject(Object.assign(new Error(`Spawn ${command} error`), errors));
}
// Resolve data
return resolve(transcode(Buffer.concat(buffers), encoding, 'utf8'));
});
// Send input data
child.stdin.end(input, encoding);
});
};
// Exports
module.exports = spawn;