Comparing version
module.exports = Filewalker; | ||
/* ----------------------------------------------------------- */ | ||
var path = require('path'), | ||
fs = require('fs'), | ||
var fs = require('fs'), | ||
path = require('path'), | ||
util = require('util'), | ||
EventEmitter = require('events').EventEmitter; | ||
FunctionQueue = require('fqueue'); | ||
var lstat = process.platform === 'win32' ? 'stat' : 'lstat'; | ||
/* ----------------------------------------------------------- */ | ||
function Filewalker(root, options) { | ||
if(!(this instanceof Filewalker)) return new Filewalker(root, options); | ||
FunctionQueue.call(this, options); | ||
var self = this; | ||
this.maxPending = -1; | ||
this.maxAttempts = 3; | ||
this.attemptTimeout = 5000; | ||
this.matchRegExp = null; | ||
@@ -34,3 +29,3 @@ | ||
} | ||
util.inherits(Filewalker, EventEmitter); | ||
util.inherits(Filewalker, FunctionQueue); | ||
@@ -45,102 +40,20 @@ Filewalker.prototype._path = function(p) { | ||
Filewalker.prototype._queueIsEmpty = function() { | ||
if(this.queue.length) { | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
}; | ||
Filewalker.prototype._enqueue = function(item, timeout) { | ||
if(timeout) { | ||
this.queue.push(['_timeout', timeout, item]); | ||
} else { | ||
this.queue.push(item); | ||
} | ||
}; | ||
Filewalker.prototype._dequeue = function() { | ||
if(this.paused) { | ||
return; | ||
} | ||
Filewalker.prototype._emitDir = function(p, s, fullPath) { | ||
var self = this, | ||
args = arguments; | ||
var item = this.queue.shift(); | ||
if(item) { | ||
this[item[0]].apply(this, item.slice(1)); | ||
this.dirs += 1; | ||
if(this.dirs) { // skip first directroy | ||
this.emit('dir', p, s, fullPath); | ||
} | ||
}; | ||
Filewalker.prototype._timeout = function(timeout, item) { | ||
if(!this._start()) { | ||
this._enqueue(['_timeout', timeout, item]); | ||
return; | ||
} | ||
var self = this; | ||
setTimeout(function() { | ||
self._enqueue(item); | ||
self._done(); | ||
}, timeout); | ||
}; | ||
Filewalker.prototype._start = function() { | ||
if(this.paused) { | ||
return false; | ||
} | ||
if(this.maxPending <= 0 || this.pending < this.maxPending) { | ||
this.pending += 1; | ||
return true; | ||
} | ||
return false; | ||
}; | ||
Filewalker.prototype._done = function() { | ||
this.pending -= 1; | ||
if(this._queueIsEmpty() === false && (this.maxPending <= 0 || this.pending < this.maxPending)) { | ||
this._dequeue(); | ||
} | ||
if(this.pending === 0) { | ||
if(this.paused) { | ||
this.emit('pause'); | ||
} else { | ||
this.emit('done'); | ||
} | ||
} | ||
}; | ||
Filewalker.prototype._emitDir = function(p, s, fullPath, prevErr, attempts) { | ||
var self = this; | ||
if(!this._start()) { | ||
this._enqueue(['_emitDir', p, s, fullPath, prevErr, attempts]); | ||
return; | ||
} | ||
attempts = attempts || 0; | ||
if(this.maxAttempts > -1 && attempts >= this.maxAttempts) { | ||
this.errors += 1; | ||
this.emit('error', prevErr); | ||
this._done(); | ||
return; | ||
} | ||
if(!attempts) { | ||
this.dirs += 1; | ||
if(this.dirs) { // skip first directroy | ||
this.emit('dir', p, s, fullPath); | ||
} | ||
} | ||
fs.readdir(fullPath, function(err, files) { | ||
if(err) { | ||
self.attempts += 1; | ||
self._enqueue(['_emitDir', p, s, fullPath, err, attempts+1], self.attemptTimeout); | ||
self.error(err, self._emitDir, args); | ||
} else { | ||
files.forEach(function(file) { | ||
self._stat(path.join(fullPath, file)); | ||
self.enqueue(self._stat, [path.join(fullPath, file)]); | ||
}); | ||
} | ||
self._done(); | ||
self.done(); | ||
}); | ||
@@ -152,7 +65,2 @@ }; | ||
if(!this._start()) { | ||
this._enqueue(['_emitFile', p, s, fullPath]); | ||
return; | ||
} | ||
this.files += 1; | ||
@@ -163,28 +71,14 @@ this.bytes += s.size; | ||
if(this.listeners('stream').length !== 0) { | ||
this._emitStream(p, s, fullPath); | ||
this.enqueue(this._emitStream, [p, s, fullPath]); | ||
} | ||
process.nextTick(function() { | ||
self._done(); | ||
self.done(); | ||
}); | ||
}; | ||
Filewalker.prototype._emitStream = function(p, s, fullPath, lastError, attempts) { | ||
var self = this; | ||
Filewalker.prototype._emitStream = function(p, s, fullPath) { | ||
var self = this, | ||
args = arguments; | ||
if(!this._start()) { | ||
this._enqueue(['_emitStream', p, s, fullPath, lastError, attempts]); | ||
return; | ||
} | ||
attempts = attempts || 0; | ||
if(this.maxAttempts > -1 && attempts >= this.maxAttempts) { | ||
process.stdout.write('\n'); | ||
console.log('Giving up after %s attempts', attempts, p); | ||
this.streamErrors += 1; | ||
this.emit('error', lastError); | ||
this._done(); | ||
return; | ||
} | ||
this.open += 1; | ||
@@ -198,14 +92,13 @@ | ||
if(err.code == 'OK' && err.errno === 0) { | ||
self._enqueue(['_emitStream', p, s, fullPath, err, attempts]); | ||
if(self.open-1>self.detectedMaxOpen) { | ||
self.detectedMaxOpen = self.open-1; | ||
} | ||
self.enqueue(self._emitStream, args); | ||
} else { | ||
self._enqueue(['_emitStream', p, s, fullPath, err, attempts+1], self.attemptTimeout); | ||
self.error(err, self._emitStream, args); | ||
} | ||
self.attempts += 1; | ||
self.open -= 1; | ||
self._done(); | ||
self.done(); | ||
}); | ||
@@ -216,3 +109,3 @@ | ||
self.open -= 1; | ||
self._done(); | ||
self.done(); | ||
}); | ||
@@ -224,60 +117,24 @@ | ||
Filewalker.prototype._stat = function(p, prevErr, attempts) { | ||
var self = this; | ||
Filewalker.prototype._stat = function(p) { | ||
var self = this, | ||
args = arguments; | ||
if(!this._start()) { | ||
this._enqueue(['_stat', p, prevErr, attempts]); | ||
return; | ||
} | ||
attempts = attempts || 0; | ||
if(this.maxAttempts > -1 && attempts >= this.maxAttempts) { | ||
this.errors += 1; | ||
this.emit('error', prevErr); | ||
this._done(); | ||
return; | ||
} | ||
if(!attempts) { | ||
this.total += 1; | ||
} | ||
fs[lstat](p, function(err, s) { | ||
if(err) { | ||
self.attempts += 1; | ||
self._enqueue(['_stat', p, err, attempts+1], self.attemptTimeout); | ||
self.error(err, self._stat, args); | ||
} else { | ||
self.total += 1; | ||
if(s.isDirectory()) { | ||
self._emitDir(self._path(p), s, p); | ||
self.enqueue(self._emitDir, [self._path(p), s, p]); | ||
} else { | ||
if(!self.matchRegExp || self.matchRegExp.test(p)) { | ||
self._emitFile(self._path(p), s, p); | ||
self.enqueue(self._emitFile, [self._path(p), s, p]); | ||
} | ||
} | ||
} | ||
self._done(); | ||
self.done(); | ||
}); | ||
}; | ||
Filewalker.prototype.pause = function() { | ||
this.paused = true; | ||
}; | ||
Filewalker.prototype.resume = function() { | ||
if(this.paused) { | ||
this.paused = false; | ||
if(this._queueIsEmpty()) { | ||
this.pending = 1; | ||
this._done(); | ||
} else { | ||
this._dequeue(); | ||
this.emit('resume'); | ||
} | ||
} | ||
}; | ||
Filewalker.prototype.walk = function() { | ||
this.paused = false; | ||
this.pending = 0; | ||
this.dirs = -1; | ||
@@ -288,7 +145,3 @@ this.files = 0; | ||
this.errors = 0; | ||
this.attempts = 0; | ||
this.streamed = 0; | ||
this.streamErrors = 0; | ||
this.open = 0; | ||
@@ -299,3 +152,4 @@ this.detectedMaxOpen = -1; | ||
this._stat(this.root); | ||
this.start(this._stat, [this.root]); | ||
return this; | ||
}; |
{ | ||
"name": "filewalker", | ||
"version": "0.0.3", | ||
"version": "0.1.0", | ||
"description": "Fast and rock-solid asynchronous traversing of directories and files for node.js", | ||
@@ -21,2 +21,3 @@ "author": { | ||
"dependencies": { | ||
"fqueue": "0.0.x" | ||
}, | ||
@@ -23,0 +24,0 @@ "scripts": { |
@@ -76,3 +76,3 @@ | ||
Inherits from events.EventEmitter | ||
Inherits from [node-fqueue](https://github.com/oleics/node-fqueue) | ||
@@ -113,5 +113,4 @@ ### Options | ||
streamed | ||
streamErrors | ||
open | ||
detectedMaxOpen | ||
detectedMaxOpen | ||
@@ -118,0 +117,0 @@ ### Methods |
@@ -33,2 +33,5 @@ | ||
}); | ||
it('are instances of fqueue', function() { | ||
assert.ok(fw instanceof require('fqueue')); | ||
}); | ||
it('should have a .maxPending property <number>', function() { | ||
@@ -164,23 +167,2 @@ assert.ok(fw.maxPending!=null); | ||
it('.streamErrors must be 0 if no listener for stream-event', function(done) { | ||
fw.on('done', function() { | ||
assert.ok(fw.streamErrors!=null); | ||
assert.strictEqual(typeof fw.streamErrors, 'number'); | ||
assert.strictEqual(fw.streamErrors, 0); | ||
}); | ||
fw.on('done', done); | ||
fw.walk(); | ||
}); | ||
it('.streamErrors must be 0 if listener for stream-event', function(done) { | ||
fw.on('stream', function(){}); | ||
fw.on('done', function() { | ||
assert.ok(fw.streamErrors!=null); | ||
assert.strictEqual(typeof fw.streamErrors, 'number'); | ||
assert.strictEqual(fw.streamErrors, 0); | ||
}); | ||
fw.on('done', done); | ||
fw.walk(); | ||
}); | ||
it('.open must be 0 if listener for stream-event', function(done) { | ||
@@ -187,0 +169,0 @@ fw.on('stream', function(){}); |
24040
-13.38%1
Infinity%583
-19.25%154
-0.65%+ Added
+ Added