@@ -4,6 +4,15 @@ import spec = require('jsii-spec');
44import path = require( 'path' ) ;
55import logging = require( './logging' ) ;
66
7+ export interface ShellOptions extends SpawnOptions {
8+ /**
9+ * Retry execution up to 3 times if it fails
10+ *
11+ * @default false
12+ */
13+ retry ?: boolean ;
14+ }
15+
716/**
817 * Given an npm package directory and a dependency name, returns the package directory of the dep.
918 * @param packageDir the root of the package declaring the dependency.
@@ -15,33 +24,51 @@ export function resolveDependencyDirectory(packageDir: string, dependencyName: s
1524 return path . dirname ( require . resolve ( `${ dependencyName } /package.json` , { paths : lookupPaths } ) ) ;
1625}
1726
18- export function shell ( cmd : string , args : string [ ] , options : SpawnOptions ) : Promise < string > {
19- return new Promise < string > ( ( resolve , reject ) => {
20- logging . debug ( cmd , args . join ( ' ' ) , JSON . stringify ( options ) ) ;
21- const child = spawn ( cmd , args , { ...options , shell : true , env : { ...process . env , ...options . env || { } } , stdio : [ 'ignore' , 'pipe' , 'pipe' ] } ) ;
22- const stdout = new Array < Buffer > ( ) ;
23- const stderr = new Array < Buffer > ( ) ;
24- child . stdout . on ( 'data' , chunk => {
25- if ( logging . level >= logging . LEVEL_VERBOSE ) {
26- process . stderr . write ( chunk ) ; // notice - we emit all build output to stderr
27- }
28- stdout . push ( Buffer . from ( chunk ) ) ;
29- } ) ;
30- child . stderr . on ( 'data' , chunk => {
31- if ( logging . level >= logging . LEVEL_VERBOSE ) {
32- process . stderr . write ( chunk ) ;
33- }
34- stderr . push ( Buffer . from ( chunk ) ) ;
35- } ) ;
36- child . once ( 'error' , reject ) ;
37- child . once ( 'exit' , ( code , signal ) => {
38- const out = Buffer . concat ( stdout ) . toString ( 'utf-8' ) ;
39- if ( code === 0 ) { return resolve ( out ) ; }
40- const err = Buffer . concat ( stderr ) . toString ( 'utf-8' ) ;
41- if ( code != null ) { return reject ( new Error ( `Process exited with status ${ code } \n${ out } \n${ err } ` ) ) ; }
42- reject ( new Error ( `Process terminated by signal ${ signal } \n${ out } \n${ err } ` ) ) ;
27+ export async function shell ( cmd : string , args : string [ ] , options : ShellOptions ) : Promise < string > {
28+ function spawn1 ( ) {
29+ return new Promise < string > ( ( resolve , reject ) => {
30+ logging . debug ( cmd , args . join ( ' ' ) , JSON . stringify ( options ) ) ;
31+ const child = spawn ( cmd , args , {
32+ ...options ,
33+ shell : true ,
34+ env : { ...process . env , ...options . env || { } } ,
35+ stdio : [ 'ignore' , 'pipe' , 'pipe' ]
36+ } ) ;
37+ const stdout = new Array < Buffer > ( ) ;
38+ const stderr = new Array < Buffer > ( ) ;
39+ child . stdout . on ( 'data' , chunk => {
40+ if ( logging . level >= logging . LEVEL_VERBOSE ) {
41+ process . stderr . write ( chunk ) ; // notice - we emit all build output to stderr
42+ }
43+ stdout . push ( Buffer . from ( chunk ) ) ;
44+ } ) ;
45+ child . stderr . on ( 'data' , chunk => {
46+ if ( logging . level >= logging . LEVEL_VERBOSE ) {
47+ process . stderr . write ( chunk ) ;
48+ }
49+ stderr . push ( Buffer . from ( chunk ) ) ;
50+ } ) ;
51+ child . once ( 'error' , reject ) ;
52+ child . once ( 'exit' , ( code , signal ) => {
53+ const out = Buffer . concat ( stdout ) . toString ( 'utf-8' ) ;
54+ if ( code === 0 ) { return resolve ( out ) ; }
55+ const err = Buffer . concat ( stderr ) . toString ( 'utf-8' ) ;
56+ if ( code != null ) { return reject ( new Error ( `Process exited with status ${ code } \n${ out } \n${ err } ` ) ) ; }
57+ reject ( new Error ( `Process terminated by signal ${ signal } \n${ out } \n${ err } ` ) ) ;
58+ } ) ;
4359 } ) ;
44- } ) ;
60+ }
61+
62+ let attempts = options . retry ? 3 : 1 ;
63+ while ( true ) {
64+ attempts -- ;
65+ try {
66+ return spawn1 ( ) ;
67+ } catch ( e ) {
68+ if ( attempts === 0 ) { throw e ; }
69+ logging . info ( `${ e . message } (retrying)` ) ;
70+ }
71+ }
4572}
4673
4774/**
0 commit comments