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
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
|
|
}
|
|
});
|
|
};
|
|
|