Skip to content

Commit

Permalink
Implement ready event. Fixes paulmillr#102
Browse files Browse the repository at this point in the history
  • Loading branch information
amasad committed Feb 24, 2014
1 parent 7f94650 commit 05c90e1
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ watcher
.on('unlink', function(path) {console.log('File', path, 'has been removed');})
.on('unlinkDir', function(path) {console.log('Directory', path, 'has been removed');})
.on('error', function(error) {console.error('Error happened', error);})
.on('ready', function() {console.log('Files has been added and ready to detect changes')})

// 'add', 'addDir' and 'change' events also receive stat() results as second argument.
// http://nodejs.org/api/fs.html#fs_class_fs_stats
Expand Down
78 changes: 48 additions & 30 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,10 @@ FSWatcher.prototype._handleFile = function(file, stats, initialAdd) {
// directory - string, fs path.

// Returns nothing.
FSWatcher.prototype._handleDir = function(directory, stats, initialAdd) {
FSWatcher.prototype._handleDir = function(directory, stats, initialAdd, readyCallback) {
var read,
_this = this;
read = function(directory, initialAdd) {
read = function(directory, initialAdd, readyCallback) {
return fs.readdir(directory, function(error, current) {
var previous;
if (error != null) {
Expand All @@ -305,17 +305,20 @@ FSWatcher.prototype._handleDir = function(directory, stats, initialAdd) {
return _this._remove(directory, file);
});

var c = 0;
// Files that present in current directory snapshot
// but absent in previous are added to watch list and
// emit `add` event.
current.filter(function(file) {
return previous.indexOf(file) === -1;
}).forEach(function(file) {
_this._handle(sysPath.join(directory, file), initialAdd);
}).forEach(function(file, i, arr) {
_this._handle(sysPath.join(directory, file), initialAdd, function() {
if (++c === arr.length && readyCallback) readyCallback();
});
});
});
};
read(directory, initialAdd);
read(directory, initialAdd, readyCallback);
this._watch(directory, function(dir) {
return read(dir, false);
});
Expand All @@ -330,13 +333,14 @@ FSWatcher.prototype._handleDir = function(directory, stats, initialAdd) {
// item - string, path to file or directory.

// Returns nothing.
FSWatcher.prototype._handle = function(item, initialAdd) {
FSWatcher.prototype._handle = function(item, initialAdd, readyCallback) {
var _this = this;
if (this._isIgnored(item)) {
return;
}
return fs.realpath(item, function(error, path) {
if (error && error.code === 'ENOENT') {
readyCallback();
return;
}
if (error != null) {
Expand All @@ -347,16 +351,19 @@ FSWatcher.prototype._handle = function(item, initialAdd) {
return _this.emit('error', error);
}
if (_this.options.ignorePermissionErrors && (!_this._hasReadPermissions(stats))) {
readyCallback();
return;
}
if (_this._isIgnored.length === 2 && _this._isIgnored(item, stats)) {
readyCallback();
return;
}
if (stats.isFile()) {
_this._handleFile(item, stats, initialAdd);
readyCallback();
}
if (stats.isDirectory()) {
return _this._handleDir(item, stats, initialAdd);
return _this._handleDir(item, stats, initialAdd, readyCallback);
}
});
});
Expand All @@ -371,32 +378,40 @@ FSWatcher.prototype.emit = function() {
}
};

FSWatcher.prototype._addToFsEvents = function(files) {
FSWatcher.prototype._addToFsEvents = function(files, readyCallback) {
var handle,
_this = this;
_this = this,
c = 0,
fileCount = files.length;

handle = function(path) {
return _this.emit('add', path);
if (_this.options.ignoreInitial) {
_this.emit('add', path);
}
if (++c === fileCount) {
readyCallback();
}
};
files.forEach(function(file) {
if (!_this.options.ignoreInitial) {
fs.stat(file, function(error, stats) {
if (error != null) {
return _this.emit('error', error);
}
if (stats.isDirectory()) {
return recursiveReaddir(file, function(error, dirFiles) {
if (error != null) {
return _this.emit('error', error);
}
return dirFiles.filter(function(path) {
return !_this._isIgnored(path);
}).forEach(handle);
fs.stat(file, function(error, stats) {
if (error != null) {
return _this.emit('error', error);
}
if (stats.isDirectory()) {
return recursiveReaddir(file, function(error, dirFiles) {
if (error != null) {
return _this.emit('error', error);
}
var dirFiles = dirFiles.filter(function(path) {
return !_this._isIgnored(path);
});
} else {
return handle(file);
}
});
}
fileCount += dirFiles.length - 1;
dirFiles.forEach(handle);
});
} else {
return handle(file);
}
});
return _this._watchWithFsEvents(file);
});
return this;
Expand All @@ -416,10 +431,13 @@ FSWatcher.prototype.add = function(files) {
if (this._initialAdd == null) this._initialAdd = true;
if (!Array.isArray(files)) files = [files];

if (this.options.useFsEvents) return this._addToFsEvents(files);
if (this.options.useFsEvents) return this._addToFsEvents(files, this.emit.bind(this, 'ready'));

var c = 0;
files.forEach(function(file) {
return _this._handle(file, _this._initialAdd);
_this._handle(file, _this._initialAdd, function() {
if (++c === files.length) _this.emit('ready');
});
});
this._initialAdd = false;
return this;
Expand Down
43 changes: 41 additions & 2 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

var chai, chokidar, delay, expect, fixturesPath, fs, getFixturePath, isBinary, should, sinon, sysPath;
var chai, chokidar, delay, expect, fixturesPath, fs, getFixturePath, isBinary, should, sinon, sysPath, os;

chai = require('chai');

Expand All @@ -18,6 +18,8 @@ fs = require('fs');

sysPath = require('path');

os = require('os');

getFixturePath = function(subPath) {
return sysPath.join(__dirname, 'test-fixtures', subPath);
};
Expand Down Expand Up @@ -182,7 +184,7 @@ describe('chokidar', function() {
});
});
});
return describe('watch options', function() {
describe('watch options', function() {
return describe('ignoreInitial', function() {
var options;
options = {
Expand Down Expand Up @@ -279,6 +281,43 @@ describe('chokidar', function() {
});
});
});
describe('ready event', function() {
var tmpdir = os.tmpdir();
var testdir = sysPath.join(tmpdir, 'chokidar_test');
var subdir = sysPath.join(testdir, 'test_sub')
beforeEach(function() {
try {
fs.mkdirSync(testdir);
} catch (e) {
//ignore.
}
try {
fs.mkdirSync(subdir);
} catch (e) {
//ignore.
}
for (var i = 0; i < 50; i++) {
fs.writeFileSync(sysPath.join(testdir, i + ''), 'test_' + i);
}
for (var i = 0; i < 50; i++) {
fs.writeFileSync(sysPath.join(subdir, i + ''), 'test_sub_' + i);
}
});

afterEach(function() {
this.watcher.close();
});

it('should emit `ready` event when finished watching', function(done) {
this.watcher = chokidar.watch(testdir);
this.watcher.on('ready', done);
});

it('should emit `ready` with fsEvents', function(done) {
this.watcher = chokidar.watch(testdir, {usePolling: false});
this.watcher.on('ready', done);
});
});
});

describe('is-binary', function() {
Expand Down

0 comments on commit 05c90e1

Please sign in to comment.