231 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| (function () {
 | |
|   var fs = require('fs'),
 | |
|     Futures = require('futures'),
 | |
|     joinPath = require('path').join,
 | |
|     util = require('util'),
 | |
|     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 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 {
 | |
|       // emitter.emit("error", stats);
 | |
|       util.debug(stats.name + '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);
 | |
|           // 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: [], 
 | |
|             dirs: [], 
 | |
|             files: [],
 | |
|             links: [], 
 | |
|             blocks: [], 
 | |
|             chars: [], 
 | |
|             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 || {};
 | |
|               stats.name = file;
 | |
|               nodes.push(stats);
 | |
| 
 | |
|               if (err) {
 | |
|                 stats.err = err;
 | |
|                 o.errors.push(stats);
 | |
|               } else {
 | |
|                 sortNodesByType(path, stats, o);
 | |
|               }
 | |
| 
 | |
|               next();
 | |
|             });
 | |
|           });
 | |
|         });
 | |
| 
 | |
|         s.then(function (next) {
 | |
|           var s2 = Futures.sequence(function(n){n();});
 | |
|           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(); });
 | |
|               });
 | |
|             });
 | |
| 
 | |
|             next();
 | |
|           }
 | |
|         });
 | |
| 
 | |
|       });
 | |
| 
 | |
|       return p.passable();
 | |
|     }
 | |
| 
 | |
|     readDir(firstPath) //.whenever(callback);
 | |
| 
 | |
|     emitter.whenever = subscription.subscribe;
 | |
|     return emitter;
 | |
|   }
 | |
| 
 | |
|   newVersion.walk = walk;
 | |
|   newVersion.remove = remove;
 | |
|   module.exports = newVersion;
 | |
| }());
 |