Created
October 5, 2010 15:41
-
-
Save fgnass/611749 to your computer and use it in GitHub Desktop.
Supervisor for node.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Node.js supervisor that spawns a node child-process and restarts it when changes are detected | |
| * in the filesystem. If the child-process exits due to an error, the supervisor waits for another | |
| * modification before it attempts to re-spawn it. The output written to stderr is captured and | |
| * scanned for stack-traces. If an error is detected it is displayed as Growl notification. | |
| */ | |
| var fs = require('fs'), | |
| sys = require('sys'), | |
| path = require('path'), | |
| http = require('http'), | |
| child_process = require('child_process'), | |
| server = null, | |
| error = '', | |
| files = [], | |
| args = [].concat(process.argv), | |
| cmd = args.shift(); | |
| args.shift(); | |
| /** | |
| * Spawns a node child-process. | |
| */ | |
| function start(title, msg) { | |
| watchFiles(); | |
| server = child_process.spawn(cmd, args); | |
| notify(msg || 'Started', title); | |
| server.addListener('exit', function (code, signal) { | |
| server = null; | |
| }); | |
| // Print data written to stdout | |
| server.stdout.addListener('data', function(data) { | |
| process.stdout.write(data); | |
| }); | |
| // Data sent to stderr is scanned for stack-traces ... | |
| server.stderr.addListener('data', function(data) { | |
| var s = new String(data), stack, src, m, file, line, col; | |
| sys.print(data); | |
| error += s; | |
| stack = s.match(/^(.+)\n\s+at.+\((.*?):(\d+):(\d+)/); | |
| if (stack) { | |
| // file:line | |
| // source-code | |
| // ^^^^^ | |
| // ErrorType: Message | |
| src = error.match(/^\s*(.+):(\d+)\n(.*)\n(\s*)\^/); | |
| if (src && !src[3].match(/throw/)) { | |
| file = src[1]; | |
| line = src[2]; | |
| col = src[4].length; | |
| } | |
| else { | |
| // No source-code or error was rethrown | |
| file = stack[2]; | |
| line = stack[3]; | |
| col = stack[4]; | |
| } | |
| notify(file + ',' + line + ':' + col, stack[1], 'error'); | |
| error = ''; | |
| } | |
| }); | |
| } | |
| /** | |
| * Watches all .js files and restarts the server if a modification is detected. | |
| */ | |
| function watchFiles() { | |
| files.forEach(fs.unwatchFile); | |
| files = []; | |
| walk(__dirname, function(file) { | |
| files.push(file); | |
| fs.watchFile(file, {interval : 500}, function(curr, prev) { | |
| if (curr.mtime.valueOf() != prev.mtime.valueOf() || curr.ctime.valueOf() != prev.ctime.valueOf()) { | |
| if (server) { | |
| server.addListener('exit', function (code, signal) { | |
| if (signal) { | |
| start('Restarting', 'File modified: ' + file); | |
| } | |
| }); | |
| server.kill(); | |
| } | |
| else { | |
| start(); | |
| } | |
| } | |
| }); | |
| }); | |
| } | |
| function walk(filename, callback) { | |
| fs.stat(filename, function(err, stats) { | |
| if(stats.isFile() && filename.match(/\.js$/)) { | |
| callback(filename); | |
| } | |
| else if(stats.isDirectory()) { | |
| fs.readdir(filename, function(err, files) { | |
| files.forEach(function(f) { | |
| walk(filename + '/' + f, callback); | |
| }); | |
| }); | |
| } | |
| }); | |
| } | |
| /** | |
| * Displays a message as Growl notification. | |
| * Requires http://growl.info/extras.php#growlnotify | |
| */ | |
| function notify(msg, title, icon) { | |
| icons[icon || 'green'].get(function(path) { | |
| child_process.spawn('growlnotify', [ | |
| '-m', msg, | |
| '--image', path, | |
| title || 'node.js']); | |
| }); | |
| } | |
| var icons = { | |
| green: new Gist('6a64dc22047197dd840a92a08fa89517a73bbdd9', 'node_green.png'), | |
| error: new Gist('84497b6c3fff14273cd39bc860a29b364188919c', 'node_red.png') | |
| }; | |
| function Gist(sha, name) { | |
| var file = path.join(process.env.TMPDIR, name); | |
| this.get = function(callback) { | |
| path.exists(file, function(exists) { | |
| if (exists) { | |
| callback(file); | |
| } | |
| else { | |
| download(callback); | |
| } | |
| }); | |
| }; | |
| function download(callback) { | |
| var fd = fs.openSync(file, 'w'); | |
| var gist = http.createClient(80, 'gist.github.com'); | |
| var request = gist.request('GET', '/raw/611749/' + sha + '/' + name, { | |
| host: 'gist.github.com' | |
| }); | |
| request.end(); | |
| request.on('response', function (response) { | |
| response.on('data', function (chunk) { | |
| fs.writeSync(fd, chunk, 0, chunk.length); | |
| }); | |
| response.on('end', function () { | |
| fs.closeSync(fd); | |
| callback(file); | |
| }); | |
| }); | |
| } | |
| } | |
| start(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment


Please go to https://github.com/fgnass/node-dev