Skip to content

Commit

Permalink
Fix: use async reading of stdin in bin/eslint.js (fixes #12212) (#12230)
Browse files Browse the repository at this point in the history
  • Loading branch information
baerrach authored and mysticatea committed Sep 29, 2019
1 parent 334ca7c commit d89390b
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 5 deletions.
37 changes: 32 additions & 5 deletions bin/eslint.js
Expand Up @@ -59,13 +59,40 @@ process.once("uncaughtException", err => {
if (useStdIn) {

/*
* Note: `process.stdin.fd` is not used here due to https://github.com/nodejs/node/issues/7439.
* Accessing the `process.stdin` property seems to modify the behavior of file descriptor 0, resulting
* in an error when stdin is piped in asynchronously.
* Note: See
* - https://github.com/nodejs/node/blob/master/doc/api/process.md#processstdin
* - https://github.com/nodejs/node/blob/master/doc/api/process.md#a-note-on-process-io
* - https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-01/msg00419.html
* - https://github.com/nodejs/node/issues/7439 (historical)
*
* On Windows using `fs.readFileSync(STDIN_FILE_DESCRIPTOR, "utf8")` seems
* to read 4096 bytes before blocking and never drains to read further data.
*
* The investigation on the Emacs thread indicates:
*
* > Emacs on MS-Windows uses pipes to communicate with subprocesses; a
* > pipe on Windows has a 4K buffer. So as soon as Emacs writes more than
* > 4096 bytes to the pipe, the pipe becomes full, and Emacs then waits for
* > the subprocess to read its end of the pipe, at which time Emacs will
* > write the rest of the stuff.
*
* Using the nodejs code example for reading from stdin.
*/
const STDIN_FILE_DESCRIPTOR = 0;
let contents = "",
chunk = "";

process.exitCode = cli.execute(process.argv, fs.readFileSync(STDIN_FILE_DESCRIPTOR, "utf8"));
process.stdin.setEncoding("utf8");
process.stdin.on("readable", () => {

// Use a loop to make sure we read all available data.
while ((chunk = process.stdin.read()) !== null) {
contents += chunk;
}
});

process.stdin.on("end", () => {
process.exitCode = cli.execute(process.argv, contents, "utf8");
});
} else if (init) {
const configInit = require("../lib/init/config-initializer");

Expand Down
9 changes: 9 additions & 0 deletions tests/bin/eslint.js
Expand Up @@ -163,6 +163,15 @@ describe("bin/eslint.js", () => {
return assertExitCode(child, 0);
});
});

it("successfully handles more than 4k data via stdin", () => {
const child = runESLint(["--stdin", "--no-eslintrc"]);
const large = fs.createReadStream(`${__dirname}/../bench/large.js`, "utf8");

large.pipe(child.stdin);

return assertExitCode(child, 0);
});
});

describe("running on files", () => {
Expand Down

0 comments on commit d89390b

Please sign in to comment.