mirror of
https://github.com/SrIzan10/nodemon.git
synced 2026-05-01 10:55:09 +00:00
246 lines
7.7 KiB
JavaScript
246 lines
7.7 KiB
JavaScript
'use strict';
|
|
var fs = require('fs'),
|
|
path = require('path'),
|
|
changedSince = require('./changed-since'),
|
|
utils = require('../utils'),
|
|
bus = utils.bus,
|
|
match = require('./match'),
|
|
config = require('../config'),
|
|
childProcess = require('child_process'),
|
|
exec = childProcess.exec,
|
|
restartTimer = null,
|
|
watched = [],
|
|
watchers = [];
|
|
|
|
var changeFunction = function () {
|
|
utils.log.error('changeFunction called when it shouldn\'t be.');
|
|
};
|
|
|
|
function reset() {
|
|
// manually remove all the file watchers.
|
|
// note that fs.unwatchFile doesn't really work, particularly in vagrant
|
|
// shared folders and in Travis CI...
|
|
var watcher;
|
|
while (watchers.length) {
|
|
watcher = watchers.pop();
|
|
watcher.removeAllListeners('change');
|
|
watcher.close();
|
|
}
|
|
|
|
// reset the watched directory too
|
|
watched.length = 0;
|
|
}
|
|
|
|
bus.on('config:update', function () {
|
|
reset();
|
|
|
|
if (config.system.useFind) {
|
|
// let's do a sanity check for the amount of files we'll be watching for...
|
|
var cmds = [];
|
|
config.dirs.forEach(function(dir) {
|
|
cmds.push('find -L "' + dir + '" -type f ' + ignoredFileTypesForFind(dir) + ' | wc');
|
|
});
|
|
|
|
exec(cmds.join(';'), function (error, stdout) {
|
|
var total = 0;
|
|
stdout.split(/\n/).map(function (line) {
|
|
total += line.trim().split(/\s+/)[0] * 1;
|
|
});
|
|
|
|
if (total > 25000) {
|
|
utils.log.fail('watching ' + (total).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' files - this might cause high cpu usage. To reduce use "--watch".');
|
|
}
|
|
});
|
|
|
|
|
|
// 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 = [];
|
|
|
|
config.dirs.forEach(function(dir) {
|
|
cmds.push('find -L "' + dir + '" -type f ' + ignoredFileTypesForFind(dir) + ' -mtime -' + ((Date.now() - config.lastStarted)/1000|0) + 's -print');
|
|
});
|
|
|
|
exec(cmds.join(';'), function (error, stdout) {
|
|
var files = stdout.split(/\n/);
|
|
files.pop(); // remove blank line ending and split
|
|
callback(files);
|
|
});
|
|
};
|
|
} else if (config.system.useWatch || config.system.useWatchFile) {
|
|
bus.once('quit', reset);
|
|
|
|
var watchFile = config.system.useWatch === false && (config.system.useWatchFile || config.options.legacyWatch),
|
|
watchMethod = watchFile ? 'watchFile' : 'watch';
|
|
changeFunction = function (lastStarted, callback) {
|
|
// recursive watch - watch each directory and it's subdirectories, etc, etc
|
|
function watch(err, dir) {
|
|
try {
|
|
if (watched.indexOf(dir) === -1 && ignoredFilter(dir)) {
|
|
var watcher = fs[watchMethod](dir, { persistent: false }, function (event, filename) {
|
|
|
|
var filepath;
|
|
|
|
if (typeof filename === 'string') {
|
|
filepath = path.join(dir, filename || '');
|
|
} else { // was called from watchFile
|
|
filepath = dir;
|
|
}
|
|
|
|
callback([filepath]);
|
|
});
|
|
watched.push(dir);
|
|
watchers.push(watcher);
|
|
}
|
|
|
|
fs.readdir(dir, function (err, files) {
|
|
if (err) { return; }
|
|
|
|
files.forEach(function (rawfile) {
|
|
var file = path.join(dir, rawfile);
|
|
if (watched.indexOf(file) === -1) {
|
|
fs.stat(file, function (err, stat) {
|
|
if (err || !stat) { return; }
|
|
|
|
// if we're using fs.watch, then watch directories
|
|
if (!watchFile && stat.isDirectory()) {
|
|
// recursive call to watch()
|
|
fs.realpath(file, watch);
|
|
} else {
|
|
// if we're in legacy mode, i.e. Vagrant + editing over
|
|
// shared drive, then watch the individual file
|
|
if (watchFile) {
|
|
fs.realpath(file, watch);
|
|
} else if (ignoredFilter(file)) {
|
|
watched.push(file);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
} catch (e) {
|
|
if ('EMFILE' === e.code) {
|
|
utils.log.error('EMFILE: Watching too many files.');
|
|
}
|
|
// ignoring this directory, likely it's "My Music"
|
|
// or some such windows fangled stuff
|
|
}
|
|
}
|
|
|
|
|
|
config.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.
|
|
utils.log.error('No clean method to watch files with - please report\nto http://github.com/remy/nodemon/issues/new with `nodemon --dump`');
|
|
}
|
|
});
|
|
|
|
// filter ignored files
|
|
function ignoredFilter(file) {
|
|
if (config.options.ignore.length && config.options.ignore.re) {
|
|
// If we are in a Windows machine
|
|
if (utils.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 !config.options.ignore.re.test(file);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function ignoredFileTypesForFind(dir) {
|
|
// search within dir for ignored files and paths
|
|
if (!config.options.ignore.length) {
|
|
return '';
|
|
}
|
|
var paths = [];
|
|
if (dir.charAt(dir.length - 1) != '/') {
|
|
dir += '/';
|
|
}
|
|
config.options.ignore.forEach(function (path) {
|
|
var pathIsDir = (path.charAt(path.length - 1) == '/');
|
|
if (pathIsDir) {
|
|
paths.push('! -ipath "' + dir + path + '*"');
|
|
}
|
|
paths.push('! -ipath "' + dir + path + '"');
|
|
});
|
|
return ' \\( ' + paths.join(' -and ') + ' \\)';
|
|
}
|
|
|
|
function filterAndRestart(files) {
|
|
if (files.length) {
|
|
var cwd = process.cwd();
|
|
utils.log.detail('files triggering change check: ' + files.map(function (file) {
|
|
return path.relative(cwd, file);
|
|
}).join(', '));
|
|
|
|
var matched = match(files, config.options.monitor, config.options.execOptions.ext);
|
|
|
|
utils.log.detail('changes after filters (before/after): ' + [files.length, matched.result.length].join('/'));
|
|
|
|
// reset the last check so we're only looking at recently modified files
|
|
config.lastStarted = Date.now();
|
|
|
|
if (matched.result.length) {
|
|
if (restartTimer !== null) {
|
|
clearTimeout(restartTimer);
|
|
}
|
|
restartTimer = setTimeout(function () {
|
|
utils.log.status('restarting due to changes...');
|
|
matched.result.map(function (file) {
|
|
utils.log.detail(path.relative(process.cwd(), file));
|
|
});
|
|
|
|
if (config.options.verbose) {
|
|
utils.log._log('');
|
|
}
|
|
|
|
bus.emit('restart', matched.result);
|
|
|
|
}, config.options.delay);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (config.system.useFind || config.options.legacyWatch) {
|
|
if (config.run) {
|
|
setTimeout(watch, config.timeout);
|
|
}
|
|
}
|
|
}
|
|
|
|
var watch = module.exports = function () {
|
|
// if we have useFind or useWatch (i.e. not using `find`)
|
|
// then called `changeFunction` which is local to this script
|
|
if ((config.system.useFind || config.system.useWatch || config.system.useWatchFile) && !config.options.legacyWatch) {
|
|
changeFunction(config.lastStarted, function (files) {
|
|
if (config.run) {
|
|
filterAndRestart(files);
|
|
}
|
|
});
|
|
} else {
|
|
// Fallback for when both find and fs.watch don't work
|
|
// using the `changedSince` which is external
|
|
changedSince(config.lastStarted, function (files) {
|
|
if (config.run) {
|
|
filterAndRestart(files);
|
|
}
|
|
});
|
|
}
|
|
}; |