From a1546bc8a6e2ecc5e18b52740c7c474c5600e1aa Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 22 Aug 2017 23:49:13 -0700 Subject: [PATCH 1/5] Add 'encoding' option to shell.exec --- src/exec.js | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/exec.js b/src/exec.js index 6a2e1261..8054c4be 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,11 @@ 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 set + // the encoding only if opts.encoding wasn't set to 'buffer' + var encoding = opts.encoding !== 'buffer' ? opts.encoding : null; + var stdout = fs.readFileSync(stdoutFile, encoding); + var stderr = fs.readFileSync(stderrFile, 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 +126,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,15 +150,10 @@ 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; } From b4375f4bd74acc19774512a6b96b9d8b5b998bb3 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Tue, 22 Aug 2017 23:55:55 -0700 Subject: [PATCH 2/5] Add 'encoding' option to docs --- README.md | 8 +++++--- src/exec.js | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) 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 8054c4be..816a1a38 100644 --- a/src/exec.js +++ b/src/exec.js @@ -160,11 +160,13 @@ function execAsync(cmd, opts, pipe, callback) { //@ //@ ### 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) //@ From e87bbc10ba69dc1c459a9dcfd5b53ca39abecc15 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 23 Aug 2017 00:01:51 -0700 Subject: [PATCH 3/5] Add exec encoding option tests --- test/exec.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/exec.js b/test/exec.js index e2e8bd1c..06d10608 100644 --- a/test/exec.js +++ b/test/exec.js @@ -163,6 +163,14 @@ 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.is(result.stdout.toString(), '1234\n'); +}); + // // async // @@ -209,3 +217,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(); + }); +}); From 2c9b363ddb7e27e593f348470f281a31df699ea4 Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 23 Aug 2017 19:23:15 -0700 Subject: [PATCH 4/5] Clarify use of encoding with fs.readFileSync --- src/exec.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/exec.js b/src/exec.js index 816a1a38..d425b5b2 100644 --- a/src/exec.js +++ b/src/exec.js @@ -105,11 +105,17 @@ function execSync(cmd, opts, pipe) { code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10); } - // fs.readFileSync uses buffer encoding by default, so set - // the encoding only if opts.encoding wasn't set to 'buffer' - var encoding = opts.encoding !== 'buffer' ? opts.encoding : null; - var stdout = fs.readFileSync(stdoutFile, encoding); - var stderr = fs.readFileSync(stderrFile, encoding); + // 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) {} From 0e0994b0738297e5477196e3ffa8a10102545b4e Mon Sep 17 00:00:00 2001 From: Brandon Freitag Date: Wed, 23 Aug 2017 19:25:02 -0700 Subject: [PATCH 5/5] Add check for stderr buffer --- test/exec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/exec.js b/test/exec.js index 06d10608..3c73d361 100644 --- a/test/exec.js +++ b/test/exec.js @@ -168,7 +168,9 @@ test('encoding option works', t => { 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(), ''); }); //