sane
Advanced tools
Comparing version 0.0.2 to 0.1.0
80
index.js
@@ -43,5 +43,7 @@ var fs = require('fs'); | ||
this.watchers = []; | ||
this.changeTimers = {}; | ||
this.watched = Object.create(null); | ||
this.changeTimers = Object.create(null); | ||
this.dir = dir | ||
this.watchdir = this.watchdir.bind(this); | ||
this.stopWatching = this.stopWatching.bind(this); | ||
this.watchdir(dir); | ||
@@ -61,10 +63,26 @@ recReaddir(dir, this.watchdir, this.emit.bind(this, 'ready')); | ||
Watcher.prototype.watchdir = function(dir) { | ||
var relativePath = path.relative(this.dir, dir); | ||
var watcher = fs.watch(dir, function(event, filename) { | ||
this.onChange(path.join(relativePath, filename)); | ||
}.bind(this)); | ||
this.watchers.push(watcher); | ||
if (this.watched[dir]) return; | ||
var watcher = fs.watch( | ||
dir, | ||
{ persistent: this.persistent }, | ||
this.processChange.bind(this, dir) | ||
); | ||
this.watched[dir] = watcher; | ||
}; | ||
/** | ||
* Stop watching a dir.s | ||
* | ||
* @param {string} dir | ||
* @private | ||
*/ | ||
Watcher.prototype.stopWatching = function(dir) { | ||
if (this.watched[dir]) { | ||
this.watched[dir].close(); | ||
this.watched[dir] = null; | ||
} | ||
}; | ||
/** | ||
* End watching. | ||
@@ -76,6 +94,3 @@ * | ||
Watcher.prototype.close = function() { | ||
var watchers = this.watchers; | ||
for (var i = 0; i < watchers.length; i++) { | ||
watchers[i].close(); | ||
} | ||
Object.keys(this.watched).forEach(this.stopWatching); | ||
this.removeAllListeners(); | ||
@@ -85,22 +100,47 @@ }; | ||
/** | ||
* Triggers a 'change' event after debounding it to take care of duplicate | ||
* events on os x. | ||
* Process a change event. | ||
* | ||
* @private | ||
* @param {string} dir | ||
* @param {string} event | ||
* @param {string} file | ||
* @public | ||
*/ | ||
Watcher.prototype.onChange = function(file) { | ||
clearTimeout(this.changeTimers[file]); | ||
this.changeTimers[file] = setTimeout(function() { | ||
var globs = this.globs; | ||
if (globs.length) { | ||
Watcher.prototype.processChange = function(dir, event, file) { | ||
var fullPath = path.join(dir, file); | ||
var relativePath = path.join(path.relative(this.dir, dir), file); | ||
fs.stat(fullPath, function(error, stat) { | ||
if (error && error.code === 'ENOENT') { | ||
this.stopWatching(fullPath); | ||
return; | ||
} else if (error) { | ||
this.emit('error', error); | ||
return; | ||
} else if (stat.isDirectory()) { | ||
this.watchdir(fullPath); | ||
} else if (this.globs.length) { | ||
var globs = this.globs; | ||
for (var i = 0; i < globs.length; i++) { | ||
if (minimatch(file, globs[i])) { | ||
this.emit('change', file); | ||
this.emitChange(relativePath); | ||
} | ||
} | ||
} else { | ||
this.emit('change', file); | ||
this.emitChange(relativePath); | ||
} | ||
}.bind(this)); | ||
}; | ||
/** | ||
* Triggers a 'change' event after debounding it to take care of duplicate | ||
* events on os x. | ||
* | ||
* @private | ||
*/ | ||
Watcher.prototype.emitChange = function(file) { | ||
clearTimeout(this.changeTimers[file]); | ||
this.changeTimers[file] = setTimeout(function() { | ||
this.changeTimers[file] = null; | ||
this.emit('change', file); | ||
}.bind(this), 100); | ||
@@ -107,0 +147,0 @@ }; |
{ | ||
"name": "sane", | ||
"version": "0.0.2", | ||
"version": "0.1.0", | ||
"description": "Sane aims to be fast, small, and reliable file system watcher. No bells and whistles, just change events.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -0,1 +1,2 @@ | ||
var os = require('os'); | ||
var fs = require('fs'); | ||
@@ -7,3 +8,6 @@ var sane = require('../'); | ||
var testdir = '/private/tmp/sane_test'; | ||
var tmpdir = os.tmpdir(); | ||
var jo = path.join.bind(path); | ||
var testdir = jo(tmpdir, 'sane_test'); | ||
before(function() { | ||
@@ -15,4 +19,4 @@ rimraf.sync(testdir); | ||
for (var i = 0; i < 10; i++) { | ||
fs.writeFileSync(testdir + '/file_' + i, 'test_' + i); | ||
var subdir = testdir + '/sub_' + i; | ||
fs.writeFileSync(jo(testdir, 'file_' + i), 'test_' + i); | ||
var subdir = jo(testdir, 'sub_' + i); | ||
try { | ||
@@ -22,3 +26,3 @@ fs.mkdirSync(subdir); | ||
for (var j = 0; j < 10; j++) { | ||
fs.writeFileSync(subdir + '/file_' + j, 'test_' + j); | ||
fs.writeFileSync(jo(subdir, 'file_' + j), 'test_' + j); | ||
} | ||
@@ -42,3 +46,3 @@ } | ||
it('change emits event', function(done) { | ||
var testfile = testdir + '/file_1'; | ||
var testfile = jo(testdir, 'file_1'); | ||
this.watcher.on('change', function(filepath) { | ||
@@ -54,3 +58,3 @@ assert.equal(filepath, path.relative(testdir, testfile)); | ||
it('emits change events for subdir files', function(done) { | ||
var testfile = testdir + '/sub_1/file_1'; | ||
var testfile = jo(testdir, 'sub_1', 'file_1'); | ||
this.watcher.on('change', function(filepath) { | ||
@@ -66,3 +70,3 @@ assert.equal(filepath, path.relative(testdir, testfile)); | ||
it('adding a file will trigger a change', function(done) { | ||
var testfile = testdir + '/file_x' + Math.floor(Math.random() * 10000); | ||
var testfile = jo(testdir, 'file_x' + Math.floor(Math.random() * 10000)); | ||
this.watcher.on('change', function(filepath) { | ||
@@ -76,2 +80,35 @@ assert.equal(filepath, path.relative(testdir, testfile)); | ||
}); | ||
it('adding in a new subdir will trigger a change', function(done) { | ||
var subdir = jo(testdir, 'sub_x' + Math.floor(Math.random() * 10000)); | ||
var testfile = jo(subdir, 'file_x' + Math.floor(Math.random() * 10000)); | ||
this.watcher.on('change', function(filepath) { | ||
assert.equal(filepath, path.relative(testdir, testfile)); | ||
done(); | ||
}); | ||
this.watcher.on('ready', function() { | ||
fs.mkdirSync(subdir); | ||
defer(function() { | ||
fs.writeFileSync(testfile, 'wow'); | ||
}); | ||
}); | ||
}); | ||
it('closes watchers when dirs are deleted', function(done) { | ||
var subdir = jo(testdir, 'sub_1'); | ||
var testfile = jo(subdir, 'file_1'); | ||
this.watcher.on('change', function(filepath) { | ||
assert.equal(filepath, path.relative(testdir, testfile)); | ||
done(); | ||
}); | ||
this.watcher.on('ready', function() { | ||
rimraf.sync(subdir); | ||
defer(function() { | ||
fs.mkdirSync(subdir); | ||
defer(function() { | ||
fs.writeFileSync(testfile, 'wow'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -95,8 +132,12 @@ | ||
this.watcher.on('ready', function() { | ||
fs.writeFileSync(testdir + '/file_1', 'wow'); | ||
fs.writeFileSync(testdir + '/file_9', 'wow'); | ||
fs.writeFileSync(testdir + '/file_3', 'wow'); | ||
fs.writeFileSync(testdir + '/file_2', 'wow'); | ||
fs.writeFileSync(jo(testdir, 'file_1'), 'wow'); | ||
fs.writeFileSync(jo(testdir, 'file_9'), 'wow'); | ||
fs.writeFileSync(jo(testdir, 'file_3'), 'wow'); | ||
fs.writeFileSync(jo(testdir, 'file_2'), 'wow'); | ||
}); | ||
}); | ||
}); | ||
function defer(fn) { | ||
setTimeout(fn, 300); | ||
} |
8524
259