Skip to content

Commit

Permalink
abstracted SubProcess into it's own module
Browse files Browse the repository at this point in the history
  • Loading branch information
tedsuo committed Jul 18, 2012
1 parent 731134f commit 7a3b0fb
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 147 deletions.
164 changes: 17 additions & 147 deletions index.js
@@ -1,30 +1,31 @@
// ### requirements
var watch = require('nodewatch'),
_ = require('underscore'),
clc = require('cli-color'),
spawn = require('child_process').spawn,
config = require(process.cwd()+'/dev_mode_config');
config = require(process.cwd()+'/dev_mode_config'),
SubProcess = require(__dirname+'/subprocess');

// ### constants
var CWD = config.cwd || process.cwd();
var WATCH_LIST = config.watch_list || [];
var RECURSIVE_WATCH_LIST = config.recursive_watch_list || [];
var processes = config.processes;
var PROCESS_DEFINITIONS = config.processes || [];

// SubProcess Collection
var processes = [];

// # Main
//
process.nextTick(function(){
// initialze sub-processes
processes.forEach(function(p){
p.process = new SubProcess(p);
PROCESS_DEFINITIONS.forEach(function(p){
p.cwd = p.cwd || CWD;
processes.push(new SubProcess(p));
});

// watch codebase for changes
WATCH_LIST.forEach(function(path){
try{
watch.add(CWD+'/'+path);
} catch(e){
console.dev(e);
console.log(e);
}
});

Expand All @@ -33,148 +34,17 @@ process.nextTick(function(){
try{
watch.add(CWD+'/'+path,true);
} catch(e){
console.dev(e);
console.log(e);
}
});

// if any file changes, restart everything
watch.onChange(function(file,prev,curr){
var file_path = file.slice(CWD.length+1);
processes.forEach(function(p,i){
processes[i].process.restart(file_path);
});
}
);
console.dev('DEV MODE watching codebase for changes');
});


// ## _class_ SubProcess
//
// spawns a restartable child process
//
function SubProcess(o){
// initialize arguments
this.command = o.command || error('o.command required');
this.color = o.color || error('o.color required');
this.name = o.name || error('o.name required');
this.args = o.args || [];
this.options = o.options || {};
this.prompt = o.prompt || this.name;
this.bg_color = o.bg_color;

// child processes seem to work better when they are passed
// process.env
if(this.options.env){
this.options.cwd = this.options.cwd || CWD;
this.options.env = _.extend(this.options.env, process.env);
}

// initialize internal properties
this.node = {};
this.original_args = this.args.slice(0);
this.node_count = 0;

// start the child process unless directed not to
if(o.on_startup !== false){
this.start();
}
}

// ### SubProcess: start()
//
// spawns a child process
//
SubProcess.prototype.start = function (){
var name = this.name + ' ' + this.node_count;
console.dev('DEV MODE starting ' + name);

// run the command as a child process
this.node = spawn(this.command,this.args,_.extend({},this.options));


if(this.node && this.node.stdout){
var self = this;

this.node.stdout.on('data',function(data){
data.toString().split("\n").forEach(function(line){
if(!line) return;
var msg = clc[self.color](self.prompt+': ')+
line+
"\n";
if(self.bg_color) msg = clc[self.bg_color](msg);
process.stdout.write(msg);
});
});

this.node.stderr.on('data',function(data){
data.toString().split("\n").forEach(function(line){
if(!line) return;
var msg = clc[self.color](self.prompt+': ')+
clc.red('ERROR ')+
line+
"\n";
if(self.bg_color) msg = clc[self.bg_color](msg);
process.stderr.write(msg);
})
var file_path = file.slice(CWD.length+1);
processes.forEach(function(p){
p.restart(file_path);
});
});

this.node.on('exit',function(){
console.dev('DEV MODE '+name+' exiting');
console.dev(Date());
self.node.pid = undefined;
});

++this.node_count;
}
};

// ### SubProcess: restart( file_name )
//
// kills the process, re-issues original command, potentially with
// new arguments.
//
SubProcess.prototype.restart = function(file_path){
this.args = this.original_args.slice(0);

// replace [[file_path]] token
this.args.forEach(function(arg,i){
this.args[i] = arg.replace(/\[\[file_path\]\]/gi,file_path);
}.bind(this));

if(this.node.pid){
console.dev('DEV MODE killing '+this.name+' '+this.node_count)
this.node.kill();
this.node.on('exit',function(){
this.start();
}.bind(this));
} else {
this.start();
}
};


// # Helpers
// - dev log
console.dev = function(msg){
var c_width = 80;
var center = function(msg) {
var num_stars = (c_width - (msg.length + 2))/2;
var star_str = '';
_(num_stars).times(function() {
star_str += '*';
});
var log_msg = star_str + ' ' + msg + ' ' + star_str;
while(log_msg.length <= c_width) {
log_msg += '*';
}
return log_msg;
}

console.log(clc.bright.green(center(msg)));
}

// - error
function error(msg){
throw new Error(msg);
}
console.log('DEV MODE watching codebase for changes');
});
132 changes: 132 additions & 0 deletions subprocess.js
@@ -0,0 +1,132 @@
// ### requirements
var _ = require('underscore'),
clc = require('cli-color'),
spawn = require('child_process').spawn;

// ## _class_ SubProcess
//
// spawns a restartable child process with fancy colored output
//
function SubProcess(o){
// initialize stdout attributes
this.name = o.name || error('o.name required');
this.color = o.color || error('o.color required');
this.bg_color = o.bg_color;
this.prompt = clc[this.color]((o.prompt || this.name)+': ');
this.error_prompt = this.prompt+ clc.red('ERROR ');

// initialize proccess attributes
this.command = o.command || error('o.command required');
this.args = o.args || [];
this.cwd = o.cwd;
this.env = _.extend(o.env || {}, process.env);

// initialize internal properties
this.node = {};
this.original_args = this.args.slice(0);
this.restart_count = 0;

// start the child process unless directed not to
if(o.on_startup !== false){
this.start();
}
}

module.exports = SubProcess;

// ### SubProcess: start()
//
// spawns a child process
//
SubProcess.prototype.start = function (){
console.dev('DEV MODE starting ' + this.name + ' ' + this.restart_count);
var self = this;

// run the command as a child process
this.node = spawn(this.command,this.args,{cwd:this.cwd,env:this.env});

this.setup_output_streams();

this.node.on('exit',function(){
console.dev('DEV MODE '+self.name+' '+self.restart_count+' exiting');
console.dev(Date());
self.node.pid = undefined;
});

++this.restart_count;
};

SubProcess.prototype.setup_output_streams = function(){
if(!this.node || !this.node.stdout) return;
var self = this;

this.node.stdout.on('data',function(data){
data.toString().split("\n").forEach(function(line){
if(!line) return;
var msg = self.prompt + line + "\n";
if(self.bg_color) msg = clc[self.bg_color](msg);
process.stdout.write(msg);
});
});

this.node.stderr.on('data',function(data){
data.toString().split("\n").forEach(function(line){
if(!line) return;
var msg = self.error_prompt + line + "\n";
if(self.bg_color) msg = clc[self.bg_color](msg);
process.stderr.write(msg);
})
});
};

// ### SubProcess: restart( file_name )
//
// kills the process, re-issues original command, potentially with
// new arguments.
//
SubProcess.prototype.restart = function(file_path){
this.args = this.original_args.slice(0);

// replace [[file_path]] token
this.args.forEach(function(arg,i){
this.args[i] = arg.replace(/\[\[file_path\]\]/gi,file_path);
}.bind(this));

if(this.node.pid){
console.dev('DEV MODE killing '+this.name+' '+this.restart_count)

this.node.on('exit',function(){
this.start();
}.bind(this));

this.node.kill();
} else {
this.start();
}
};


// # Helpers
// - dev log
console.dev = function(msg){
var c_width = 80;
var center = function(msg) {
var num_stars = (c_width - (msg.length + 2))/2;
var star_str = '';
_(num_stars).times(function() {
star_str += '*';
});
var log_msg = star_str + ' ' + msg + ' ' + star_str;
while(log_msg.length <= c_width) {
log_msg += '*';
}
return log_msg;
}

console.log(clc.bright.green(center(msg)));
}

// - error
function error(msg){
throw new Error(msg);
}

0 comments on commit 7a3b0fb

Please sign in to comment.