diff --git a/README.md b/README.md index ef93d4b..6db84fe 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,17 @@ Installation 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 = { - followlinks: false, - topdown: false, // currently ignored + followLinks: false, }; - function fileHandler(err, path, nodes, sorted) { + function fileHandler(err, path, errors, dirs, files, links, blocks, chars, fifos, sockets) { // handle each path } @@ -25,18 +29,43 @@ Usage // This also works // walk("path/to/dir", options).whenever(fileHandler); - * err - Probably can't read a directory due to permissions. - * path - the current path being read - * nodes - an array of `stats` - * sorted - `nodes` sorted by type - * `errors` - nodes that could not be `stat`ed and why - * `files` - actual files (or links when `followlinks` is `true`) - * `dirs` - directories - * `blocks` - block devices - * `chars` - character devices - * `links` - symbolic links - * `fifos` - FIFOs - * `sockets` - sockets +Single Arguments + + * `err` - Error when reading path (Probably due to permissions). + * `path` - the current path being read + +Array Arguments + + * `errors` - `fs.stat` encountered on files in the directory + * `dirs` - directories (modification of this array - sorting, removing, etc - affects traversal) + * `files` - regular files (includes links when `followLinks` is `true`) + * `links` - symbolic links (always empty when `followLinks` is `true`) + * `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 ==== @@ -52,114 +81,21 @@ node-walk-test 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) { console.log('ERROR: '); console.log(err); return; } - sorted.dirs.forEach(function (item, i, arr) { + + dirs.forEach(function (item, i, arr) { if (item.name.match(/trash/i)) { console.log('found a trash'); arr.splice(i,1); } }); + console.log("PATH: " + path); 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: [] } diff --git a/examples/walk-array-emitters.js b/examples/walk-array-emitters.js new file mode 100755 index 0000000..988ccfb --- /dev/null +++ b/examples/walk-array-emitters.js @@ -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); + }); +}()); diff --git a/examples/walk-older-version.js b/examples/walk-older-version.js new file mode 100644 index 0000000..15b22a8 --- /dev/null +++ b/examples/walk-older-version.js @@ -0,0 +1 @@ +require('../lib/walk')(); diff --git a/examples/walk-pythonic.js b/examples/walk-pythonic.js new file mode 100644 index 0000000..f2a352e --- /dev/null +++ b/examples/walk-pythonic.js @@ -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"); + } + }); +}()); diff --git a/examples/walk-singles-emitter.js b/examples/walk-singles-emitter.js new file mode 100755 index 0000000..5f7cd5e --- /dev/null +++ b/examples/walk-singles-emitter.js @@ -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('/')); + }); +}()); diff --git a/examples/walk-whenever.js b/examples/walk-whenever.js new file mode 100755 index 0000000..757d72a --- /dev/null +++ b/examples/walk-whenever.js @@ -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)); + }); + +}()); diff --git a/lib/walk.js b/lib/walk.js index ae95226..ba63b57 100644 --- a/lib/walk.js +++ b/lib/walk.js @@ -3,25 +3,99 @@ Futures = require('futures'), joinPath = require('path').join, 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()) { o.files.push(stats); + emitter.emit("file", path, stats, (nexts["file"]||noop)(cb)); } else if (stats.isDirectory()) { o.dirs.push(stats); + emitter.emit("directory", path, stats, function () { + remove(o.dirs, stats); + }, (nexts["directory"]||noop)(cb)); } else if (stats.isBlockDevice()) { o.blocks.push(stats); + emitter.emit("blockDevice", path, stats, (nexts["blockDevice"]||noop)(cb)); } else if (stats.isCharacterDevice()) { o.chars.push(stats); + emitter.emit("characterDevice", path, stats, (nexts["characterDevice"]||noop)(cb)); } else if (stats.isSymbolicLink()) { o.links.push(stats); + emitter.emit("symbolicLink", path, stats, (nexts["symbolicLink"]||noop)(cb)); } else if (stats.isFIFO()) { o.fifos.push(stats); + emitter.emit("fifo", path, stats, (nexts["fifo"]||noop)(cb)); } else if (stats.isSocket()) { o.sockets.push(stats); + emitter.emit("socket", path, stats, (nexts["socket"]||noop)(cb)); } 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 topdown: boolean, onerror: boolean, // ignored - followlinks: boolean // lstat or stat + followLinks: boolean // lstat or stat }); */ function walk(firstPath, options, callback) { options = options || {}; - var fstat = options.followlinks ? fs.stat : fs.lstat, + var fstat = options.followLinks ? fs.stat : fs.lstat, subscription = Futures.subscription(); if (callback) { subscription.subscribe(callback); } @@ -58,7 +132,7 @@ fs.readdir(path, function (err, files) { if (err) { err.path = path; - subscription.deliver(err, path, undefined, undefined); + subscription.deliver(err, path); // Signal the completion of this readdir attempt p.fulfill(); return; @@ -69,16 +143,17 @@ nodes = [], o = { errors: [], - files: [], dirs: [], + files: [], + links: [], blocks: [], chars: [], - links: [], fifos: [], sockets: [] }; files.forEach(function (file) { + // pushes onto the sequence stack without recursion s.then(function (next) { fstat(joinPath(path, file), function (err, stats) { stats = stats || {}; @@ -89,7 +164,7 @@ stats.err = err; o.errors.push(stats); } else { - sortNodesByType(stats, o); + sortNodesByType(path, stats, o); } next(); @@ -99,17 +174,43 @@ s.then(function (next) { var s2 = Futures.sequence(function(n){n();}); - subscription.deliver(undefined, path, nodes, o); - p.fulfill(); + if (nodes.length > 0) { + 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) { - s2.then(function (next2) { - readDir(joinPath(path, dir.name)) - .when(function () { next2(); }); + o.dirs.forEach(function (dir) { + s2.then(function (next2) { + readDir(joinPath(path, dir.name)) + .when(function () { next2(); }); + }); }); - }); - next(); + next(); + } }); }); @@ -119,10 +220,11 @@ readDir(firstPath) //.whenever(callback); - return { - whenever: subscription.subscribe - } + emitter.whenever = subscription.subscribe; + return emitter; } - module.exports = walk; + newVersion.walk = walk; + newVersion.remove = remove; + module.exports = newVersion; }()); diff --git a/package.json b/package.json index 90fdf0f..e5bfbf3 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,5 @@ "dependencies" : ["futures"], "lib" : "lib", "main" : "./lib/walk.js", - "version" : "0.9.1" + "version" : "0.9.2" } diff --git a/walk-test.js b/walk-test.js deleted file mode 100755 index 071a089..0000000 --- a/walk-test.js +++ /dev/null @@ -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); -}());