1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.9 KiB

var sys = require("sys"),
util = require("util"),
events = require("events"),
colors = require("colors"),
fs = require("fs");
/**
* read a directory (recursively deep)
* data[] = an object for each element in the directory
* .name = item's name (file or folder name)
* .stat = item's stat (.stat.isDirectory() == true IF a folder)
* .children = another data[] for the children
* filter = an object with various filter settings:
* .depth = max directory recursion depth to travel
* (0 or missing means: infinite)
* (1 means: only the folder passed in)
* .hidden = true means: process hidden files and folders (defaults to false)
* .callback = callback function: callback(name, path, filter) -- returns truthy to keep the file
*
*
* @param path = path to directory to read (".", ".\apps")
* @param callback = function to callback to: callback(err, data)
* @param [filter] = (optional) filter object
*
* Shamelessly snagged from:
* http://utahjs.com/2010/09/16/nodejs-events-and-recursion-readdir/
*/
exports.recurseDir = function(path, callback, filter) {
if (filter) {
// process filter. are we too deep yet?
if (!filter.depthAt) filter.depthAt = 1; // initialize what depth we are at
if (filter.depth && filter.depth < filter.depthAt) {
callback(undefined, []); // we are too deep. return "nothing found"
return;
}
}
// queue up a "readdir" file system call (and return)
fs.readdir(path, function(err, files) {
if (err) {
callback(err);
return;
}
var doHidden = false; // true means: process hidden files and folders
if (filter && filter.hidden) {
doHidden = true; // filter requests to process hidden files and folders
}
var count = 0; // count the number of "stat" calls queued up
var countFolders = 0; // count the number of "folders" calls queued up
var data = []; // the data to return
// iterate over each file in the dir
files.forEach(function (name) {
// ignore files that start with a "." UNLESS requested to process hidden files and folders
if (doHidden || name.indexOf(".") !== 0) {
// queue up a "stat" file system call for every file (and return)
count += 1;
fs.stat(path + "/" + name, function(err, stat) {
if (err) {
callback(err);
return;
}
var processFile = true;
if (filter && filter.callback) {
processFile = filter.callback(name, stat, filter);
}
if (processFile) {
var obj = {};
obj.name = name;
obj.filepath = path + "/" + name;
obj.stat = stat;
data.push(obj);
if (stat.isDirectory()) {
countFolders += 1;
// perform "recurseDir" on each child folder (which queues up a readdir and returns)
(function(obj2) {
// obj2 = the "obj" object
exports.recurseDir(path + "/" + name, function(err, data2) {
if (err) {
callback(err);
return;
}
// entire child folder info is in "data2" (1 fewer child folders to wait to be processed)
countFolders -= 1;
obj2.children = data2;
if (countFolders <= 0) {
// sub-folders found. This was the last sub-folder to processes.
callback(undefined, data); // callback w/ data
} else {
// more children folders to be processed. do nothing here.
}
});
})(obj);
}
}
// 1 more file has been processed (or skipped)
count -= 1;
if (count <= 0) {
// all files have been processed.
if (countFolders <= 0) {
// no sub-folders were found. DONE. no sub-folders found
callback(undefined, data); // callback w/ data
} else {
// children folders were found. do nothing here (we are waiting for the children to callback)
}
}
});
}
});
if (count <= 0) { // if no "stat" calls started, then this was an empty folder
callback(undefined, []); // callback w/ empty
}
});
};