UNPKG

bricks-cli

Version:

Command line tool for developing ambitious ember.js apps

172 lines (162 loc) 4.61 kB
var child_process = require('child_process') var EventEmitter = require('events').EventEmitter var log = require('npmlog') var fileutils = require('./fileutils') var async = require('async') var ProcessRunner = require('./process_runner') var template = require('./strutils').template function Launcher(name, settings, config){ this.name = name this.config = config this.settings = settings this.setupDefaultSettings() this.id = String(Math.floor(Math.random() * 10000)) } Launcher.prototype = { __proto__: EventEmitter.prototype , setupDefaultSettings: function(){ var settings = this.settings if (settings.protocol === 'tap' && !('hide_stdout' in settings)){ settings.hide_stdout = true } } , isProcess: function(){ return this.settings.protocol !== 'browser' } , protocol: function(){ return this.settings.protocol || 'process' } , commandLine: function(){ if (this.settings.command){ return '"' + this.settings.command + '"' }else if (this.settings.exe){ return '"' + this.settings.exe + ' ' + this.getArgs().join(' ') + '"' } } , start: function(){ if (this.isProcess()){ var self = this self.runner = new ProcessRunner({ launcher: self }) }else{ this.launch() } } , getUrl: function(){ return this.config.get('url') + this.id } , launch: function(cb){ var self = this var settings = this.settings this.kill('SIGTERM', function(){ if (settings.setup){ settings.setup.call(self, self.config, function(){ self.doLaunch(cb) }) }else{ self.doLaunch(cb) } }) } , doLaunch: function(cb){ var id = this.id var config = this.config var settings = this.settings var self = this var options = {} if (settings.cwd) options.cwd = settings.cwd if (settings.exe){ function spawn(exe){ args = self.template(args, id) log.info('spawning: ' + exe + ' - ' + JSON.stringify(args)) self.process = child_process.spawn(exe, args, options) self.stdout = '' self.stderr = '' self.process.stdout.on('data', function(chunk){ self.stdout += chunk }) self.process.stderr.on('data', function(chunk){ self.stderr += chunk }) self.process.once('close', self.onClose.bind(self)) self.emit('processStarted', self.process) if (cb) cb(self.process) } var args = self.getArgs() if (Array.isArray(settings.exe)){ async.filter(settings.exe, self.exeExists, function(found){ spawn(found[0]) }) }else{ spawn(settings.exe) } }else if (settings.command){ var self = this var cmd = this.template(settings.command, id) log.info('cmd: ' + cmd) this.process = child_process.exec(cmd, options, function(err, stdout, stderr){ self.stdout = stdout self.stderr = stderr }) this.process.on('close', self.onClose.bind(self)) self.emit('processStarted', self.process) if (cb) cb(self.process) } } , getArgs: function(){ var settings = this.settings var url = this.config.get('url') + this.id var args = [url] if (settings.args instanceof Array) args = settings.args.concat(args) else if (settings.args instanceof Function){ args = settings.args.call(this, this.config) } return args } , template: function(thing, id){ if (Array.isArray(thing)){ return thing.map(this.template, this) }else{ var params = { url: this.config.get('url') + id, port: this.config.get('port') } return template(thing, params) } } , exeExists: function(exe, cb){ fileutils.fileExists(exe, function(yes){ if (yes) return cb(true) else fileutils.which(exe, function(yes){ if (yes) return cb(true) else fileutils.where(exe, cb) }) }) } , onClose: function(code){ this.exitCode = code this.emit('processExit', code, this.stdout, this.stderr) this.process = null } , kill: function(sig, cb){ if (!this.process){ if(cb) cb(this.exitCode) return } var process = this.process sig = sig || 'SIGTERM' var exited = false process.on('close', function(code, sig){ exited = true process.stdout.removeAllListeners() process.stderr.removeAllListeners() process.removeAllListeners() if (cb) cb() }) process.kill(sig) } } module.exports = Launcher