mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
104 lines
3.9 KiB
JavaScript
104 lines
3.9 KiB
JavaScript
var fs = require("fs");
|
|
|
|
// Set this env variable to a truthy value to force fs.watchFile instead
|
|
// of pathwatcher.watch.
|
|
var PATHWATCHER_ENABLED = !process.env.METEOR_WATCH_FORCE_POLLING;
|
|
|
|
var DEFAULT_POLLING_INTERVAL =
|
|
~~process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 5000;
|
|
|
|
|
|
var NO_PATHWATCHER_POLLING_INTERVAL =
|
|
~~process.env.METEOR_WATCH_POLLING_INTERVAL_MS || 500;
|
|
|
|
var suggestedRaisingWatchLimit = false;
|
|
|
|
exports.watch = function watch(absPath, callback) {
|
|
var lastPathwatcherEventTime = 0;
|
|
|
|
function pathwatcherWrapper() {
|
|
// It's tempting to call fs.unwatchFile(absPath, watchFileWrapper)
|
|
// here, but previous pathwatcher success is no guarantee of future
|
|
// pathwatcher reliability. For example, pathwatcher works just fine
|
|
// when file changes originate from within a Vagrant VM, but changes
|
|
// to shared files made outside the VM are invisible to pathwatcher,
|
|
// so our only hope of catching them is to continue polling.
|
|
lastPathwatcherEventTime = +new Date;
|
|
callback.apply(this, arguments);
|
|
}
|
|
|
|
var watcher = null;
|
|
if (PATHWATCHER_ENABLED) {
|
|
var pathwatcher = require('meteor-pathwatcher-tweaks');
|
|
try {
|
|
watcher = pathwatcher.watch(absPath, pathwatcherWrapper);
|
|
} catch (e) {
|
|
// If it isn't an actual pathwatcher failure, rethrow.
|
|
if (e.message !== 'Unable to watch path')
|
|
throw e;
|
|
var constants = require('constants');
|
|
var archinfo = require('./archinfo.js');
|
|
if (! suggestedRaisingWatchLimit &&
|
|
// Note: the not-super-documented require('constants') maps from
|
|
// strings to SYSTEM errno values. System errno values aren't the same
|
|
// as the numbers used internally by libuv! It would be nice to just
|
|
// make pathwatcher process the system errno into a string for us, but
|
|
// this is a pain, because posix doesn't give us a function to give us
|
|
// 'ENOSPC'-style strings (just the longer strings that strerror gives
|
|
// you). While libuv does give us uv_err_name, it takes in a *UV*
|
|
// errno value, which is different from the system errno value, and
|
|
// the translation function is not exposed:
|
|
// https://github.com/libuv/libuv/issues/79
|
|
e.code === constants.ENOSPC &&
|
|
// The only suggestion we currently have is for Linux.
|
|
archinfo.matches(archinfo.host(), 'os.linux')) {
|
|
suggestedRaisingWatchLimit = true;
|
|
var Console = require('./console.js').Console;
|
|
Console.arrowWarn(
|
|
"It looks like a simple tweak to your system's configuration will " +
|
|
"make many tools (including this Meteor command) more efficient. " +
|
|
"To learn more, see " +
|
|
Console.url("https://github.com/meteor/meteor/wiki/File-Change-Watcher-Efficiency"));
|
|
}
|
|
// ... ignore the error. We'll still have watchFile, which is good
|
|
// enough.
|
|
}
|
|
}
|
|
|
|
var pollingInterval = watcher
|
|
? DEFAULT_POLLING_INTERVAL : NO_PATHWATCHER_POLLING_INTERVAL;
|
|
|
|
function watchFileWrapper() {
|
|
// If a pathwatcher event fired in the last polling interval, ignore
|
|
// this event.
|
|
if (new Date - lastPathwatcherEventTime > pollingInterval) {
|
|
callback.apply(this, arguments);
|
|
}
|
|
}
|
|
|
|
// We use fs.watchFile in addition to pathwatcher.watch as a fail-safe to
|
|
// detect file changes even on network file systems. However (unless the user
|
|
// disabled pathwatcher or this pathwatcher call failed), we use a relatively
|
|
// long default polling interval of 5000ms to save CPU cycles.
|
|
fs.watchFile(absPath, {
|
|
persistent: false,
|
|
interval: pollingInterval
|
|
}, watchFileWrapper);
|
|
|
|
var polling = true;
|
|
|
|
return {
|
|
close: function close() {
|
|
if (watcher) {
|
|
watcher.close();
|
|
watcher = null;
|
|
}
|
|
|
|
if (polling) {
|
|
polling = false;
|
|
fs.unwatchFile(absPath, watchFileWrapper);
|
|
}
|
|
}
|
|
};
|
|
};
|