@@ -18,17 +18,43 @@ import {glob as glob_glob} from 'glob';
18
18
import mkdirp_mkdirp from 'mkdirp' ;
19
19
import rimraf_rimraf from 'rimraf' ;
20
20
21
+ import { splitIntoChunks } from './string' ;
22
+
21
23
import type { ReadStream , WriteStream } from 'fs' ;
22
24
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 > {
24
33
return new Promise ( ( resolve , reject ) => {
25
- cp_exec ( cmd , options , ( err , stdout , stderr ) => {
34
+ const cp = cp_exec ( cmd , options , ( err , stdout , stderr ) => {
26
35
if ( err == null ) {
27
36
resolve ( stdout . toString ( ) ) ;
28
37
} else {
29
38
reject ( [ err , stdout , stderr ] ) ;
30
39
}
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
+ }
32
58
} ) ;
33
59
}
34
60
0 commit comments