diff --git a/README.md b/README.md index 51082f47..479fea71 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/src/exec.js b/src/exec.js index 6a2e1261..d425b5b2 100644 --- a/src/exec.js +++ b/src/exec.js @@ -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) //@ diff --git a/test/exec.js b/test/exec.js index e2e8bd1c..3c73d361 100644 --- a/test/exec.js +++ b/test/exec.js @@ -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(); + }); +});