commit 8462d7458ba48815e192189f16eee3134bc64859 Author: AJ ONeal Date: Sat Nov 20 22:02:53 2010 -0700 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..096858d --- /dev/null +++ b/README.md @@ -0,0 +1,165 @@ +node-walk +==== + +A not-quite-port of python's `os.walk`. + +Installation +---- + + npm install walk + +Usage +==== + + var walk = require('walk'), + options = { + followlinks: false, + topdown: false, // currently ignored + }; + + function fileHandler(err, path, nodes, sorted) { + // handle each path + } + + walk("path/to/dir", options, fileHandler); + // 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) + * `dirs` + * `blocks` + * `chars` + * `links` + * `fifos` + * `sockets` + +Example +==== + + mkdir -p walk-test/dir1 + touch walk-test/file-1 + touch walk-test/file-2 + touch walk-test/dir1/file-1 + touch walk-test/dir1/file-2 + +node-walk-test +---- + + var walk = require('walk'); + + walk('./walk-test', undefined, function (err, path, nodes, sorted) { + 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.splice(i,1); + } + }); + console.log("PATH: " + path); + console.log("SORTED: "); + console.log(o); + }); + + +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/lib/walk.js b/lib/walk.js new file mode 100644 index 0000000..ae95226 --- /dev/null +++ b/lib/walk.js @@ -0,0 +1,128 @@ +(function () { + var fs = require('fs'), + Futures = require('futures'), + joinPath = require('path').join, + util = require('util'), + dir = process.argv[2]; + + function sortNodesByType(stats, o) { + if (stats.isFile()) { + o.files.push(stats); + } else if (stats.isDirectory()) { + o.dirs.push(stats); + } else if (stats.isBlockDevice()) { + o.blocks.push(stats); + } else if (stats.isCharacterDevice()) { + o.chars.push(stats); + } else if (stats.isSymbolicLink()) { + o.links.push(stats); + } else if (stats.isFIFO()) { + o.fifos.push(stats); + } else if (stats.isSocket()) { + o.sockets.push(stats); + } else { + util.debug(stats.node + 'is not of any node type'); + } + } + + /* + import os + from os.path import join, getsize + for root, dirs, files in os.walk('python/Lib/email'): + print root, "consumes", + print sum(getsize(join(root, name)) for name in files), + print "bytes in", len(files), "non-directory files" + if 'CVS' in dirs: + dirs.remove('CVS') # don't visit CVS directories + */ + + /* + fs.walk(path, function ({ err, root, dirs, files }) {}, { + // currently ignored + topdown: boolean, + onerror: boolean, // ignored + followlinks: boolean // lstat or stat + }); + */ + + function walk(firstPath, options, callback) { + options = options || {}; + var fstat = options.followlinks ? fs.stat : fs.lstat, + subscription = Futures.subscription(); + + if (callback) { subscription.subscribe(callback); } + + function readDir(path) { + var p = Futures.promise(); + + fs.readdir(path, function (err, files) { + if (err) { + err.path = path; + subscription.deliver(err, path, undefined, undefined); + // Signal the completion of this readdir attempt + p.fulfill(); + return; + } + + // TODO fix futures sequence to not require a first function like this + var s = Futures.sequence(function(n){n();}), + nodes = [], + o = { + errors: [], + files: [], + dirs: [], + blocks: [], + chars: [], + links: [], + fifos: [], + sockets: [] + }; + + files.forEach(function (file) { + s.then(function (next) { + fstat(joinPath(path, file), function (err, stats) { + stats = stats || {}; + stats.name = file; + nodes.push(stats); + + if (err) { + stats.err = err; + o.errors.push(stats); + } else { + sortNodesByType(stats, o); + } + + next(); + }); + }); + }); + + s.then(function (next) { + var s2 = Futures.sequence(function(n){n();}); + subscription.deliver(undefined, path, nodes, o); + p.fulfill(); + + o.dirs.forEach(function (dir) { + s2.then(function (next2) { + readDir(joinPath(path, dir.name)) + .when(function () { next2(); }); + }); + }); + + next(); + }); + + }); + + return p.passable(); + } + + readDir(firstPath) //.whenever(callback); + + return { + whenever: subscription.subscribe + } + } + + module.exports = walk; +}()); diff --git a/package.json b/package.json new file mode 100644 index 0000000..90fdf0f --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name" : "walk", + "description" : "A node port of python's os.walk", + "url" : "github.com/coolaj86/walk", + "keywords" : ["util", "os", "fs", "walk"], + "author" : "AJ ONeal ", + "contributors" : [], + "dependencies" : ["futures"], + "lib" : "lib", + "main" : "./lib/walk.js", + "version" : "0.9.1" +} diff --git a/walk-test.js b/walk-test.js new file mode 100755 index 0000000..071a089 --- /dev/null +++ b/walk-test.js @@ -0,0 +1,30 @@ +#!/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); +}()); diff --git a/walk-test.sh b/walk-test.sh new file mode 100755 index 0000000..15504fc --- /dev/null +++ b/walk-test.sh @@ -0,0 +1,5 @@ +mkdir -p walk-test/dir1 +touch walk-test/file-1 +touch walk-test/file-2 +touch walk-test/dir1/file-1 +touch walk-test/dir1/file-2