Skip to content

Commit

Permalink
add a 'ready' event
Browse files Browse the repository at this point in the history
This is fires once the watchers are created.

* For single files,
  this happens immediately.

* For directories on macOS/Windows (recursive, and non-recursive)
  this happens after hasNativeRecursive() callback.

* For directories on Linux (non-recursive)
  this happens after hasNativeRecursive() callback.

* For directories on Linux (recursive)
  this happens after hasNativeRecursive() callback and after
  each recursive call to watchDirectory() via getSubDirectories()
  is completed. To keep track of this, use a counting semaphore.

Fixes yuanchuan#71
  • Loading branch information
Krinkle committed Dec 28, 2018
1 parent b3311d8 commit f72173a
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 5 deletions.
48 changes: 43 additions & 5 deletions lib/watch.js
Expand Up @@ -113,7 +113,7 @@ function createDupsFilter() {
}
}

function getSubDirectories(dir, fn) {
function getSubDirectories(dir, fn, done) {
if (is.directory(dir)) {
fs.readdir(dir, function(err, all) {
if (err) {
Expand All @@ -126,11 +126,29 @@ function getSubDirectories(dir, fn) {
var sdir = path.join(dir, f);
if (is.directory(sdir)) fn(sdir);
});
done();
}
});
} else {
done();
}
}

function semaphore(final) {
var counter = 0;
return function start() {
counter++;
return function stop() {
counter--;
if (counter === 0) final();
};
};
}

function nullCounter() {
return function nullStop() {};
}

var deprecationWarning = util.deprecate(
function() {},
'(node-watch) First param in callback function\
Expand All @@ -141,6 +159,7 @@ var deprecationWarning = util.deprecate(
function Watcher() {
events.EventEmitter.call(this);
this.watchers = {};
this._isReady = false;
this._isClosed = false;
}

Expand Down Expand Up @@ -189,6 +208,17 @@ Watcher.prototype.close = function(fullPath) {
process.nextTick(emitClose, this);
};

function emitReady(self) {
if (!self._isReady) {
self._isReady = true;
// do not call emit for 'ready' until after watch() has returned,
// so that consumer can call on().
process.nextTick(function () {
self.emit('ready');
});
}
}

function emitClose(self) {
self.emit('close');
}
Expand Down Expand Up @@ -281,8 +311,10 @@ Watcher.prototype.watchFile = function(file, options, fn) {
}
}

Watcher.prototype.watchDirectory = function(dir, options, fn) {
Watcher.prototype.watchDirectory = function(dir, options, fn, counter) {
counter = counter || nullCounter;
var self = this;
var done = counter();
hasNativeRecursive(function(has) {
// always specify recursive
options.recursive = !!options.recursive;
Expand All @@ -309,9 +341,11 @@ Watcher.prototype.watchDirectory = function(dir, options, fn) {

if (options.recursive && !has) {
getSubDirectories(dir, function(d) {
self.watchDirectory(d, options);
});
self.watchDirectory(d, options, counter);
}, counter());
}

done();
});
}

Expand Down Expand Up @@ -380,10 +414,14 @@ function watch(fpath, options, fn) {

if (is.file(fpath)) {
watcher.watchFile(fpath, options, fn);
emitReady(watcher);
}

else if (is.directory(fpath)) {
watcher.watchDirectory(fpath, options, fn);
var counter = semaphore(function () {
emitReady(watcher);
});
watcher.watchDirectory(fpath, options, fn, counter);
}

return watcher.expose();
Expand Down
17 changes: 17 additions & 0 deletions test/test.js
Expand Up @@ -124,6 +124,23 @@ describe('events', function() {
watcher.close();
});

it('should emit `ready` event when watching a file', function(done) {
var file = 'home/a/file1';
var fpath = tree.getPath(file);
watcher = watch(fpath);
watcher.on('ready', function() {
done();
});
});

it('should emit `ready` event when watching a directory recursively', function(done) {
var dir = tree.getPath('home');
watcher = watch(dir, { recursive: true });
watcher.on('ready', function() {
done();
});
});

it('should report `update` on new files', function(done) {
var dir = tree.getPath('home/a');
var file = 'home/a/newfile' + Date.now();
Expand Down

0 comments on commit f72173a

Please sign in to comment.