Skip to content

Instantly share code, notes, and snippets.

@fgnass
Created October 5, 2010 15:41
Show Gist options
  • Select an option

  • Save fgnass/611749 to your computer and use it in GitHub Desktop.

Select an option

Save fgnass/611749 to your computer and use it in GitHub Desktop.

Revisions

  1. Felix Gnass revised this gist Oct 14, 2010. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,5 @@
    The node-dev supervisor has a new home:
    https://github.com/fgnass/node-dev
    # This project has moved!

    You may also install it directly via npm:
    The node-dev supervisor has a new home:
    [https://github.com/fgnass/node-dev](https://github.com/fgnass/node-dev)

    npm install node-dev
  2. Felix Gnass revised this gist Oct 14, 2010. 4 changed files with 6 additions and 166 deletions.
    6 changes: 6 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    The node-dev supervisor has a new home:
    https://github.com/fgnass/node-dev

    You may also install it directly via npm:

    npm install node-dev
    166 changes: 0 additions & 166 deletions dev
    Original file line number Diff line number Diff line change
    @@ -1,166 +0,0 @@
    /**
    * 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.
    *
    * Author: Felix Gnass [fgnass at neteye dot de]
    * License: MIT
    * See http://gist.github.com/611749
    */
    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 = data.toString(), stack, src, m, file, line, col;

    sys.print(data);
    error += s;

    stack = s.match(/^(.+): (.*)\n\s+at.+\((.*?):(\d+):(\d+)/m);
    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[3];
    line = stack[4];
    col = stack[5];
    }

    notify(stack[2] + '\n @' + 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) {
    var stats = fs.statSync(filename);
    if(stats.isFile() && filename.match(/\.js$/)) {
    callback(filename);
    }
    else if(stats.isDirectory()) {
    fs.readdir(filename, function(err, files) {
    files.forEach(function(f) {
    walk(fs.realpathSync(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('611749', 'node_green.png'),
    error: new Gist('611749', 'node_red.png')
    };

    function Gist(id, 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 host = 'gist.github.com',
    fd = fs.openSync(file, 'w'),
    gist = http.createClient(80, host),
    request = gist.request('GET', '/raw/' + id + '/' + name, {host: host});

    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();
    Binary file removed node_green.png
    Binary file not shown.
    Binary file removed node_red.png
    Binary file not shown.
  3. Felix Gnass revised this gist Oct 11, 2010. 1 changed file with 6 additions and 3 deletions.
    9 changes: 6 additions & 3 deletions dev
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,10 @@
    * 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.
    *
    * Author: Felix Gnass [fgnass at neteye dot de]
    * License: MIT
    * See http://gist.github.com/611749
    */
    var fs = require('fs'),
    sys = require('sys'),
    @@ -37,13 +41,12 @@ function start(title, msg) {

    // 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;
    var s = data.toString(), stack, src, m, file, line, col;

    sys.print(data);
    error += s;

    stack = s.match(/^(.+): (.*)\n\s+at.+\((.*?):(\d+):(\d+)/);

    stack = s.match(/^(.+): (.*)\n\s+at.+\((.*?):(\d+):(\d+)/m);
    if (stack) {

    // file:line
  4. Felix Gnass revised this gist Oct 7, 2010. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions dev
    Original file line number Diff line number Diff line change
    @@ -42,7 +42,7 @@ function start(title, msg) {
    sys.print(data);
    error += s;

    stack = s.match(/^(.+)\n\s+at.+\((.*?):(\d+):(\d+)/);
    stack = s.match(/^(.+): (.*)\n\s+at.+\((.*?):(\d+):(\d+)/);

    if (stack) {

    @@ -59,12 +59,12 @@ function start(title, msg) {
    }
    else {
    // No source-code or error was rethrown
    file = stack[2];
    line = stack[3];
    col = stack[4];
    file = stack[3];
    line = stack[4];
    col = stack[5];
    }

    notify(file + ',' + line + ':' + col, stack[1], 'error');
    notify(stack[2] + '\n @' + file + ',' + line + ':' + col, stack[1], 'error');
    error = '';
    }
    });
  5. Felix Gnass revised this gist Oct 7, 2010. 1 changed file with 11 additions and 12 deletions.
    23 changes: 11 additions & 12 deletions dev
    Original file line number Diff line number Diff line change
    @@ -98,18 +98,17 @@ function watchFiles() {
    }

    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);
    });
    });
    }
    });
    var stats = fs.statSync(filename);
    if(stats.isFile() && filename.match(/\.js$/)) {
    callback(filename);
    }
    else if(stats.isDirectory()) {
    fs.readdir(filename, function(err, files) {
    files.forEach(function(f) {
    walk(fs.realpathSync(filename + '/' + f), callback);
    });
    });
    }
    }

    /**
  6. Felix Gnass revised this gist Oct 6, 2010. 1 changed file with 16 additions and 16 deletions.
    32 changes: 16 additions & 16 deletions dev
    Original file line number Diff line number Diff line change
    @@ -126,11 +126,11 @@ function notify(msg, title, icon) {
    }

    var icons = {
    green: new Gist('6a64dc22047197dd840a92a08fa89517a73bbdd9', 'node_green.png'),
    error: new Gist('84497b6c3fff14273cd39bc860a29b364188919c', 'node_red.png')
    green: new Gist('611749', 'node_green.png'),
    error: new Gist('611749', 'node_red.png')
    };

    function Gist(sha, name) {
    function Gist(id, name) {
    var file = path.join(process.env.TMPDIR, name);
    this.get = function(callback) {
    path.exists(file, function(exists) {
    @@ -143,21 +143,21 @@ function Gist(sha, name) {
    });
    };
    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'
    });
    var host = 'gist.github.com',
    fd = fs.openSync(file, 'w'),
    gist = http.createClient(80, host),
    request = gist.request('GET', '/raw/' + id + '/' + name, {host: host});
    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);
    });
    });
    response.on('data', function (chunk) {
    fs.writeSync(fd, chunk, 0, chunk.length);
    });
    response.on('end', function () {
    fs.closeSync(fd);
    callback(file);
    });
    });
    }
    }

  7. Felix Gnass revised this gist Oct 6, 2010. 1 changed file with 23 additions and 32 deletions.
    55 changes: 23 additions & 32 deletions dev
    Original file line number Diff line number Diff line change
    @@ -11,30 +11,25 @@ var fs = require('fs'),
    child_process = require('child_process'),
    server = null,
    error = '',
    files = [];
    files = [],
    args = [].concat(process.argv),
    cmd = args.shift();

    function restart() {
    if (server) {
    server.kill();
    }
    else {
    unwatchFiles();
    start();
    }
    }
    args.shift();

    /**
    * Spawns a node child-process.
    */
    function start() {
    var args = [].concat(process.argv),
    cmd = args.shift();

    function start(title, msg) {
    watchFiles();
    args.shift();

    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);
    @@ -74,38 +69,34 @@ function start() {
    }
    });

    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() {
    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()) {
    notify('File modified: ' + file, 'Restarting');
    restart();
    if (server) {
    server.addListener('exit', function (code, signal) {
    if (signal) {
    start('Restarting', 'File modified: ' + file);
    }
    });
    server.kill();
    }
    else {
    start();
    }
    }
    });
    });
    }

    /**
    * 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$/)) {
  8. Felix Gnass renamed this gist Oct 6, 2010. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  9. Felix Gnass renamed this gist Oct 6, 2010. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions dev_server.js → dev.js
    Original file line number Diff line number Diff line change
    @@ -24,12 +24,16 @@ function restart() {
    }

    /**
    * Spawns a node child-process using the same script name, without the leading dev_ prefix.
    * Spawns a node child-process.
    */
    function start() {
    watchFiles();
    var args = [].concat(process.argv),
    cmd = args.shift();

    server = child_process.spawn(process.ARGV[0], ['--debug', __filename.replace('dev_', '')]);
    watchFiles();
    args.shift();

    server = child_process.spawn(cmd, args);

    // Print data written to stdout
    server.stdout.addListener('data', function(data) {
  10. Felix Gnass revised this gist Oct 6, 2010. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion dev_server.js
    100644 → 100755
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    * 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.
    * scanned for stack-traces. If an error is detected it is displayed as Growl notification.
    */
    var fs = require('fs'),
    sys = require('sys'),
    @@ -119,6 +119,7 @@ function walk(filename, 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) {
  11. Felix Gnass revised this gist Oct 6, 2010. 1 changed file with 17 additions and 8 deletions.
    25 changes: 17 additions & 8 deletions dev_server.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,9 @@
    /**
    * 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'),
    @@ -30,7 +36,7 @@ function start() {
    process.stdout.write(data);
    });

    // Data sent to stderr is scanned for stcktraces ...
    // 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;

    @@ -59,7 +65,7 @@ function start() {
    col = stack[4];
    }

    log(file + ',' + line + ':' + col, stack[1], 'error');
    notify(file + ',' + line + ':' + col, stack[1], 'error');
    error = '';
    }
    });
    @@ -74,14 +80,14 @@ function start() {
    }

    /**
    * Watches all .js files and restarts the server if a modifiaction is detected.
    * 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()) {
    log('File modified: ' + file, 'Restarting');
    notify('File modified: ' + file, 'Restarting');
    restart();
    }
    });
    @@ -111,7 +117,10 @@ function walk(filename, callback) {
    });
    }

    function log(msg, title, icon) {
    /**
    * Displays a message as Growl notification.
    */
    function notify(msg, title, icon) {
    icons[icon || 'green'].get(function(path) {
    child_process.spawn('growlnotify', [
    '-m', msg,
    @@ -121,11 +130,11 @@ function log(msg, title, icon) {
    }

    var icons = {
    green: new Icon('6a64dc22047197dd840a92a08fa89517a73bbdd9', 'node_green.png'),
    error: new Icon('84497b6c3fff14273cd39bc860a29b364188919c', 'node_red.png')
    green: new Gist('6a64dc22047197dd840a92a08fa89517a73bbdd9', 'node_green.png'),
    error: new Gist('84497b6c3fff14273cd39bc860a29b364188919c', 'node_red.png')
    };

    function Icon(sha, name) {
    function Gist(sha, name) {
    var file = path.join(process.env.TMPDIR, name);
    this.get = function(callback) {
    path.exists(file, function(exists) {
  12. Felix Gnass revised this gist Oct 5, 2010. 1 changed file with 41 additions and 20 deletions.
    61 changes: 41 additions & 20 deletions dev_server.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    var fs = require('fs'),
    sys = require('sys'),
    path = require('path'),
    http = require('http'),
    child_process = require('child_process'),
    server = null,
    error = '',
    @@ -46,7 +47,7 @@ function start() {
    // ErrorType: Message
    src = error.match(/^\s*(.+):(\d+)\n(.*)\n(\s*)\^/);

    if (src && !src[3].match(/throw/)) {
    if (src && !src[3].match(/throw/)) {
    file = src[1];
    line = src[2];
    col = src[4].length;
    @@ -58,7 +59,7 @@ function start() {
    col = stack[4];
    }

    log(file + ',' + line + ':' + col, stack[1], 'nodejs_red');
    log(file + ',' + line + ':' + col, stack[1], 'error');
    error = '';
    }
    });
    @@ -111,28 +112,48 @@ function walk(filename, callback) {
    }

    function log(msg, title, icon) {
    growlnotify(msg, {title: title || 'node.js', image: '/usr/local/share/icons/' + (icon || 'nodejs') + '.png'});
    icons[icon || 'green'].get(function(path) {
    child_process.spawn('growlnotify', [
    '-m', msg,
    '--image', path,
    title || 'node.js']);
    });
    }

    /**
    * Displays the given message with growlnotify.
    */
    function growlnotify(msg, options) {
    var image,
    args = ['-m', msg],
    options = options || {}
    var icons = {
    green: new Icon('6a64dc22047197dd840a92a08fa89517a73bbdd9', 'node_green.png'),
    error: new Icon('84497b6c3fff14273cd39bc860a29b364188919c', 'node_red.png')
    };

    if (image = options.image) {
    args.push('--image', image);
    }
    if (options.sticky) {
    args.push('--sticky');
    }
    if (options.title) {
    args.push(options.title);
    function Icon(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);
    });
    });
    }
    child_process.spawn('growlnotify', args);
    }


    start();
  13. Felix Gnass revised this gist Oct 5, 2010. 2 changed files with 0 additions and 0 deletions.
    Binary file modified node_green.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified node_red.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  14. fgnass created this gist Oct 5, 2010.
    138 changes: 138 additions & 0 deletions dev_server.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,138 @@
    var fs = require('fs'),
    sys = require('sys'),
    path = require('path'),
    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 stcktraces ...
    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];
    }

    log(file + ',' + line + ':' + col, stack[1], 'nodejs_red');
    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 modifiaction 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()) {
    log('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);
    });
    });
    }
    });
    }

    function log(msg, title, icon) {
    growlnotify(msg, {title: title || 'node.js', image: '/usr/local/share/icons/' + (icon || 'nodejs') + '.png'});
    }

    /**
    * Displays the given message with growlnotify.
    */
    function growlnotify(msg, options) {
    var image,
    args = ['-m', msg],
    options = options || {}

    if (image = options.image) {
    args.push('--image', image);
    }
    if (options.sticky) {
    args.push('--sticky');
    }
    if (options.title) {
    args.push(options.title);
    }
    child_process.spawn('growlnotify', args);
    }


    start();
    Empty file added node_green.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Empty file added node_red.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.