alinex-fs
Version:
Extension of nodes filesystem tools.
205 lines (182 loc) • 6.24 kB
JavaScript
/*
Find Files
=================================================
This is a powerfull method to search for files on the local filesystem. It works
recursively with multiple checks and to get a file list as quick as possible.
To define which files to select you may use the following options::
- `filter` - `Array<Object>|Object` {@link filter.coffee}
- `dereference` - `Boolean` dereference symbolic links and go into them
- `ìgnoreErrors` - `Boolean` go on and ignore IO errors
- `parallel` - `Integer` number of maximum parallel calls in asynchronous run
(defaults to half of open files limit per process on the system)
To not completely exhaust the system or the allowed open files per process use the
parallel limit but because this runs recursively the square root of the given value
is used for the first and less for each other level of depth.
__Example:__
``` coffee
fs = require 'alinex-fs'
fs.find '/tmp/some/directory',
filter:
include: '*.jpg'
, (err, list) ->
return console.error err if err
console.log "Found " + list.length + " images."
* do something with list
```
*/
(function() {
var async, debug, filter, findSync, fs, parallel, path;
debug = require('debug')('fs:find');
fs = require('fs');
path = require('path');
async = require('async');
filter = require('../helper/filter');
parallel = require('../helper/parallel');
/*
@param {String} search source path to be searched in
@param {Object} [options] specifications for check defining which files to list
@param {function(Error, Array)} [cb] callback which is called after done with an `Èrror`
or the complete list of files found as `Àrray`
*/
module.exports.find = function(source, options, cb) {
var list, queue;
if (cb == null) {
cb = function() {};
}
if (typeof options === 'function' || !options) {
cb = options != null ? options : function() {};
options = {};
}
list = [];
queue = async.queue(function(task, cb) {
if (debug.enabled) {
debug("check " + task.source);
}
return async.setImmediate(function() {
return filter.filter(task.source, task.depth, options, function(ok) {
var stat;
if (ok === void 0) {
return cb();
}
stat = options.dereference != null ? fs.stat : fs.lstat;
return stat(task.source, function(err, stats) {
if (err) {
return cb((options != null ? options.ignoreErrors : void 0) ? null : err);
}
if (ok) {
list.push(task.source);
}
if (!stats.isDirectory()) {
return cb(null, list);
}
if (debug.enabled) {
debug("going deeper into " + task.source + " directory");
}
task.depth++;
return fs.readdir(task.source, function(err, files) {
var file, i, len;
if (err) {
return cb(err);
}
for (i = 0, len = files.length; i < len; i++) {
file = files[i];
queue.push({
source: task.source + "/" + file,
depth: task.depth
});
}
return cb();
});
});
});
});
}, parallel(options));
queue.push({
source: source,
depth: 0
});
queue.drain = function() {
list.sort();
return cb(null, list);
};
return queue.error = function(err) {
queue.kill();
cb(err);
return cb = function() {};
};
};
/*
@param {String} search source path to be searched in
@param {Object} [options] specifications for check defining which files to list
@return {Array} complete list of files found
@throws {Error} if anything out of order happened
@internal The `depth` parameter is only used internally.
@param {Integer} [depth=0] current depth in file tree
*/
findSync = module.exports.findSync = function(source, options, depth) {
var error, file, files, i, len, list, ok, ref, stat, stats;
if (options == null) {
options = {};
}
if (depth == null) {
depth = 0;
}
list = [];
ok = filter.filterSync(source, depth, options);
if (options.lazy && !ok) {
return list;
}
if (ok) {
list.push(source);
}
stat = options.dereference != null ? fs.statSync : fs.lstatSync;
try {
stats = stat(source);
} catch (error1) {
error = error1;
if (options.ignoreErrors) {
return list;
}
throw error;
}
if (!stats.isDirectory()) {
return list;
}
depth++;
files = fs.readdirSync(source);
ref = files.sort();
for (i = 0, len = ref.length; i < len; i++) {
file = ref[i];
list = list.concat(findSync(path.join(source, file), options, depth));
}
return list;
};
/*
Debugging
---------------------------------------------------------
This module uses the {@link debug} module so you may anytime call your app with
the environment setting `DEBUG=fs:find` for the output of this method only.
fs:find check test/temp +0ms
fs:filter skip test/temp because path not included +5ms
fs:filter test/temp SKIP +1ms
fs:find going deeper into test/temp directory +40ms
fs:find check test/temp/dir1 +1ms
fs:find check test/temp/dir2 +0ms
fs:find check test/temp/dir3 +0ms
fs:find check test/temp/file1 +0ms
fs:find check test/temp/file2 +0ms
fs:filter test/temp/dir1 OK +1ms
fs:filter skip dir2 because path not included +0ms
fs:filter test/temp/dir2 SKIP +0ms
fs:filter skip dir3 because path not included +0ms
fs:filter test/temp/dir3 SKIP +0ms
fs:filter test/temp/file1 OK +0ms
fs:filter skip file2 because path not included +0ms
fs:filter test/temp/file2 SKIP +0ms
fs:find going deeper into test/temp/dir1 directory +0ms
fs:find going deeper into test/temp/dir2 directory +0ms
fs:find check test/temp/dir1/file11 +1ms
fs:filter test/temp/dir1/file11 OK +0ms
*/
}).call(this);
//# sourceMappingURL=find.map