the reminder not showing content on the card at dashboard view and the quizes are hardcoded must move to the db make api's for it
245 lines
6.4 KiB
JavaScript
245 lines
6.4 KiB
JavaScript
module.exports.watch = watch;
|
|
module.exports.resetWatchers = resetWatchers;
|
|
|
|
var debug = require('debug')('nodemon:watch');
|
|
var debugRoot = require('debug')('nodemon');
|
|
var chokidar = require('chokidar');
|
|
var undefsafe = require('undefsafe');
|
|
var config = require('../config');
|
|
var path = require('path');
|
|
var utils = require('../utils');
|
|
var bus = utils.bus;
|
|
var match = require('./match');
|
|
var watchers = [];
|
|
var debouncedBus;
|
|
|
|
bus.on('reset', resetWatchers);
|
|
|
|
function resetWatchers() {
|
|
debugRoot('resetting watchers');
|
|
watchers.forEach(function (watcher) {
|
|
watcher.close();
|
|
});
|
|
watchers = [];
|
|
}
|
|
|
|
function watch() {
|
|
if (watchers.length) {
|
|
debug('early exit on watch, still watching (%s)', watchers.length);
|
|
return;
|
|
}
|
|
|
|
var dirs = [].slice.call(config.dirs);
|
|
|
|
debugRoot('start watch on: %s', dirs.join(', '));
|
|
const rootIgnored = config.options.ignore;
|
|
debugRoot('ignored', rootIgnored);
|
|
|
|
var watchedFiles = [];
|
|
|
|
const promise = new Promise(function (resolve) {
|
|
const dotFilePattern = /[/\\]\./;
|
|
var ignored = match.rulesToMonitor(
|
|
[], // not needed
|
|
Array.from(rootIgnored),
|
|
config
|
|
).map(pattern => pattern.slice(1));
|
|
|
|
const addDotFile = dirs.filter(dir => dir.match(dotFilePattern));
|
|
|
|
// don't ignore dotfiles if explicitly watched.
|
|
if (addDotFile.length === 0) {
|
|
ignored.push(dotFilePattern);
|
|
}
|
|
|
|
var watchOptions = {
|
|
ignorePermissionErrors: true,
|
|
ignored: ignored,
|
|
persistent: true,
|
|
usePolling: config.options.legacyWatch || false,
|
|
interval: config.options.pollingInterval,
|
|
// note to future developer: I've gone back and forth on adding `cwd`
|
|
// to the props and in some cases it fixes bugs but typically it causes
|
|
// bugs elsewhere (since nodemon is used is so many ways). the final
|
|
// decision is to *not* use it at all and work around it
|
|
// cwd: ...
|
|
};
|
|
|
|
if (utils.isWindows) {
|
|
watchOptions.disableGlobbing = true;
|
|
}
|
|
|
|
if (utils.isIBMi) {
|
|
watchOptions.usePolling = true;
|
|
}
|
|
|
|
if (process.env.TEST) {
|
|
watchOptions.useFsEvents = false;
|
|
}
|
|
|
|
var watcher = chokidar.watch(
|
|
dirs,
|
|
Object.assign({}, watchOptions, config.options.watchOptions || {})
|
|
);
|
|
|
|
watcher.ready = false;
|
|
|
|
var total = 0;
|
|
|
|
watcher.on('change', filterAndRestart);
|
|
watcher.on('unlink', filterAndRestart);
|
|
watcher.on('add', function (file) {
|
|
if (watcher.ready) {
|
|
return filterAndRestart(file);
|
|
}
|
|
|
|
watchedFiles.push(file);
|
|
bus.emit('watching', file);
|
|
debug('chokidar watching: %s', file);
|
|
});
|
|
watcher.on('ready', function () {
|
|
watchedFiles = Array.from(new Set(watchedFiles)); // ensure no dupes
|
|
total = watchedFiles.length;
|
|
watcher.ready = true;
|
|
resolve(total);
|
|
debugRoot('watch is complete');
|
|
});
|
|
|
|
watcher.on('error', function (error) {
|
|
if (error.code === 'EINVAL') {
|
|
utils.log.error(
|
|
'Internal watch failed. Likely cause: too many ' +
|
|
'files being watched (perhaps from the root of a drive?\n' +
|
|
'See https://github.com/paulmillr/chokidar/issues/229 for details'
|
|
);
|
|
} else {
|
|
utils.log.error('Internal watch failed: ' + error.message);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
|
|
watchers.push(watcher);
|
|
});
|
|
|
|
return promise.catch(e => {
|
|
// this is a core error and it should break nodemon - so I have to break
|
|
// out of a promise using the setTimeout
|
|
setTimeout(() => {
|
|
throw e;
|
|
});
|
|
}).then(function () {
|
|
utils.log.detail(`watching ${watchedFiles.length} file${
|
|
watchedFiles.length === 1 ? '' : 's'}`);
|
|
return watchedFiles;
|
|
});
|
|
}
|
|
|
|
function filterAndRestart(files) {
|
|
if (!Array.isArray(files)) {
|
|
files = [files];
|
|
}
|
|
|
|
if (files.length) {
|
|
var cwd = process.cwd();
|
|
if (this.options && this.options.cwd) {
|
|
cwd = this.options.cwd;
|
|
}
|
|
|
|
utils.log.detail(
|
|
'files triggering change check: ' +
|
|
files
|
|
.map(file => {
|
|
const res = path.relative(cwd, file);
|
|
return res;
|
|
})
|
|
.join(', ')
|
|
);
|
|
|
|
// make sure the path is right and drop an empty
|
|
// filenames (sometimes on windows)
|
|
files = files.filter(Boolean).map(file => {
|
|
return path.relative(process.cwd(), path.relative(cwd, file));
|
|
});
|
|
|
|
if (utils.isWindows) {
|
|
// ensure the drive letter is in uppercase (c:\foo -> C:\foo)
|
|
files = files.map(f => {
|
|
if (f.indexOf(':') === -1) { return f; }
|
|
return f[0].toUpperCase() + f.slice(1);
|
|
});
|
|
}
|
|
|
|
|
|
debug('filterAndRestart on', files);
|
|
|
|
var matched = match(
|
|
files,
|
|
config.options.monitor,
|
|
undefsafe(config, 'options.execOptions.ext')
|
|
);
|
|
|
|
debug('matched?', JSON.stringify(matched));
|
|
|
|
// if there's no matches, then test to see if the changed file is the
|
|
// running script, if so, let's allow a restart
|
|
if (config.options.execOptions && config.options.execOptions.script) {
|
|
const script = path.resolve(config.options.execOptions.script);
|
|
if (matched.result.length === 0 && script) {
|
|
const length = script.length;
|
|
files.find(file => {
|
|
if (file.substr(-length, length) === script) {
|
|
matched = {
|
|
result: [file],
|
|
total: 1,
|
|
};
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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 (config.options.delay > 0) {
|
|
utils.log.detail('delaying restart for ' + config.options.delay + 'ms');
|
|
if (debouncedBus === undefined) {
|
|
debouncedBus = debounce(restartBus, config.options.delay);
|
|
}
|
|
debouncedBus(matched);
|
|
} else {
|
|
return restartBus(matched);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function restartBus(matched) {
|
|
utils.log.status('restarting due to changes...');
|
|
matched.result.map(file => {
|
|
utils.log.detail(path.relative(process.cwd(), file));
|
|
});
|
|
|
|
if (config.options.verbose) {
|
|
utils.log._log('');
|
|
}
|
|
|
|
bus.emit('restart', matched.result);
|
|
}
|
|
|
|
function debounce(fn, delay) {
|
|
var timer = null;
|
|
return function () {
|
|
const context = this;
|
|
const args = arguments;
|
|
clearTimeout(timer);
|
|
timer = setTimeout(() =>fn.apply(context, args), delay);
|
|
};
|
|
}
|