66 * @author  Pawel Psztyc 
77 */ 
88const  { DependenciesOptions}  =  require ( './dependencies-options' ) ; 
9- const  { exec }  =  require ( 'child_process' ) ; 
9+ const  { spawn }  =  require ( 'child_process' ) ; 
1010const  fs  =  require ( 'fs-extra' ) ; 
1111const  path  =  require ( 'path' ) ; 
1212const  platform  =  process . platform ; 
@@ -112,18 +112,31 @@ class DependendenciesManager {
112112   * Prepares bower command options depending on environment and options. 
113113   * 
114114   * @param  {String } command to execute, what is after `$ bower` 
115-    * @return  {String } Full comand to execute. 
115+    * @return  {object } Object containing the command and arguments 
116+    * - cmd {String} Command to call 
117+    * - args {Array<String>} List of arguments to send to the child process. 
116118   */ 
117-   _prepareBowerCommand ( command )  { 
118-     let   cmd  =  this . commandRoot ; 
119+   _prepareBowerCommand ( ... command )  { 
120+     var   args  =  [ ] ; 
119121    if  ( ! this . opts . verbose )  { 
120-       cmd   +=   '  --quiet'; 
122+       args . push ( ' --quiet') ; 
121123    } 
122124    if  ( this . runningRoot )  { 
123-       cmd   +=   '  --allow-root'; 
125+       args . push ( ' --allow-root') ; 
124126    } 
125-     cmd  +=  ' '  +  command ; 
126-     return  cmd ; 
127+     if  ( command  &&  command . length )  { 
128+       command . forEach ( item  =>  { 
129+         if  ( item  instanceof  Array )  { 
130+           args  =  args . concat ( item ) ; 
131+         }  else  { 
132+           args . push ( item ) ; 
133+         } 
134+       } ) ; 
135+     } 
136+     return  { 
137+       cmd : this . commandRoot , 
138+       args : args 
139+     } ; 
127140  } 
128141  /** 
129142   * Processes dependencies installation. 
@@ -148,7 +161,7 @@ class DependendenciesManager {
148161    return  promise . then ( ( )  =>  { 
149162      this . logger . info ( 'Installing bower dependencies...' ) ; 
150163      let  cmd  =  this . _prepareBowerCommand ( 'install' ) ; 
151-       return  this . exec ( cmd ) ; 
164+       return  this . spawn ( cmd . cmd ,   cmd . args ) ; 
152165    } ) 
153166    . then ( ( )  =>  { 
154167      this . logger . info ( 'Dependencies installed.' ) ; 
@@ -163,14 +176,17 @@ class DependendenciesManager {
163176   * installed. 
164177   */ 
165178  _setBowerCommandRoot ( )  { 
166-     const  localCommand  =  path . join ( '.' ,  'node_modules' ,  '.bin' ,  'bower' ) ; 
179+     var  localCommand  =  path . join ( '.' ,  'node_modules' ,  '.bin' ,  'bower' ) ; 
180+     if  ( isWin )  { 
181+       localCommand  +=  '.cmd' ; 
182+     } 
167183    return  fs . pathExists ( localCommand ) 
168184    . then ( exists  =>  { 
169185      if  ( ! exists )  { 
170186        return  this . _ensureNpmPackage ( ) 
171187        . then ( ( )  =>  { 
172188          this . logger . info ( 'installing bower in '  +  process . cwd ( ) ) ; 
173-           return  this . exec ( 'npm  install  bower' ) ; 
189+           return  this . spawn ( 'npm'  ,   [ ' install' ,   ' bower',   '--no-save' ] ) ; 
174190        } ) ; 
175191      } 
176192    } ) 
@@ -224,43 +240,42 @@ class DependendenciesManager {
224240    if  ( deps . length )  { 
225241      this . logger . info ( 'Installing additional bower dependencies...' ) ; 
226242      this . logger . info ( 'Installing: ' ,  deps ) ; 
227-       let  cmd  =  this . _prepareBowerCommand ( 'install '    +   deps . join ( ' ' ) ) ; 
228-       return  this . exec ( cmd ) ; 
243+       let  cmd  =  this . _prepareBowerCommand ( 'install'  ,   deps ) ; 
244+       return  this . spawn ( cmd . cmd ,   cmd . args ) ; 
229245    } 
230246    return  Promise . resolve ( ) ; 
231247  } 
232248  /** 
233-    * Executea shell command 
234-    * 
249+    * Spawns process and execute task with output printed to the logger. 
235250   * @param  {String } cmd Command to execute 
236-    * @param  {?String } dir A directoy where to execute the command. 
237-    * @return  {Promise } Promise resolves itself if the command was executed 
238-    * successfully and rejects it there was an error. 
251+    * @param  {Array<String> } args Arguments to pass to the command 
252+    * @return  {Promise<String> } A promise resolved to an output of command execution. 
239253   */ 
240-   exec ( cmd ,  dir )  { 
241-     dir  =  dir  ||  undefined ; 
254+   spawn ( cmd ,  args )  { 
255+     args  =  args  ||  [ ] ; 
256+     let  log  =  `Executing command: ${ cmd }   with arguments: ${ args . join ( ' ' ) }   in ${ process . cwd ( ) }  ` ; 
257+     this . logger . info ( log ) ; 
242258    return  new  Promise ( ( resolve ,  reject )  =>  { 
243-       var   opts  =  { } ; 
244-       if   ( dir )   { 
245-          opts . cwd   =   dir ; 
246-       } 
247- 
248-       let  log  =  `Executing command:  ${ cmd } ` ; 
249-       if   ( dir )   { 
250-         log   +=   ` in dir:  ${ dir } ` ; 
251-       } 
252-       this . logger . info ( log ) ; 
253-       exec ( cmd ,   opts ,   ( err ,   stdout ,   stderr )   =>   { 
254-         if   ( err )   { 
255-            let   currentDir   =   opts . cwd   ||   process . cwd ( ) ; 
256-            let   message   =   '  Unable to execute previous command with error: ' ; 
257-            message   +=   err . message . trim ( )   +   '.\n  Was in dir: '   +   currentDir   +   '. stdout: ' ; 
258-            message   +=   stdout   +   '. stderr: '   +   stderr ; 
259-           this . logger . error ( message ) ; 
260-            reject ( new   Error ( err . message . trim ( ) ) ) ; 
261-           return ; 
259+       const   proc  =  spawn ( cmd ,   args ,   { 
260+          shell :  true 
261+       } ) ; 
262+       var   result   =   '' ; 
263+        proc . stdout . on ( 'data' ,   ( data )   =>   { 
264+          let  _res  =  data . toString ( 'utf8' ) ; 
265+          result   +=   _res ; 
266+         this . logger . info ( _res ) ; 
267+       } ) ; 
268+       proc . stderr . on ( 'data' ,   ( data )   =>   { 
269+          let   _res   =   data . toString ( 'utf8' ) ; 
270+         result   +=   _res ; 
271+         this . logger . error ( _res ) ; 
272+       } ) ; 
273+       proc . on ( 'close' ,   ( code )   =>   { 
274+         if   ( code   !==   0 )   { 
275+           reject ( 'Command '   +   cmd   +   ' failde with code '   +   code ) ; 
276+         }   else   { 
277+           resolve ( result ) ; 
262278        } 
263-         resolve ( stdout ) ; 
264279      } ) ; 
265280    } ) ; 
266281  } 
@@ -272,7 +287,7 @@ class DependendenciesManager {
272287    if  ( isWin )  { 
273288      return  Promise . resolve ( false ) ; 
274289    } 
275-     return  this . exec ( 'id  -u' ) 
290+     return  this . spawn ( 'id'  ,   [ ' -u'] ) 
276291    . then ( ( response )  =>  { 
277292      if  ( ! response )  { 
278293        return  false ; 
0 commit comments