Add "encoding" option to exec (#763)

* Add 'encoding' option to shell.exec

* Add 'encoding' option to docs

* Add exec encoding option tests

* Clarify use of encoding with fs.readFileSync

* Add check for stderr buffer
This commit is contained in:
Brandon Freitag 2017-09-13 16:18:28 -07:00 committed by GitHub
parent c7d65ac590
commit dcead1be86
3 changed files with 49 additions and 21 deletions

View File

@ -273,11 +273,13 @@ like `.to()`.
### exec(command [, options] [, callback])
Available options (all `false` by default):
Available options:
+ `async`: Asynchronous execution. If a callback is provided, it will be set to
`true`, regardless of the passed value.
+ `silent`: Do not echo program output to console.
`true`, regardless of the passed value (default: `false`).
+ `silent`: Do not echo program output to console (default: `false`).
+ `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and
what is written to stdout and stderr when not in silent mode (default: `'utf8'`).
+ and any option available to Node.js's
[child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)

View File

@ -34,6 +34,7 @@ function execSync(cmd, opts, pipe) {
cwd: _pwd().toString(),
env: process.env,
maxBuffer: DEFAULT_MAXBUFFER_SIZE,
encoding: 'utf8',
}, opts);
if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile);
@ -104,8 +105,17 @@ function execSync(cmd, opts, pipe) {
code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10);
}
var stdout = fs.readFileSync(stdoutFile, 'utf8');
var stderr = fs.readFileSync(stderrFile, 'utf8');
// fs.readFileSync uses buffer encoding by default, so call
// it without the encoding option if the encoding is 'buffer'
var stdout;
var stderr;
if (opts.encoding === 'buffer') {
stdout = fs.readFileSync(stdoutFile);
stderr = fs.readFileSync(stderrFile);
} else {
stdout = fs.readFileSync(stdoutFile, opts.encoding);
stderr = fs.readFileSync(stderrFile, opts.encoding);
}
// No biggie if we can't erase the files now -- they're in a temp dir anyway
try { common.unlinkSync(scriptFile); } catch (e) {}
@ -122,17 +132,15 @@ function execSync(cmd, opts, pipe) {
// Wrapper around exec() to enable echoing output to console in real time
function execAsync(cmd, opts, pipe, callback) {
var stdout = '';
var stderr = '';
opts = common.extend({
silent: common.config.silent,
cwd: _pwd().toString(),
env: process.env,
maxBuffer: DEFAULT_MAXBUFFER_SIZE,
encoding: 'utf8',
}, opts);
var c = child.exec(cmd, opts, function (err) {
var c = child.exec(cmd, opts, function (err, stdout, stderr) {
if (callback) {
if (!err) {
callback(0, stdout, stderr);
@ -148,26 +156,23 @@ function execAsync(cmd, opts, pipe, callback) {
if (pipe) c.stdin.end(pipe);
c.stdout.on('data', function (data) {
stdout += data;
if (!opts.silent) process.stdout.write(data);
});
c.stderr.on('data', function (data) {
stderr += data;
if (!opts.silent) process.stderr.write(data);
});
if (!opts.silent) {
c.stdout.pipe(process.stdout);
c.stderr.pipe(process.stderr);
}
return c;
}
//@
//@ ### exec(command [, options] [, callback])
//@ Available options (all `false` by default):
//@ Available options:
//@
//@ + `async`: Asynchronous execution. If a callback is provided, it will be set to
//@ `true`, regardless of the passed value.
//@ + `silent`: Do not echo program output to console.
//@ `true`, regardless of the passed value (default: `false`).
//@ + `silent`: Do not echo program output to console (default: `false`).
//@ + `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and
//@ what is written to stdout and stderr when not in silent mode (default: `'utf8'`).
//@ + and any option available to Node.js's
//@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)
//@

View File

@ -163,6 +163,16 @@ test('exec returns a ShellString', t => {
t.is(result.toString(), result.stdout);
});
test('encoding option works', t => {
const result = shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(1234);"`, { encoding: 'buffer' });
t.falsy(shell.error());
t.is(result.code, 0);
t.truthy(Buffer.isBuffer(result.stdout));
t.truthy(Buffer.isBuffer(result.stderr));
t.is(result.stdout.toString(), '1234\n');
t.is(result.stderr.toString(), '');
});
//
// async
//
@ -209,3 +219,14 @@ test.cb('command that fails', t => {
t.end();
});
});
test.cb('encoding option works with async', t => {
shell.exec(`${JSON.stringify(shell.config.execPath)} -e "console.log(5566);"`, { async: true, encoding: 'buffer' }, (code, stdout, stderr) => {
t.is(code, 0);
t.truthy(Buffer.isBuffer(stdout));
t.truthy(Buffer.isBuffer(stderr));
t.is(stdout.toString(), '5566\n');
t.is(stderr.toString(), '');
t.end();
});
});