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. | |
| */ | |
| var fs = require('fs'), | |
| sys = require('sys'), | |
| path = require('path'), | |
| http = require('http'), | |
| child_process = require('child_process'), | |
| server = null, | |
| error = '', | |
| files = []; | |
| function restart() { | |
| if (server) { | |
| server.kill(); | |
| } | |
| else { | |
| unwatchFiles(); | |
| start(); | |
| } | |
| } | |
| /** | |
| * Spawns a node child-process using the same script name, without the leading dev_ prefix. | |
| */ | |
| function start() { | |
| watchFiles(); | |
| server = child_process.spawn(process.ARGV[0], ['--debug', __filename.replace('dev_', '')]); | |
| // 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 = ''; | |
| } | |
| }); | |
| server.addListener('exit', function (code, signal) { | |
| server = null; | |
| if (signal) { | |
| // If killed via signal, restart the server | |
| restart(); | |
| } | |
| }); | |
| } | |
| /** | |
| * Watches all .js files and restarts the server if a modification is detected. | |
| */ | |
| function watchFiles() { | |
| 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()) { | |
| notify('File modified: ' + file, 'Restarting'); | |
| restart(); | |
| } | |
| }); | |
| }); | |
| } | |
| /** | |
| * Unwatches all previously watched files. | |
| */ | |
| function unwatchFiles() { | |
| files.forEach(fs.unwatchFile); | |
| files = []; | |
| } | |
| 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. | |
| */ | |
| 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