Skip to content

Commit 756c602

Browse files
nmotefacebook-github-bot
authored andcommitted
Add support for passing stdin contents to exec
Reviewed By: gabelevi Differential Revision: D5906702 fbshipit-source-id: e65cd3e8bd89e3ef183559811031c5508c47d1bd
1 parent fe83935 commit 756c602

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

tsrc/utils/async.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,43 @@ import {glob as glob_glob} from 'glob';
1818
import mkdirp_mkdirp from 'mkdirp';
1919
import rimraf_rimraf from 'rimraf';
2020

21+
import {splitIntoChunks} from './string';
22+
2123
import type {ReadStream, WriteStream} from 'fs';
2224

23-
export function exec(cmd: string, options?: Object): Promise<string> {
25+
export type ExecOpts = child_process$execOpts & {
26+
stdin?: string,
27+
}
28+
29+
// Based on nothing but a few experiments on my laptop, this seems like a pretty safe size.
30+
const STDIN_WRITE_CHUNK_SIZE = 10000;
31+
32+
export function exec(cmd: string, options?: ExecOpts): Promise<string> {
2433
return new Promise((resolve, reject) => {
25-
cp_exec(cmd, options, (err, stdout, stderr) => {
34+
const cp = cp_exec(cmd, options, (err, stdout, stderr) => {
2635
if (err == null) {
2736
resolve(stdout.toString());
2837
} else {
2938
reject([err, stdout, stderr]);
3039
}
31-
})
40+
});
41+
if (options != null && options.stdin != null) {
42+
// If we just write a giant string it can lead to a crash
43+
const chunks = splitIntoChunks(options.stdin, STDIN_WRITE_CHUNK_SIZE);
44+
const write = (chunkIndex: number) => {
45+
if (chunkIndex >= chunks.length) {
46+
cp.stdin.end();
47+
return;
48+
}
49+
const canContinue = cp.stdin.write(chunks[chunkIndex]);
50+
if (canContinue) {
51+
write(chunkIndex + 1);
52+
} else {
53+
cp.stdin.once('drain', () => write(chunkIndex + 1));
54+
}
55+
};
56+
write(0);
57+
}
3258
});
3359
}
3460

tsrc/utils/async.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {exec} from './async';
2+
3+
function repeatString(str, times) {
4+
let result = '';
5+
for (let i = 0; i < times; i++) {
6+
result += str;
7+
}
8+
return result;
9+
}
10+
11+
test('exec', async () => {
12+
expect(await exec('echo foo')).toBe('foo\n');
13+
expect(await exec('cat', {stdin: 'bar'})).toBe('bar');
14+
15+
expect(repeatString('foo', 2)).toBe('foofoo');
16+
17+
// make the string big enough that it exceeds the chunk size for writes
18+
const repeatedString = repeatString('0123456789', 2000);
19+
expect(await exec('cat', {stdin: repeatedString})).toBe(repeatedString);
20+
});

0 commit comments

Comments
 (0)