UNPKG

copy-dir

Version:
181 lines (174 loc) 4.67 kB
var fs = require('fs'); var path = require('path'); /* options: { utimes: false, // Boolean | Object, keep utimes if true mode: false, // Boolean | Number, keep file mode if true cover: true, // Boolean, cover if file exists filter: true, // Boolean | Function, file filter } */ function copydir(from, to, options, callback) { if (typeof options === 'function') { if(!callback) { callback = options; options = { filter: function() { return true; } }; } else { options = { filter: options }; } } if(typeof callback !== 'function') { callback = function() {}; } if(typeof options.cover === 'undefined') { options.cover = true; } options.filter = typeof options.filter === 'function' ? options.filter : function(state, filepath, filename) { return options.filter; }; fs.lstat(from, function(err, stats) { if (err) { callback(err); } else { var statsname = stats.isDirectory() ? 'directory' : stats.isFile() ? 'file' : stats.isSymbolicLink() ? 'symbolicLink' : ''; var valid = options.filter(statsname, from, path.basename(from)); if (statsname === 'directory' || statsname === 'symbolicLink') { // Directory or SymbolicLink if(valid) { fs.stat(to, function(err) { if(err) { if(err.code === 'ENOENT') { fs.mkdir(to, function(err) { if(err) { callback(err); } else { options.debug && console.log('>> ' + to); rewrite(to, options, stats, function(err) { if(err) { callback(err); } else { listDirectory(from, to, options, callback); } }); } }); } else { callback(err); } } else { rewrite(to, options, stats, function(err) { if(err) { callback(err); } else { listDirectory(from, to, options, callback); } }); } }); } else { callback(); } } else if(stats.isFile()) { // File if(valid) { if(options.cover) { writeFile(from, to, options, stats, callback); } else { fs.stat(to, function(err) { if(err) { if(err.code === 'ENOENT') { writeFile(from, to, options, stats, callback); } else { callback(err); } } else { callback(); } }); } } else { callback(); } } else { callback(new Error('stats invalid: '+ from)); } } }); } function listDirectory(from, to, options, callback) { fs.readdir(from, function(err, files) { if(err) { callback(err); } else { copyFromArray(files, from, to, options, callback); } }); } function copyFromArray(files, from, to, options, callback) { if(files.length === 0) { callback(null); } else { var f = files.shift(); copydir(path.join(from, f), path.join(to, f), options, function(err) { if(err) { callback(err); } else { copyFromArray(files, from, to, options, callback); } }); } } function chmod(f, mode, callback) { if(mode) { fs.chmod(f, mode, callback); } else { callback(); } } function utimes(f, mode, callback) { if(mode) { fs.utimes(f, mode.atime, mode.mtime, callback); } else { callback(); } } function writeFile(from, to, options, stats, callback) { fs.readFile(from, 'binary', function(err, data) { if(err) { callback(err); } else { fs.writeFile(to, data, 'binary', function(err) { if(err) { callback(err); } else { options.debug && console.log('>> ' + to); rewrite(to, options, stats, callback); } }); } }); } function rewrite(f, options, stats, callback) { if(options.cover) { chmod(f, options.mode === true ? stats.mode : options.mode, function(err) { if(err) { callback(err); } else { utimes(f, options.utimes === true ? { atime: stats.atime, mtime: stats.mtime } : options.utimes, callback); } }); } else { callback(); } } module.exports = copydir;