704 lines
23 KiB
JavaScript
Executable File
704 lines
23 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
var fs = require('fs'),
|
|
util = require('util'),
|
|
childProcess = require('child_process'),
|
|
dirs = [],
|
|
path = require('path'),
|
|
exists = fs.exists || path.exists, // yay, exists moved from path to fs in 0.7.x ... :-\
|
|
existsSync = fs.existsSync || path.existsSync,
|
|
spawn = childProcess.spawn,
|
|
meta = JSON.parse(fs.readFileSync(__dirname + '/package.json')),
|
|
exec = childProcess.exec,
|
|
flag = './.monitor',
|
|
child = null,
|
|
monitor = null,
|
|
ignoreFilePath = './.nodemonignore',
|
|
oldIgnoreFilePath = './nodemon-ignore',
|
|
ignoreFiles = [],
|
|
reIgnoreFiles = null,
|
|
timeout = 1000, // check every 1 second
|
|
restartDelay = 0, // controlled through arg --delay 10 (for 10 seconds)
|
|
restartTimer = null,
|
|
lastStarted = +new Date,
|
|
statOffset = 0, // stupid fix for https://github.com/joyent/node/issues/2705
|
|
platform = process.platform,
|
|
isWindows = platform === 'win32',
|
|
noWatch = (platform !== 'win32') || !fs.watch, // && platform !== 'linux' - removed linux fs.watch usage #72
|
|
watchFile = platform === 'darwin' ? fs.watchFile : fs.watch, // lame :(
|
|
watchWorks = true, // whether or not fs.watch actually works on this platform, tested and set later before starting
|
|
// create once, reuse as needed
|
|
reEscComments = /\\#/g,
|
|
reUnescapeComments = /\^\^/g, // note that '^^' is used in place of escaped comments
|
|
reComments = /#.*$/,
|
|
reTrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
|
|
reEscapeChars = /[.|\-[\]()\\]/g,
|
|
reAsterisk = /\*/g,
|
|
// Flag to distinguish an app crash from intentional killing (used on Windows only for now)
|
|
killedAfterChange = false,
|
|
// Make this the last call so it can use the variables defined above (specifically isWindows)
|
|
program = getNodemonArgs(),
|
|
watched = [];
|
|
|
|
|
|
|
|
// test to see if the version of find being run supports searching by seconds (-mtime -1s -print)
|
|
var testAndStart = function() {
|
|
if (noWatch) {
|
|
exec('find -L /dev/null -type f -mtime -1s -print', function(error, stdout, stderr) {
|
|
if (error) {
|
|
if (!fs.watch) {
|
|
util.error('\x1B[1;31mThe version of node you are using combined with the version of find being used does not support watching files. Upgrade to a newer version of node, or install a version of find that supports search by seconds.\x1B[0m');
|
|
process.exit(1);
|
|
} else {
|
|
noWatch = false;
|
|
watchFileChecker.check(function(success) {
|
|
watchWorks = success;
|
|
startNode();
|
|
});
|
|
}
|
|
} else {
|
|
// Find is compatible with -1s
|
|
startNode();
|
|
}
|
|
});
|
|
} else {
|
|
watchFileChecker.check(function(success) {
|
|
watchWorks = success;
|
|
startNode();
|
|
});
|
|
}
|
|
}
|
|
|
|
// This is a fallback function if fs.watch does not work
|
|
function changedSince(time, dir, callback) {
|
|
callback || (callback = dir);
|
|
var changed = [],
|
|
i = 0,
|
|
j = 0,
|
|
dir = dir && typeof dir !== 'function' ? [dir] : dirs,
|
|
dlen = dir.length,
|
|
todo = 0,
|
|
flen = 0,
|
|
done = function () {
|
|
todo--;
|
|
if (todo === 0) callback(changed);
|
|
};
|
|
|
|
dir.forEach(function (dir) {
|
|
todo++;
|
|
fs.readdir(dir, function (err, files) {
|
|
if (err) return;
|
|
|
|
files.forEach(function (file) {
|
|
if (program.includeHidden == true || !program.includeHidden && file.indexOf('.') !== 0) {
|
|
todo++;
|
|
file = path.resolve(dir + '/' + file);
|
|
var stat = fs.stat(file, function (err, stat) {
|
|
if (stat) {
|
|
if (stat.isDirectory()) {
|
|
todo++;
|
|
changedSince(time, file, function (subChanged) {
|
|
if (subChanged.length) changed = changed.concat(subChanged);
|
|
done();
|
|
});
|
|
} else if (stat.mtime > time) {
|
|
changed.push(file);
|
|
}
|
|
}
|
|
done();
|
|
});
|
|
}
|
|
});
|
|
done();
|
|
});
|
|
});
|
|
}
|
|
|
|
// Attempts to see if fs.watch will work. On some platforms, it doesn't.
|
|
// See: http://nodejs.org/api/fs.html#fs_caveats
|
|
// Sends the callback true if fs.watch will work, false if it won't
|
|
//
|
|
// Caveats:
|
|
// If there is no writable tmp directory, it will also return true, although
|
|
// a warning message will be displayed.
|
|
//
|
|
var watchFileChecker = {};
|
|
watchFileChecker.check = function(cb) {
|
|
var tmpdir,
|
|
seperator = '/';
|
|
|
|
this.cb = cb;
|
|
this.changeDetected = false;
|
|
if (isWindows) {
|
|
seperator = '\\';
|
|
tmpdir = process.env.TEMP;
|
|
} else if (process.env.TMPDIR) {
|
|
tmpdir = process.env.TMPDIR
|
|
} else {
|
|
tmpdir = '/tmp';
|
|
}
|
|
var watchFileName = tmpdir + seperator + 'nodemonCheckFsWatch'
|
|
var watchFile = fs.openSync(watchFileName, 'w');
|
|
if (!watchFile) {
|
|
util.log('\x1B[32m[nodemon] Unable to write to temp directory. If you experience problems with file reloading, ensure ' + tmpdir + ' is writable.\x1B[0m');
|
|
cb(true);
|
|
return;
|
|
}
|
|
fs.watch(watchFileName, function(event, filename) {
|
|
if (watchFileChecker.changeDetected) { return; }
|
|
watchFileChecker.changeDetected = true;
|
|
cb(true);
|
|
});
|
|
// This should trigger fs.watch, if it works
|
|
fs.writeSync(watchFile, '1');
|
|
fs.unlinkSync(watchFileName);
|
|
|
|
setTimeout(function() { watchFileChecker.verify() }, 250);
|
|
};
|
|
|
|
// Verifies that fs.watch was not triggered and sends false to the callback
|
|
watchFileChecker.verify = function() {
|
|
if (!this.changeDetected) {
|
|
this.cb(false);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
function startNode() {
|
|
util.log('\x1B[32m[nodemon] starting `' + program.options.exec + ' ' + program.args.join(' ') + '`\x1B[0m');
|
|
|
|
child = spawn(program.options.exec, program.args);
|
|
|
|
lastStarted = +new Date;
|
|
|
|
child.stdout.on('data', function (data) {
|
|
util.print(data);
|
|
});
|
|
|
|
child.stderr.on('data', function (data) {
|
|
process.stderr.write(data);
|
|
});
|
|
|
|
child.on('exit', function (code, signal) {
|
|
// In case we killed the app ourselves, set the signal thusly
|
|
if (killedAfterChange) {
|
|
killedAfterChange = false;
|
|
signal = 'SIGUSR2';
|
|
}
|
|
// this is nasty, but it gives it windows support
|
|
if (isWindows && signal == 'SIGTERM') signal = 'SIGUSR2';
|
|
// exit the monitor, but do it gracefully
|
|
if (signal == 'SIGUSR2') {
|
|
// restart
|
|
startNode();
|
|
} else if (code === 0) { // clean exit - wait until file change to restart
|
|
util.log('\x1B[32m[nodemon] clean exit - waiting for changes before restart\x1B[0m');
|
|
child = null;
|
|
} else if (program.options.exitcrash) {
|
|
util.log('\x1B[1;31m[nodemon] app crashed\x1B[0m');
|
|
process.exit(0);
|
|
} else {
|
|
util.log('\x1B[1;31m[nodemon] app crashed - waiting for file changes before starting...\x1B[0m');
|
|
child = null;
|
|
}
|
|
});
|
|
|
|
// pinched from https://github.com/DTrejo/run.js - pipes stdin to the child process - cheers DTrejo ;-)
|
|
if (program.options.stdin) {
|
|
process.stdin.resume();
|
|
process.stdin.setEncoding('utf8');
|
|
process.stdin.pipe(child.stdin);
|
|
}
|
|
|
|
setTimeout(startMonitor, timeout);
|
|
}
|
|
|
|
function startMonitor() {
|
|
var changeFunction;
|
|
|
|
if (noWatch) {
|
|
// if native fs.watch doesn't work the way we want, we keep polling find command (mac only oddly)
|
|
changeFunction = function (lastStarted, callback) {
|
|
var cmds = [],
|
|
changed = [];
|
|
|
|
dirs.forEach(function(dir) {
|
|
cmds.push('find -L "' + dir + '" -type f -mtime -' + ((+new Date - lastStarted)/1000|0) + 's -print');
|
|
});
|
|
|
|
exec(cmds.join(';'), function (error, stdout, stderr) {
|
|
var files = stdout.split(/\n/);
|
|
files.pop(); // remove blank line ending and split
|
|
callback(files);
|
|
});
|
|
}
|
|
} else if (watchWorks) {
|
|
changeFunction = function (lastStarted, callback) {
|
|
// recursive watch - watch each directory and it's subdirectories, etc, etc
|
|
var watch = function (err, dir) {
|
|
try {
|
|
fs.watch(dir, { persistent: false }, function (event, filename) {
|
|
var filepath = path.join(dir, filename);
|
|
callback([filepath]);
|
|
});
|
|
|
|
fs.readdir(dir, function (err, files) {
|
|
if (!err) {
|
|
files = files.
|
|
map(function (file ) { return path.join(dir, file); }).
|
|
filter(ignoredFilter);
|
|
files.forEach(function (file) {
|
|
if (-1 === watched.indexOf(file)) {
|
|
watched.push(file);
|
|
fs.stat(file, function (err, stat) {
|
|
if (!err && stat) {
|
|
if (stat.isDirectory()) {
|
|
fs.realpath(file, watch);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} catch (e) {
|
|
if ('EMFILE' === e.code) {
|
|
console.error('EMFILE: Watching too many files.');
|
|
}
|
|
// ignoring this directory, likely it's "My Music"
|
|
// or some such windows fangled stuff
|
|
}
|
|
}
|
|
dirs.forEach(function (dir) {
|
|
fs.realpath(dir, watch);
|
|
});
|
|
}
|
|
} else {
|
|
// changedSince, the fallback for when both the find method and fs.watch don't work,
|
|
// is not compatible with the way changeFunction works. If we have reached this point,
|
|
// changeFunction should not be called from herein out.
|
|
changeFunction = function() { util.error("Nodemon error: changeFunction called when it shouldn't be.") }
|
|
}
|
|
|
|
// filter ignored files
|
|
var ignoredFilter = function (file) {
|
|
// If we are in a Windows machine
|
|
if (isWindows) {
|
|
// Break up the file by slashes
|
|
var fileParts = file.split(/\\/g);
|
|
|
|
// Remove the first piece (C:)
|
|
fileParts.shift();
|
|
|
|
// Join the parts together with Unix slashes
|
|
file = '/' + fileParts.join('/');
|
|
}
|
|
return !reIgnoreFiles.test(file);
|
|
};
|
|
|
|
var isWindows = process.platform === 'win32';
|
|
if ((noWatch || watchWorks) && !program.options.forceLegacyWatch) {
|
|
changeFunction(lastStarted, function (files) {
|
|
if (files.length) {
|
|
files = files.filter(ignoredFilter);
|
|
if (files.length) {
|
|
if (restartTimer !== null) clearTimeout(restartTimer);
|
|
restartTimer = setTimeout(function () {
|
|
if (program.options.verbose) util.log('[nodemon] restarting due to changes...');
|
|
files.forEach(function (file) {
|
|
if (program.options.verbose) util.log('[nodemon] ' + file);
|
|
});
|
|
if (program.options.verbose) util.print('\n\n');
|
|
|
|
killNode();
|
|
|
|
}, restartDelay);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (noWatch) setTimeout(startMonitor, timeout);
|
|
});
|
|
} else {
|
|
// Fallback for when both find and fs.watch don't work
|
|
changedSince(lastStarted, function (files) {
|
|
if (files.length) {
|
|
// filter ignored files
|
|
if (ignoreFiles.length) {
|
|
files = files.filter(function(file) {
|
|
return !reIgnoreFiles.test(file);
|
|
});
|
|
}
|
|
|
|
if (files.length) {
|
|
if (restartTimer !== null) clearTimeout(restartTimer);
|
|
restartTimer = setTimeout(function () {
|
|
if (program.options.verbose) util.log('[nodemon] restarting due to changes...');
|
|
files.forEach(function (file) {
|
|
if (program.options.verbose) util.log('[nodemon] ' + file);
|
|
});
|
|
if (program.options.verbose) util.print('\n\n');
|
|
|
|
killNode();
|
|
|
|
}, restartDelay);
|
|
return;
|
|
}
|
|
}
|
|
|
|
setTimeout(startMonitor, timeout);
|
|
});
|
|
}
|
|
}
|
|
|
|
function killNode() {
|
|
if (child !== null) {
|
|
// When using CoffeeScript under Windows, child's process is not node.exe
|
|
// Instead coffee.cmd is launched, which launches cmd.exe, which starts node.exe as a child process
|
|
// child.kill() would only kill cmd.exe, not node.exe
|
|
// Therefore we use the Windows taskkill utility to kill the process and all its children (/T for tree)
|
|
if (isWindows) {
|
|
// For the on('exit', ...) handler above the following looks like a crash, so we set the killedAfterChange flag
|
|
killedAfterChange = true;
|
|
// Force kill (/F) the whole child tree (/T) by PID (/PID 123)
|
|
exec('taskkill /pid '+child.pid+' /T /F');
|
|
} else {
|
|
child.kill('SIGUSR2');
|
|
}
|
|
} else {
|
|
startNode();
|
|
}
|
|
}
|
|
|
|
function addIgnoreRule(line, noEscape) {
|
|
// remove comments and trim lines
|
|
// this mess of replace methods is escaping "\#" to allow for emacs temp files
|
|
if (!noEscape) {
|
|
if (line = line.replace(reEscComments, '^^').replace(reComments, '').replace(reUnescapeComments, '#').replace(reTrim, '')) {
|
|
ignoreFiles.push(line.replace(reEscapeChars, '\\$&').replace(reAsterisk, '.*'));
|
|
}
|
|
} else if (line = line.replace(reTrim, '')) {
|
|
ignoreFiles.push(line);
|
|
}
|
|
reIgnoreFiles = new RegExp(ignoreFiles.join('|'));
|
|
}
|
|
|
|
function readIgnoreFile(curr, prev) {
|
|
// unless the ignore file was actually modified, do no re-read it
|
|
if(curr && prev && curr.mtime.valueOf() === prev.mtime.valueOf()) return;
|
|
|
|
if (platform === 'darwin') fs.unwatchFile(ignoreFilePath);
|
|
|
|
// Check if ignore file still exists. Vim tends to delete it before replacing with changed file
|
|
exists(ignoreFilePath, function(exists) {
|
|
if (program.options.verbose) util.log('[nodemon] reading ignore list');
|
|
|
|
// ignoreFiles = ignoreFiles.concat([flag, ignoreFilePath]);
|
|
// addIgnoreRule(flag);
|
|
addIgnoreRule(ignoreFilePath.substring(2)); // ignore the ./ part of the filename
|
|
fs.readFileSync(ignoreFilePath).toString().split(/\n/).forEach(function (rule, i) {
|
|
addIgnoreRule(rule);
|
|
});
|
|
|
|
watchFile(ignoreFilePath, { persistent: false }, readIgnoreFile);
|
|
});
|
|
}
|
|
|
|
// attempt to shutdown the wrapped node instance and remove
|
|
// the monitor file as nodemon exists
|
|
function cleanup() {
|
|
child && child.kill();
|
|
// fs.unlink(flag);
|
|
}
|
|
|
|
function getNodemonArgs() {
|
|
var args = process.argv,
|
|
len = args.length,
|
|
i = 2,
|
|
dir = process.cwd(),
|
|
indexOfApp = -1,
|
|
app = null;
|
|
|
|
for (; i < len; i++) {
|
|
if (existsSync(path.resolve(dir, args[i]))) {
|
|
// double check we didn't use the --watch or -w opt before this arg
|
|
if (args[i-1] && (args[i-1] == '-w' || args[i-1] == '--watch')) {
|
|
// ignore
|
|
} else {
|
|
indexOfApp = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (indexOfApp !== -1) {
|
|
// not found, so assume we're reading the package.json and thus swallow up all the args
|
|
// indexOfApp = len;
|
|
app = process.argv[i];
|
|
indexOfApp++;
|
|
} else {
|
|
indexOfApp = len;
|
|
}
|
|
|
|
var appargs = [], //process.argv.slice(indexOfApp),
|
|
// app = appargs[0],
|
|
nodemonargs = process.argv.slice(2, indexOfApp - (app ? 1 : 0)),
|
|
arg,
|
|
options = {
|
|
delay: 1,
|
|
watch: [],
|
|
exec: 'node',
|
|
verbose: true,
|
|
js: false, // becomes the default anyway...
|
|
includeHidden: false,
|
|
exitcrash: false,
|
|
forceLegacyWatch: false, // forces nodemon to use the slowest but most compatible method for watching for file changes
|
|
stdin: true
|
|
// args: []
|
|
};
|
|
|
|
// process nodemon args
|
|
args.splice(0, 2);
|
|
while (arg = args.shift()) {
|
|
if (arg === '--help' || arg === '-h' || arg === '-?') {
|
|
return help(); // exits program
|
|
} else if (arg === '--version' || arg == '-v') {
|
|
return version(); // also exits
|
|
} else if (arg == '--js') {
|
|
options.js = true;
|
|
} else if (arg == '--quiet' || arg == '-q') {
|
|
options.verbose = false;
|
|
} else if (arg == '--hidden') {
|
|
options.includeHidden = true;
|
|
} else if (arg === '--watch' || arg === '-w') {
|
|
options.watch.push(args.shift());
|
|
} else if (arg === '--exitcrash') {
|
|
options.exitcrash = true;
|
|
} else if (arg === '--delay' || arg === '-d') {
|
|
options.delay = parseInt(args.shift());
|
|
} else if (arg === '--exec' || arg === '-x') {
|
|
options.exec = args.shift();
|
|
} else if (arg == '--legacy-watch' || arg == '-L') {
|
|
options.forceLegacyWatch = true;
|
|
} else if (arg === '--no-stdin' || arg === '-I') {
|
|
options.stdin = false;
|
|
} else { //if (arg === "--") {
|
|
// Remaining args are node arguments
|
|
appargs.push(arg);
|
|
}
|
|
}
|
|
|
|
var program = { options: options, args: appargs, app: app };
|
|
|
|
getAppScript(program);
|
|
|
|
return program;
|
|
}
|
|
|
|
function getAppScript(program) {
|
|
var hokeycokey = false;
|
|
if (!program.args.length || program.app === null) {
|
|
// try to get the app from the package.json
|
|
// doing a try/catch because we can't use the path.exist callback pattern
|
|
// or we could, but the code would get messy, so this will do exactly
|
|
// what we're after - if the file doesn't exist, it'll throw.
|
|
try {
|
|
// note: this isn't nodemon's package, it's the user's cwd package
|
|
program.app = JSON.parse(fs.readFileSync('./package.json').toString()).main;
|
|
if (program.app === undefined) {
|
|
// no app found to run - so give them a tip and get the feck out
|
|
help();
|
|
}
|
|
program.args.unshift(program.app);
|
|
hokeycokey = true;
|
|
} catch (e) {}
|
|
}
|
|
|
|
if (!program.app) {
|
|
program.app = program.args[0];
|
|
}
|
|
|
|
program.app = path.basename(program.app);
|
|
program.ext = path.extname(program.app);
|
|
|
|
if (program.options.exec.indexOf(' ') !== -1) {
|
|
var execOptions = program.options.exec.split(' ');
|
|
program.options.exec = execOptions.splice(0, 1)[0];
|
|
program.args = execOptions.concat(program.args);
|
|
}
|
|
|
|
if (program.options.exec === 'node' && program.ext == '.coffee') {
|
|
program.options.exec = 'coffee';
|
|
}
|
|
|
|
if (program.options.exec === 'coffee') {
|
|
if (hokeycokey) {
|
|
program.args.push(program.args.shift());
|
|
}
|
|
//coffeescript requires --nodejs --debug
|
|
var debugIndex = program.args.indexOf('--debug');
|
|
if (debugIndex === -1) debugIndex = program.args.indexOf('--debug-brk');
|
|
if (debugIndex !== -1 && program.args.indexOf('--nodejs') === -1) {
|
|
program.args.splice(debugIndex, 0, '--nodejs');
|
|
}
|
|
// monitor both types - TODO possibly make this an option?
|
|
program.ext = '.coffee|.js';
|
|
if (!program.options.exec || program.options.exec == 'node') program.options.exec = 'coffee';
|
|
|
|
// because windows can't find 'coffee', it needs the real file 'coffee.cmd'
|
|
if (isWindows) program.options.exec += '.cmd';
|
|
}
|
|
}
|
|
|
|
function findStatOffset() {
|
|
var filename = './.stat-test';
|
|
fs.writeFile(filename, function (err) {
|
|
if (err) return;
|
|
fs.stat(filename, function (err, stat) {
|
|
if (err) return;
|
|
|
|
statOffset = stat.mtime.getTime() - new Date().getTime();
|
|
fs.unlink(filename);
|
|
});
|
|
});
|
|
}
|
|
|
|
function version() {
|
|
console.log(meta.version);
|
|
process.exit(0);
|
|
}
|
|
|
|
function help() {
|
|
util.print([
|
|
'',
|
|
' Usage: nodemon [options] [script.js] [args]',
|
|
'',
|
|
' Options:',
|
|
'',
|
|
' -d, --delay n throttle restart for "n" seconds',
|
|
' -w, --watch dir watch directory "dir". use once for each',
|
|
' directory to watch',
|
|
' -x, --exec app execute script with "app", ie. -x "python -v"',
|
|
' -I, --no-stdin don\'t try to read from stdin',
|
|
' -q, --quiet minimise nodemon messages to start/stop only',
|
|
' --exitcrash exit on crash, allows use of nodemon with',
|
|
' daemon tools like forever.js',
|
|
' -L, --legacy-watch Forces node to use the most compatible',
|
|
' version for watching file changes',
|
|
' -v, --version current nodemon version',
|
|
' -h, --help you\'re looking at it',
|
|
'',
|
|
' Note: if the script is omitted, nodemon will try to ',
|
|
' read "main" from package.json and without a .nodemonignore,',
|
|
' nodemon will monitor .js and .coffee by default.',
|
|
'',
|
|
' Examples:',
|
|
'',
|
|
' $ nodemon server.js',
|
|
' $ nodemon -w ../foo server.js apparg1 apparg2',
|
|
' $ PORT=8000 nodemon --debug-brk server.js',
|
|
' $ nodemon --exec python app.py',
|
|
'',
|
|
' For more details see http://github.com/remy/nodemon/',
|
|
''
|
|
].join('\n') + '\n');
|
|
process.exit(0);
|
|
}
|
|
|
|
// this little bit of hoop jumping is because sometimes the file can't be
|
|
// touched properly, and it send nodemon in to a loop of restarting.
|
|
// this way, the .monitor file is removed entirely, and recreated with
|
|
// permissions that anyone can remove it later (i.e. if you run as root
|
|
// by accident and then try again later).
|
|
// if (path.existsSync(flag)) fs.unlinkSync(flag);
|
|
// fs.writeFileSync(flag, '.'); // requires some content https://github.com/remy/nodemon/issues/36
|
|
// fs.chmodSync(flag, '666');
|
|
|
|
// remove the flag file on exit
|
|
process.on('exit', function (code) {
|
|
if (program.options.verbose) util.log('[nodemon] exiting');
|
|
cleanup();
|
|
});
|
|
|
|
if (!isWindows) { // because windows borks when listening for the SIG* events
|
|
// usual suspect: ctrl+c exit
|
|
process.on('SIGINT', function () {
|
|
child && child.kill('SIGINT');
|
|
cleanup();
|
|
process.exit(0);
|
|
});
|
|
|
|
process.on('SIGTERM', function () {
|
|
cleanup();
|
|
process.exit(0);
|
|
});
|
|
}
|
|
|
|
// TODO on a clean exit, we could continue to monitor the directory and reboot the service
|
|
|
|
// on exception *inside* nodemon, shutdown wrapped node app
|
|
process.on('uncaughtException', function (err) {
|
|
util.log('[nodemon] exception in nodemon killing node');
|
|
util.error(err.stack);
|
|
cleanup();
|
|
});
|
|
|
|
|
|
if (program.options.delay) {
|
|
restartDelay = program.options.delay * 1000;
|
|
}
|
|
|
|
// this is the default - why am I making it a cmd line opt?
|
|
if (program.options.js) {
|
|
addIgnoreRule('^((?!\.js|\.coffee$).)*$', true); // ignores everything except JS
|
|
}
|
|
|
|
if (program.options.watch && program.options.watch.length > 0) {
|
|
program.options.watch.forEach(function (dir) {
|
|
dirs.push(path.resolve(dir));
|
|
});
|
|
} else {
|
|
dirs.unshift(process.cwd());
|
|
}
|
|
|
|
if (!program.app) {
|
|
help();
|
|
}
|
|
|
|
if (program.options.verbose) util.log('[nodemon] v' + meta.version);
|
|
|
|
// this was causing problems for a lot of people, so now not moving to the subdirectory
|
|
// process.chdir(path.dirname(app));
|
|
dirs.forEach(function(dir) {
|
|
if (program.options.verbose) util.log('\x1B[32m[nodemon] watching: ' + dir + '\x1B[0m');
|
|
});
|
|
|
|
// findStatOffset();
|
|
|
|
exists(ignoreFilePath, function (exist) {
|
|
// watch it: "exist" not to be confused with "exists"....
|
|
if (!exist) {
|
|
// try the old format
|
|
exists(oldIgnoreFilePath, function (exist) {
|
|
if (exist) {
|
|
if (program.options.verbose) util.log('[nodemon] detected old style .nodemonignore');
|
|
ignoreFilePath = oldIgnoreFilePath;
|
|
} else {
|
|
// don't create the ignorefile, just ignore the flag & JS
|
|
// addIgnoreRule(flag);
|
|
var ext = program.ext.replace(/\./g, '\\.');
|
|
if (ext) {
|
|
addIgnoreRule('^((?!' + ext + '$).)*$', true);
|
|
} else {
|
|
addIgnoreRule('^((?!\.js|\.coffee$).)*$', true); // ignores everything except JS
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
readIgnoreFile();
|
|
}
|
|
});
|
|
|
|
testAndStart();
|