#!/usr/local/bin/node var fs = require('fs'), sys = require('sys'), spawn = require('child_process').spawn, exec = require('child_process').exec, flag = __dirname + '/.monitor', nodeArgs = process.ARGV.splice(2), node = null, // removes 'node' and this script monitor = null, ignoreFilePath = __dirname + '/ignore', ignoreFileTime = null, ignoreFiles = [flag], // ignore the monitor flag by default reIgnoreFiles = null, timeout = 1000, // check every 1 second // create once, reuse as needed reComments = /#.*$/, reTrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, reEscapeChars = /[.|\-[\]()\\]/g, reAsterisk = /\*/g; function startNode() { sys.log('[nodemon] starting node'); node = spawn('node', nodeArgs); node.stdout.on('data', function (data) { sys.print(data); }); node.stderr.on('data', function (data) { sys.error(data); }); node.on('exit', function (code, signal) { // exit the monitor, but do it gracefully if (signal == 'SIGUSR1') { // restart startNode(); } else { process.exit(); } }); } function startMonitor() { var cmd = 'find . -type f -newer ' + flag + ' -print'; exec(cmd, function (error, stdout, stderr) { var files = stdout.split(/\n/); files.pop(); // remove blank line ending and split if (files.length) { // filter ignored files if (ignoreFiles.length) { files = files.filter(function(file) { return !reIgnoreFiles.test(file); }); } fs.writeFileSync(flag, ''); if (files.length) { sys.log('[nodemon] restarting due to changes...'); files.forEach(function (file) { sys.log('[nodemon] ' + file); }); sys.print('\n\n'); node.kill('SIGUSR1'); } } setTimeout(startMonitor, timeout); }); } function readIgnoreFile() { fs.unwatchFile(ignoreFilePath); sys.log('[nodemon] reading ignore list'); ignoreFiles = [flag]; fs.readFileSync(ignoreFilePath).toString().split(/\n/).forEach(function (line) { // remove comments and trim lines if (line = line.replace(reComments, '').replace(reTrim, '')) { ignoreFiles.push(line.replace(reEscapeChars, '\\$&').replace(reAsterisk, '.*')); } }); reIgnoreFiles = new RegExp(ignoreFiles.join('|')); fs.watchFile(ignoreFilePath, { persistent: false }, readIgnoreFile); } require('path').exists(ignoreFilePath, readIgnoreFile); // touch fs.writeFileSync(flag, ''); // remove the flag file on exit process.on('exit', function (code) { sys.log('[nodemon] exiting'); fs.unlink(flag); }); process.on('uncaughtException', function (err) { sys.log('[nodemon] exception in nodemon killing node: ' + err); node.kill(); }); sys.log('[nodemon] starting'); startNode(); setTimeout(startMonitor, timeout);