katana
Version:
Easy to use, modular web framework for any Node.js samurai.
264 lines (212 loc) • 6.14 kB
JavaScript
var Path = require('path');
var Fs = require('fs');
var async = require('async');
var join = Path.join;
var normalize = Path.normalize;
var dirname = Path.dirname;
var basename = Path.basename;
var extension = Path.extname;
var sep = Path.sep;
// https://github.com/nodeca/fs-tools/blob/master/lib/fs-tools.js
var utils = module.exports;
utils.walkFlat = function(path, iterator, callback) {
Fs.readdir(path, function(error, files) {
if (error) {
return callback(error.code==='ENOENT' ? null : error);
}
async.forEach(files, function(file, next) {
iterator(join(path, file), next);
}, callback);
});
}
utils.walkDeep = function(path, match, iterator, callback) {
utils.walkFlat(normalize(path), function(path, next) {
Fs.lstat(path, function(error, stats) {
if (error) {
return next(error);
}
if (match(path, stats)) {
if (stats.isDirectory()) {
iterator(path, stats, function() {
utils.walkDeep(path, match, iterator, next);
});
} else {
iterator(path, stats, next);
}
return;
}
next();
});
}, callback);
}
utils.copyFile = function(source, destination, callback) {
var _done = false;
function done() {
if (!_done) {
_done = true; callback.apply(callback, arguments);
}
}
var read = Fs.createReadStream(source, { bufferSize: 64 * 1024 }).on('error', done);
var write = Fs.createWriteStream(destination).on('error', done).on('close', done);
read.pipe(write);
}
utils.walk = function(path, pattern, iterator, callback) {
if (!callback) {
callback = iterator; iterator = pattern; pattern = null;
}
if (!pattern) {
var match = function() { return true; }
} else if (typeof(pattern) === 'function') {
var match = pattern;
} else {
pattern = new RegExp(pattern);
var match = function(path) { return pattern.test(path); }
}
path = normalize(path);
Fs.lstat(path, function(error, stats) {
if (error) {
return callback(error.code==='ENOENT' ? null : error);
}
if (!stats.isDirectory()) {
return callback(new Error('Path is not a directory!'));
}
utils.walkDeep(path, match, iterator, callback);
});
}
utils.remove = function(path, callback) {
path = normalize(path);
Fs.lstat(path, function(error, stats) {
if (error) {
return callback(error.code==='ENOENT' ? null : error);
}
if (!stats.isDirectory()) {
return Fs.unlink(path, callback);
}
async.series([
async.apply(utils.walkFlat, path, utils.remove),
async.apply(Fs.rmdir, path)
], function(error) {
callback(error);
});
});
}
utils.mkdir = function(path, mode, callback) {
path = normalize(path);
if (typeof(mode) === 'function') {
callback = mode; mode = 0755;
} else if (typeof(mode) === 'string') {
mode = parseInt(mode, 8);
}
Fs.exists(path, function(exists) {
if (exists) {
return callback();
}
var parent = dirname(path);
utils.mkdir(parent, mode, function(error) {
if (error) {
return callback(error);
}
Fs.mkdir(path, mode, function(error) {
if (error && error.code==='EEXIST') {
return callback();
}
callback(error);
});
});
});
}
utils.copy = function(source, destination, callback) {
source = normalize(source);
destination = normalize(destination);
if (source === destination) {
return callback();
}
Fs.lstat(source, function(error, stats) {
if (error) {
return callback(error);
}
utils.mkdir(dirname(destination), function(error) {
if (error) {
return callback(error);
}
var chmod = async.apply(Fs.chmod, destination, stats.mode);
var done = function(error) { callback(error); }
if (stats.isFile()) {
return async.series([async.apply(utils.copyFile, source, destination), chmod], done);
}
if (stats.isSymbolicLink()) {
return async.waterfall([
function(next) {
Fs.exists(destination, function(exists) {
if (exists) {
return utils.remove(destination, next);
}
next();
});
},
async.apply(Fs.readlink, source),
function(path, next) {
Fs.symlink(path, destination, next);
},
chmod
], done);
}
if (stats.isDirectory()) {
return async.series([
function(next) {
Fs.mkdir(destination, 0755, function(error) {
if (error && error.code==='EEXISTS') {
return next();
}
next(error);
});
},
async.apply(utils.walkFlat, source, function(path, next) {
utils.copy(path, destination + sep + path.replace(source, ''), next);
}),
chmod
], done);
}
callback(new Error('Unsupported type of the source'));
});
});
}
utils.move = function(source, destination, callback) {
Fs.rename(source, destination, function(error) {
if (!error) {
return callback();
}
async.series([
async.apply(utils.copy, source, destination),
async.apply(utils.remove, source)
], function(error) {
callback(error);
});
});
}
utils.find = function(path, options, callback) {
var files = [];
if (!callback) {
callback = options; options = {};
}
if (typeof(options) === 'function') {
options = {
pattern: options
};
}
options.filesOnly===undefined && (options.filesOnly = true);
options.hiddens===undefined && (options.hiddens = false);
utils.walk(path, options.pattern, function(file, stats, next) {
if (options.filesOnly && stats.isDirectory()) {
return next();
}
var name = basename(file, extension(file));
if (!options.hiddens && (!name || name[0]==='.')) {
return next();
}
files.push(file);
next();
}, function(error) {
callback(error, files);
});
}