nl_tokens: Hack to run child_process . exec () synchronously ( sync avoids callback hell ) Uses a custom wait loop that checks for a flag file created when the child process is done . ( Can t do a wait loop that checks for internal Node variables / messages as Node is single - threaded ; callbacks and other internal state changes are done in the event loop ) .
pl_tokens: function execSync ( cmd , opts ) { var tempDir = _tempDir ( ) ; var stdoutFile = path . resolve ( tempDir + '/' + common . randomFileName ( ) ) , codeFile = path . resolve ( tempDir + '/' + common . randomFileName ( ) ) , scriptFile = path . resolve ( tempDir + '/' + common . randomFileName ( ) ) , sleepFile = path . resolve ( tempDir + '/' + common . randomFileName ( ) ) ; var options = common . extend ( { silent : common . config . silent } , opts ) ; var previousStdoutContent = '' ; // Echoes stdout changes from running process, if not silent function updateStdout ( ) { if ( options . silent || ! fs . existsSync ( stdoutFile ) ) return ; var stdoutContent = fs . readFileSync ( stdoutFile , 'utf8' ) ; // No changes since last time? if ( stdoutContent . length <= previousStdoutContent . length ) return ; process . stdout . write ( stdoutContent . substr ( previousStdoutContent . length ) ) ; previousStdoutContent = stdoutContent ; } function escape ( str ) { return ( str + '' ) . replace ( / ([\\"']) / g , "\\$1" ) . replace ( / \0 / g , "\\0" ) ; } if ( fs . existsSync ( scriptFile ) ) common . unlinkSync ( scriptFile ) ; if ( fs . existsSync ( stdoutFile ) ) common . unlinkSync ( stdoutFile ) ; if ( fs . existsSync ( codeFile ) ) common . unlinkSync ( codeFile ) ; var execCommand = '"' + <mask> . execPath + '" ' + scriptFile ; var execOptions = { env : process . env , cwd : _pwd ( ) , maxBuffer : 20 * 1024 * 1024 } ; if ( typeof child . execSync === 'function' ) { var script = [ "var child = require('child_process')" , "  , fs = require('fs');" , "var childProcess = child.exec('" + escape ( cmd ) + "', {env: process.env, maxBuffer: 20*1024*1024}, function(err) {" , "  fs.writeFileSync('" + escape ( codeFile ) + "', err ? err.code.toString() : '0');" , "});" , "var stdoutStream = fs.createWriteStream('" + escape ( stdoutFile ) + "');" , "childProcess.stdout.pipe(stdoutStream, {end: false});" , "childProcess.stderr.pipe(stdoutStream, {end: false});" , "childProcess.stdout.pipe(process.stdout);" , "childProcess.stderr.pipe(process.stderr);" , "var stdoutEnded = false, stderrEnded = false;" , "function tryClosing(){ if(stdoutEnded && stderrEnded){ stdoutStream.end(); } }" , "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosing(); });" , "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosing(); });" ] . join ( '\n' ) ; fs . writeFileSync ( scriptFile , script ) ; if ( options . silent ) { execOptions . stdio = 'ignore' ; } else { execOptions . stdio = [ 0 , 1 , 2 ] ; } // Welcome to the future child . execSync ( execCommand , execOptions ) ; } else { cmd += ' > ' + stdoutFile + ' 2>&1' ; // works on both win/unix var script = [ "var child = require('child_process')" , "  , fs = require('fs');" , "var childProcess = child.exec('" + escape ( cmd ) + "', {env: process.env, maxBuffer: 20*1024*1024}, function(err) {" , "  fs.writeFileSync('" + escape ( codeFile ) + "', err ? err.code.toString() : '0');" , "});" ] . join ( '\n' ) ; fs . writeFileSync ( scriptFile , script ) ; child . exec ( execCommand , execOptions ) ; // The wait loop // sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage // (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing // CPU usage, though apparently not so much on Windows) while ( ! fs . existsSync ( codeFile ) ) { updateStdout ( ) ; fs . writeFileSync ( sleepFile , 'a' ) ; } while ( ! fs . existsSync ( stdoutFile ) ) { updateStdout ( ) ; fs . writeFileSync ( sleepFile , 'a' ) ; } } // At this point codeFile exists, but it's not necessarily flushed yet. // Keep reading it until it is. var code = parseInt ( '' , 10 ) ; while ( isNaN ( code ) ) { code = parseInt ( fs . readFileSync ( codeFile , 'utf8' ) , 10 ) ; } var stdout = fs . readFileSync ( stdoutFile , 'utf8' ) ; // No biggie if we can't erase the files now -- they're in a temp dir anyway try { common . unlinkSync ( scriptFile ) ; } catch ( e ) { } try { common . unlinkSync ( stdoutFile ) ; } catch ( e ) { } try { common . unlinkSync ( codeFile ) ; } catch ( e ) { } try { common . unlinkSync ( sleepFile ) ; } catch ( e ) { } // some shell return codes are defined as errors, per http://tldp.org/LDP/abs/html/exitcodes.html if ( code === 1 || code === 2 || code >= 126 ) { common . error ( '' , true ) ; // unix/shell doesn't really give an error message after non-zero exit codes } // True if successful, false if not var obj = { code : code , output : stdout } ; return obj ; }