Comparing version 0.4.0 to 0.5.0
86
index.js
@@ -5,2 +5,3 @@ var fs = require('fs'); | ||
var walker = require('walker'); | ||
var platform = require('os').platform() | ||
var minimatch = require('minimatch'); | ||
@@ -187,5 +188,12 @@ var EventEmitter = require('events').EventEmitter; | ||
{ persistent: this.persistent }, | ||
this.processChange.bind(this, dir) | ||
this.normalizeChange.bind(this, dir) | ||
); | ||
this.watched[dir] = watcher; | ||
// Workaround Windows node issue #4337. | ||
if (platform === 'win32') { | ||
watcher.on('error', function(error) { | ||
if (error.code !== 'EPERM') throw error; | ||
}); | ||
} | ||
}; | ||
@@ -222,3 +230,5 @@ | ||
/** | ||
* Process a change event. | ||
* On some platforms, as pointed out on the fs docs (most likely just win32) | ||
* the file argument might be missing from the fs event. Try to detect what | ||
* change by detecting if something was deleted or the most recent file change. | ||
* | ||
@@ -231,7 +241,60 @@ * @param {string} dir | ||
Watcher.prototype.processChange = function(dir, event, file) { | ||
Watcher.prototype.detectChangedFile = function(dir, event, callback) { | ||
var found = false; | ||
var closest = {mtime: 0} | ||
var c = 0; | ||
Object.keys(this.dirRegistery[dir]).forEach(function(file, i, arr) { | ||
fs.stat(path.join(dir, file), function(error, stat) { | ||
if (found) return; | ||
if (error) { | ||
if (error.code === 'ENOENT') { | ||
found = true; | ||
callback(file); | ||
} else { | ||
this.emit('error', error); | ||
} | ||
} else { | ||
if (stat.mtime > closest.mtime) { | ||
stat.file = file; | ||
closest = stat; | ||
} | ||
if (arr.length === ++c) { | ||
callback(closest.file); | ||
} | ||
} | ||
}.bind(this)); | ||
}, this); | ||
}; | ||
/** | ||
* Normalize fs events and pass it on to be processed. | ||
* | ||
* @param {string} dir | ||
* @param {string} event | ||
* @param {string} file | ||
* @public | ||
*/ | ||
Watcher.prototype.normalizeChange = function(dir, event, file) { | ||
if (!file) { | ||
return; | ||
this.detectChangedFile(dir, event, function(actualFile) { | ||
if (actualFile) { | ||
this.processChange(dir, event, actualFile); | ||
} | ||
}.bind(this)); | ||
} else { | ||
this.processChange(dir, event, file); | ||
} | ||
}; | ||
/** | ||
* Process changes. | ||
* | ||
* @param {string} dir | ||
* @param {string} event | ||
* @param {string} file | ||
* @public | ||
*/ | ||
Watcher.prototype.processChange = function(dir, event, file) { | ||
var fullPath = path.join(dir, file); | ||
@@ -243,4 +306,7 @@ var relativePath = path.join(path.relative(this.root, dir), file); | ||
} else if (!error && stat.isDirectory()) { | ||
this.watchdir(fullPath); | ||
this.emitEvent(ADD_EVENT, relativePath); | ||
// win32 emits usless change events on dirs. | ||
if (event !== 'change') { | ||
this.watchdir(fullPath); | ||
this.emitEvent(ADD_EVENT, relativePath); | ||
} | ||
} else { | ||
@@ -347,4 +413,10 @@ var registered = this.registered(fullPath); | ||
.on('file', fileCallback) | ||
.on('end', endCallback); | ||
.on('end', function() { | ||
if (platform === 'win32') { | ||
setTimeout(endCallback, 1000); | ||
} else { | ||
endCallback(); | ||
} | ||
}); | ||
} | ||
{ | ||
"name": "sane", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Sane aims to be fast, small, and reliable file system watcher.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "node_modules/mocha/bin/mocha --bail" | ||
"test": "mocha --bail" | ||
}, | ||
@@ -9,0 +9,0 @@ "keywords": [ |
@@ -12,6 +12,12 @@ var os = require('os'); | ||
describe('sane in polling mode', harness.bind(this, true)); | ||
describe('sand in normal mode', harness.bind(this, false)); | ||
describe('sane in polling mode', function() { | ||
harness.call(this, true); | ||
}); | ||
describe('sand in normal mode', function() { | ||
harness.call(this, false); | ||
}); | ||
function harness(isPolling) { | ||
if (isPolling) this.timeout(5000); | ||
before(function() { | ||
@@ -87,3 +93,3 @@ rimraf.sync(testdir); | ||
this.watcher.on('ready', function() { | ||
fs.unlink(testfile, 'wow'); | ||
fs.unlinkSync(testfile); | ||
}); | ||
@@ -142,11 +148,18 @@ }); | ||
var i = 0; | ||
this.watcher.on('add', function(filepath) { | ||
if (++i === 1) { | ||
assert.equal(filepath, path.relative(testdir, subdir)); | ||
} else { | ||
assert.equal(filepath, path.relative(testdir, testfile)); | ||
done(); | ||
} | ||
}); | ||
var actualFiles = {}; | ||
this.watcher.on('ready', function() { | ||
this.watcher.on('add', function(filepath) { | ||
actualFiles[filepath] = true; | ||
if (Object.keys(actualFiles).length === 2) { | ||
// win32 order is not guaranteed | ||
var expectedFiles = {}; | ||
expectedFiles[path.relative(testdir, subdir)] = true; | ||
expectedFiles[path.relative(testdir, testfile)] = true; | ||
assert.deepEqual( | ||
expectedFiles, | ||
actualFiles | ||
); | ||
done(); | ||
} | ||
}); | ||
rimraf.sync(subdir); | ||
@@ -159,3 +172,3 @@ defer(function() { | ||
}); | ||
}); | ||
}.bind(this)); | ||
}); | ||
@@ -208,6 +221,7 @@ | ||
}); | ||
} | ||
function defer(fn) { | ||
setTimeout(fn, 300); | ||
function defer(fn) { | ||
setTimeout(fn, isPolling ? 1000 : 300); | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18436
569