added event emitters, changed general usage

This commit is contained in:
AJ ONeal 2010-12-02 03:09:01 -07:00
parent 076c710594
commit 4857e3a168
9 changed files with 299 additions and 166 deletions

164
README.md
View File

@ -11,13 +11,17 @@ Installation
Usage Usage
==== ====
var walk = require('walk'), All of the examples in the folder included in this repository work and have no typos.
without emitter
----
var walk = require('walk').walk,
options = { options = {
followlinks: false, followLinks: false,
topdown: false, // currently ignored
}; };
function fileHandler(err, path, nodes, sorted) { function fileHandler(err, path, errors, dirs, files, links, blocks, chars, fifos, sockets) {
// handle each path // handle each path
} }
@ -25,18 +29,43 @@ Usage
// This also works // This also works
// walk("path/to/dir", options).whenever(fileHandler); // walk("path/to/dir", options).whenever(fileHandler);
* err - Probably can't read a directory due to permissions. Single Arguments
* path - the current path being read
* nodes - an array of `stats` * `err` - Error when reading path (Probably due to permissions).
* sorted - `nodes` sorted by type * `path` - the current path being read
* `errors` - nodes that could not be `stat`ed and why
* `files` - actual files (or links when `followlinks` is `true`) Array Arguments
* `dirs` - directories
* `blocks` - block devices * `errors` - `fs.stat` encountered on files in the directory
* `chars` - character devices * `dirs` - directories (modification of this array - sorting, removing, etc - affects traversal)
* `links` - symbolic links * `files` - regular files (includes links when `followLinks` is `true`)
* `fifos` - FIFOs * `links` - symbolic links (always empty when `followLinks` is `true`)
* `sockets` - sockets * `blocks` - block devices
* `chars` - character devices
* `fifos` - FIFOs
* `sockets` - sockets
using emitter
----
`errors`, `directories`, `files`, `symbolicLinks`
var walk = require('walk').walk,
emitter = walk('./walk-test');
emitter.on("directories", function (path, dirs) {
// the second directory will not be traversed
dirs.splice(1,1);
dirs.forEach(function (dir) {
console.log(dir);
});
});
emitter.on("files", function (path, files) {
files.forEach(function (dir) {
console.log(dir);
});
});
Example Example
==== ====
@ -52,114 +81,21 @@ node-walk-test
var walk = require('walk'); var walk = require('walk');
walk('./walk-test', undefined, function (err, path, nodes, sorted) { walk('./walk-test', undefined, function (err, path, errors, dirs, files, links) {
if (err) { if (err) {
console.log('ERROR: '); console.log('ERROR: ');
console.log(err); console.log(err);
return; return;
} }
sorted.dirs.forEach(function (item, i, arr) {
dirs.forEach(function (item, i, arr) {
if (item.name.match(/trash/i)) { if (item.name.match(/trash/i)) {
console.log('found a trash'); console.log('found a trash');
arr.splice(i,1); arr.splice(i,1);
} }
}); });
console.log("PATH: " + path); console.log("PATH: " + path);
console.log("SORTED: "); console.log("SORTED: ");
console.log(sorted); console.log(errors, dirs, files, links);
}); });
Output
----
PATH: ./walk-test
SORTED:
{ errors: [],
files:
[ { dev: 234881026,
ino: 30682245,
mode: 33204,
nlink: 1,
uid: 504,
gid: 20,
rdev: 0,
size: 0,
blksize: 4096,
blocks: 0,
atime: Sun, 21 Nov 2010 04:48:23 GMT,
mtime: Sun, 21 Nov 2010 04:48:23 GMT,
ctime: Sun, 21 Nov 2010 04:48:23 GMT,
name: 'file-1' },
{ dev: 234881026,
ino: 30682246,
mode: 33204,
nlink: 1,
uid: 504,
gid: 20,
rdev: 0,
size: 0,
blksize: 4096,
blocks: 0,
atime: Sun, 21 Nov 2010 04:48:23 GMT,
mtime: Sun, 21 Nov 2010 04:48:23 GMT,
ctime: Sun, 21 Nov 2010 04:48:23 GMT,
name: 'file-2' } ],
dirs:
[ { dev: 234881026,
ino: 30682244,
mode: 16893,
nlink: 4,
uid: 504,
gid: 20,
rdev: 0,
size: 136,
blksize: 4096,
blocks: 0,
atime: Sun, 21 Nov 2010 04:49:40 GMT,
mtime: Sun, 21 Nov 2010 04:48:23 GMT,
ctime: Sun, 21 Nov 2010 04:48:23 GMT,
name: 'dir1' } ],
blocks: [],
chars: [],
links: [],
fifos: [],
sockets: [] }
PATH: walk-test/dir1
SORTED:
{ errors: [],
files:
[ { dev: 234881026,
ino: 30682247,
mode: 33204,
nlink: 1,
uid: 504,
gid: 20,
rdev: 0,
size: 0,
blksize: 4096,
blocks: 0,
atime: Sun, 21 Nov 2010 04:48:23 GMT,
mtime: Sun, 21 Nov 2010 04:48:23 GMT,
ctime: Sun, 21 Nov 2010 04:48:23 GMT,
name: 'file-1' },
{ dev: 234881026,
ino: 30682248,
mode: 33204,
nlink: 1,
uid: 504,
gid: 20,
rdev: 0,
size: 0,
blksize: 4096,
blocks: 0,
atime: Sun, 21 Nov 2010 04:48:23 GMT,
mtime: Sun, 21 Nov 2010 04:48:23 GMT,
ctime: Sun, 21 Nov 2010 04:48:23 GMT,
name: 'file-2' } ],
dirs: [],
blocks: [],
chars: [],
links: [],
fifos: [],
sockets: [] }

25
examples/walk-array-emitters.js Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env node
(function () {
var walk = require('../lib/walk').walk,
// todo remove(arr, obj, true), remove(arr, from, to)
remove = require('../lib/walk').remove,
util = require('util');
Array.prototype.removeAt = function (i) {
return this.splice(i, 1)[0];
}
var count = 0, emitter = walk('/System');
emitter.on("directories", function (path, dirs) {
count += 1;
console.log('[' + count + '] REMOVED: ' + [path,dirs.splice(0,1).name].join('/'));
console.log(dirs);
});
emitter.on("files", function (path, files) {
count += 1;
console.log('[' + count + '] F:' + [path,files[0].name].join('/'));
console.log(files);
});
}());

View File

@ -0,0 +1 @@
require('../lib/walk')();

39
examples/walk-pythonic.js Normal file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env node
(function () {
var walk = require('../lib/walk').walk,
remove = require('../lib/walk').remove,
util = require('util'),
emitter = walk('/System'),
whenever;
whenever = function (cb, eb) {
emitter.whenever(function (err, path, errs, dirs, files, links) {
if (err || errs.length) {
eb(path, err, errs);
if (err) { return; }
}
cb(path, dirs, files.concat(links));
});
}
// A much more pythonic style
whenever(function (path, dirs, files) {
console.log(path);
if (dirs.length) {
console.log(dirs);
}
if (files.length) {
console.log(files);
}
}, function (path, err, errs) {
util.debug(path);
if (err) {
util.debug(err);
} else if (errs.length) {
util.debug(errs);
} else {
throw new Error("No Error when Error Expected");
}
});
}());

View File

@ -0,0 +1,23 @@
#!/usr/bin/env node
(function () {
var walk = require('../lib/walk').walk,
// todo remove(arr, obj, true), remove(arr, from, to)
remove = require('../lib/walk').remove,
util = require('util');
Array.prototype.removeAt = function (i) {
return this.splice(i, 1)[0];
}
var count = 0, emitter = walk('/System');
emitter.on("directory", function (path, stats) {
count += 1;
console.log('[' + count + '] D:' + [path,stats.name].join('/'));
});
emitter.on("file", function (path, stats) {
count += 1;
console.log('[' + count + '] F:' + [path,stats.name].join('/'));
});
}());

37
examples/walk-whenever.js Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env node
(function () {
var walk = require('../lib/walk').walk,
// todo remove(arr, obj, true), remove(arr, from, to)
remove = require('../lib/walk').remove,
util = require('util'),
emitter = walk('/System');
emitter.whenever(function (err, path, errs, dirs, files, links, blocks, chars, fifos, sockets) {
// If there was an error reading the directory
// then we can return already
if (err) {
util.debug('ERROR reading path: ' + path + '\n' + util.inspect(err));
return;
}
// If there was an error `stat`ing a node
// then there may still be other nodes read successfully
if (errs) {
errs.forEach(function (err) {
util.debug('ERROR fs.stat node: ' + path + '\n' + util.inspect(err));
});
}
//
dirs.forEach(function (item, i, arr) {
if (item.name.match(/trash/i)) {
console.log('REMOVE: found a trash');
remove(arr, item);
}
});
console.log("PATH: " + path);
console.log("FILES: " + util.inspect(files));
});
}());

View File

@ -3,25 +3,99 @@
Futures = require('futures'), Futures = require('futures'),
joinPath = require('path').join, joinPath = require('path').join,
util = require('util'), util = require('util'),
dir = process.argv[2]; ev = require("events"),
emitter = new ev.EventEmitter(),
oneNodeEvent = [
"file",
"directory",
"blockDevice",
"characterDevice",
"symbolicLink",
"fifo",
"socket"
],
multiNodeEvents = [
// multiple
"files",
"directories",
"blockDevices",
"characterDevices",
"symbolicLinks",
"fifos",
"sockets"
],
eventsTpl = {
listeners: function () { return []; },
next: function () { return; }
},
events = {},
nexts = {};
function sortNodesByType(stats, o) { function newVersion() {
throw new Error("see README.md at http://github.com/coolaj86/node-walk");
}
function noop() {
}
function remove(arr, obj) {
return arr.splice(arr.indexOf(obj), 1);
}
oneNodeEvent.forEach(function (key) {
var e = events[key] = {}, next;
Object.keys(eventsTpl).forEach(function (k) {
e[k] = eventsTpl[k]();
});
emitter.on("newListener", function (ev, listener) {
var count = 0,
num = e.listeners.length + 1;
e.listeners.push(listener);
e.next = function (cb) {
cb = noop;
return function () {
if (count === num) { cb(); }
count += 1;
};
};
});
// TODO
next = function () {
};
});
function sortNodesByType(path, stats, o, cb) {
if (stats.isFile()) { if (stats.isFile()) {
o.files.push(stats); o.files.push(stats);
emitter.emit("file", path, stats, (nexts["file"]||noop)(cb));
} else if (stats.isDirectory()) { } else if (stats.isDirectory()) {
o.dirs.push(stats); o.dirs.push(stats);
emitter.emit("directory", path, stats, function () {
remove(o.dirs, stats);
}, (nexts["directory"]||noop)(cb));
} else if (stats.isBlockDevice()) { } else if (stats.isBlockDevice()) {
o.blocks.push(stats); o.blocks.push(stats);
emitter.emit("blockDevice", path, stats, (nexts["blockDevice"]||noop)(cb));
} else if (stats.isCharacterDevice()) { } else if (stats.isCharacterDevice()) {
o.chars.push(stats); o.chars.push(stats);
emitter.emit("characterDevice", path, stats, (nexts["characterDevice"]||noop)(cb));
} else if (stats.isSymbolicLink()) { } else if (stats.isSymbolicLink()) {
o.links.push(stats); o.links.push(stats);
emitter.emit("symbolicLink", path, stats, (nexts["symbolicLink"]||noop)(cb));
} else if (stats.isFIFO()) { } else if (stats.isFIFO()) {
o.fifos.push(stats); o.fifos.push(stats);
emitter.emit("fifo", path, stats, (nexts["fifo"]||noop)(cb));
} else if (stats.isSocket()) { } else if (stats.isSocket()) {
o.sockets.push(stats); o.sockets.push(stats);
emitter.emit("socket", path, stats, (nexts["socket"]||noop)(cb));
} else { } else {
util.debug(stats.node + 'is not of any node type'); // emitter.emit("error", stats);
util.debug(stats.name + 'is not of any node type');
} }
} }
@ -41,13 +115,13 @@
// currently ignored // currently ignored
topdown: boolean, topdown: boolean,
onerror: boolean, // ignored onerror: boolean, // ignored
followlinks: boolean // lstat or stat followLinks: boolean // lstat or stat
}); });
*/ */
function walk(firstPath, options, callback) { function walk(firstPath, options, callback) {
options = options || {}; options = options || {};
var fstat = options.followlinks ? fs.stat : fs.lstat, var fstat = options.followLinks ? fs.stat : fs.lstat,
subscription = Futures.subscription(); subscription = Futures.subscription();
if (callback) { subscription.subscribe(callback); } if (callback) { subscription.subscribe(callback); }
@ -58,7 +132,7 @@
fs.readdir(path, function (err, files) { fs.readdir(path, function (err, files) {
if (err) { if (err) {
err.path = path; err.path = path;
subscription.deliver(err, path, undefined, undefined); subscription.deliver(err, path);
// Signal the completion of this readdir attempt // Signal the completion of this readdir attempt
p.fulfill(); p.fulfill();
return; return;
@ -69,16 +143,17 @@
nodes = [], nodes = [],
o = { o = {
errors: [], errors: [],
files: [],
dirs: [], dirs: [],
files: [],
links: [],
blocks: [], blocks: [],
chars: [], chars: [],
links: [],
fifos: [], fifos: [],
sockets: [] sockets: []
}; };
files.forEach(function (file) { files.forEach(function (file) {
// pushes onto the sequence stack without recursion
s.then(function (next) { s.then(function (next) {
fstat(joinPath(path, file), function (err, stats) { fstat(joinPath(path, file), function (err, stats) {
stats = stats || {}; stats = stats || {};
@ -89,7 +164,7 @@
stats.err = err; stats.err = err;
o.errors.push(stats); o.errors.push(stats);
} else { } else {
sortNodesByType(stats, o); sortNodesByType(path, stats, o);
} }
next(); next();
@ -99,17 +174,43 @@
s.then(function (next) { s.then(function (next) {
var s2 = Futures.sequence(function(n){n();}); var s2 = Futures.sequence(function(n){n();});
subscription.deliver(undefined, path, nodes, o); if (nodes.length > 0) {
p.fulfill(); subscription.deliver(undefined, path, o.errors, o.dirs, o.files, o.links, o.blocks, o.chars, o.fifos, o.sockets);
if (o.errors.length > 0) {
emitter.emit("errors", path, o.errors);
}
if (o.dirs.length > 0) {
emitter.emit("directories", path, o.dirs);
}
if (o.files.length > 0) {
emitter.emit("files", path, o.files);
}
if (o.links.length > 0) {
emitter.emit("symbolicLinks", path, o.links);
}
if (o.blocks.length > 0) {
emitter.emit("blockDevices", path, o.blocks);
}
if (o.chars.length > 0) {
emitter.emit("characterDevices", path, o.chars);
}
if (o.fifos.length > 0) {
emitter.emit("fifos", path, o.fifos);
}
if (o.sockets.length > 0) {
emitter.emit("sockets", path, o.fifos);
}
p.fulfill();
o.dirs.forEach(function (dir) { o.dirs.forEach(function (dir) {
s2.then(function (next2) { s2.then(function (next2) {
readDir(joinPath(path, dir.name)) readDir(joinPath(path, dir.name))
.when(function () { next2(); }); .when(function () { next2(); });
});
}); });
});
next(); next();
}
}); });
}); });
@ -119,10 +220,11 @@
readDir(firstPath) //.whenever(callback); readDir(firstPath) //.whenever(callback);
return { emitter.whenever = subscription.subscribe;
whenever: subscription.subscribe return emitter;
}
} }
module.exports = walk; newVersion.walk = walk;
newVersion.remove = remove;
module.exports = newVersion;
}()); }());

View File

@ -8,5 +8,5 @@
"dependencies" : ["futures"], "dependencies" : ["futures"],
"lib" : "lib", "lib" : "lib",
"main" : "./lib/walk.js", "main" : "./lib/walk.js",
"version" : "0.9.1" "version" : "0.9.2"
} }

View File

@ -1,30 +0,0 @@
#!/usr/bin/env node
(function () {
var walk = require('./lib/walk');
Array.prototype.removeAt = function (i) {
return this.splice(i, 1)[0];
}
walk('./walk-test').whenever(function (err, path, nodes, o) {
if (err) {
console.log('ERROR: ');
console.log(err);
return;
}
o.dirs.forEach(function (item, i, arr) {
if (item.name.match(/trash/i)) {
console.log('found a trash');
arr.removeAt(i);
}
});
console.log("PATH: " + path);
console.log("SORTED: ");
console.log(o);
});
setTimeout(function () {
process.nextTick(process.exit);
}, 200);
}());