core/node_modules/nak/lib/walkdir.js
2017-05-14 13:22:31 +02:00

126 lines
3.4 KiB
JavaScript

// gutted from walkdir: https://github.com/soldair/node-walkdir
// speed up a bunch.
var fs = require("fs");
var PathFilter = require("./path-filter");
var path = require("path");
// weird, but keeping these outside of walkdir makes it faster
var finalizer,
allPaths = Object.create(null),
allStats = Object.create(null),
allLinks = Object.create(null),
ended = 0,
jobs = 0,
// since windows handles well paths with forward slashes
// and we need .nakignore files to work the same on all platforms
// we always use /
DIR_SEP = "/",
// makes sure we're asynching right
job = function(value) {
jobs += value;
if(value < 1 && !tick) {
tick = 1;
process.nextTick(function(){
tick = 0;
if(jobs <= 0 && !ended) {
ended = 1;
finalizer();
}
});
}
}, tick = 0;
exports.walkdir = function(fpath, options, printCb, done) {
var maxFiles = options.limit || -1;
// if there are ignore rules, properly set them up
var pathFilter = new PathFilter(options.inclusions, options.exclusions, options.hidden);
// called at the end of the walk
finalizer = function() {
require('./finalizer')(fpath, options, allPaths, allStats, printCb, done);
};
var follow = options.follow;
var list = options.list;
var statAction = function(stat, parent, filepath) {
// job(-1);
if (!stat) return;
// TODO: this could probably be cleaned up
if (stat.isFile() && pathFilter.isPathAccepted(filepath)) {
if (!list)
allStats[filepath] = stat;
if (allPaths[parent] === undefined)
allPaths[parent] = [];
allPaths[parent].push(filepath);
}
else if (stat.isDirectory() && pathFilter.isPathAccepted(filepath + DIR_SEP)) {
maxFiles && readdir(filepath + DIR_SEP);
}
};
var statter = function (parent, filepath) {
// job(1); // statAction is sync
// lstat is SLOW, but what other way to determine if something is a directory or file ?
// also, sync is about 200ms faster than async...
statAction(getStat(fpath + filepath), parent, filepath);
};
var getStat = function(filepath) {
try {
var stat = fs.lstatSync(filepath);
if (follow && stat.isSymbolicLink()) {
stat = fs.statSync(filepath);
var fullPath = fs.realpathSync(filepath);
if (allLinks[fullPath]) {
return;
}
allLinks[fullPath] = true;
}
return stat;
} catch (e) {
// console.error(e);
}
};
var readdirAction = function(files, filepath) {
job(-1);
if (!files) { return; }
var fileCount = files.length, prefix = filepath;
if (maxFiles >= 0) {
if (maxFiles === 0) {
return;
}
maxFiles -= fileCount;
if (maxFiles <= 0) {
maxFiles = 0;
console.error("reached file number limit");
}
}
while (fileCount--) {
var file = files.shift(), filename = prefix + file;
statter(filepath, filename);
}
};
var readdir = function(filepath) {
job(1);
// async doesn't matter, we sort results at end anyway
fs.readdir(fpath + filepath, function(err, files) {
readdirAction(files, filepath);
});
};
if (options.startPaths) {
job(1);
options.startPaths.forEach(function(p) {
statter(path.dirname(p), p);
});
job(-1);
}
else
readdir(DIR_SEP);
};