diff --git a/lib/wrench.js b/lib/wrench.js index a4e29b5..2a41896 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -12,7 +12,8 @@ */ var fs = require("fs"), - _path = require("path"); + _path = require("path"), + mkdirp = require("mkdirp"); /* wrench.readdirSyncRecursive("directory_path"); @@ -166,7 +167,7 @@ exports.rmdirSyncRecursive = function(path, failSilent) { */ exports.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts) { try { - if(fs.statSync(newDirLocation).isDirectory()) { + if(fs.statSync(newDirLocation).isDirectory()) { if(typeof opts !== 'undefined' && opts.forceDelete) { exports.rmdirSyncRecursive(newDirLocation); } else { @@ -202,6 +203,8 @@ exports.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts) { var contents = fs.readFileSync(srcFile); fs.writeFileSync(destFile, contents); + var stat = fs.lstatSync(srcFile); + fs.chmodSync(destFile, stat.mode); }; if(currFile.isDirectory()) { @@ -289,12 +292,21 @@ exports.chownSyncRecursive = function(sourceDir, uid, gid) { * Recursively dives through directories and obliterates everything about it. */ exports.rmdirRecursive = function rmdirRecursive(dir, failSilent, clbk){ + if (clbk === null || typeof clbk == 'undefined') { + clbk = function(err) {}; + } + fs.readdir(dir, function(err, files){ - if(err && typeof failSilent === 'boolean' && !failSilent) - return clbk(err); + if(err) { + if (typeof failSilent === 'boolean' && failSilent) { + return clbk(null); + } else { + return clbk(err); + } + } - if(typeof failSilent === 'function') - clbk = failSilent; + if(typeof failSilent === 'function') + clbk = failSilent; (function rmFile(err){ if (err) return clbk(err); @@ -315,59 +327,97 @@ exports.rmdirRecursive = function rmdirRecursive(dir, failSilent, clbk){ }); }; -/* wrench.copyDirRecursive("directory_to_copy", "new_location", {forceDelete: bool}, callback); +/* wrench.copyDirRecursive("directory_to_copy", "new_location", {preserve: bool, inflateSymlinks:bool, excludeHiddenUnix:bool }, callback); * * Recursively dives through a directory and moves all its files to a new - * location. Specify forceDelete to force directory overwrite. + * location. * * Note: Directories should be passed to this function without a trailing slash. */ exports.copyDirRecursive = function copyDirRecursive(srcDir, newDir, opts, clbk) { - fs.stat(newDir, function(err, newDirStat){ - if(!err) { - if(typeof opts !== 'undefined' && typeof opts !== 'function' && opts.forceDelete) - return exports.rmdirRecursive(newDir, function(err){ - copyDirRecursive.apply(this, arguments); - }); - else - return clbk(new Error('You are trying to delete a directory that already exists. Specify forceDelete in an options object to override this.')); - } - if(typeof opts === 'function') - clbk = opts; + if (typeof opts === 'function') + clbk = opts; + srcDir = _path.normalize(srcDir); + newDir = _path.normalize(newDir); - fs.stat(srcDir, function(err, srcDirStat){ + var handleFile = function(file, newFile, clbk) { + fs.readFile(file, function (err, data) { + fs.writeFile(newFile, data, clbk); + }); + }; + + var handleSymlink = function(file, newFile, clbk) { + fs.readlink(file, function (err, link) { + if (!opts.inflateSymlinks) { + fs.symlink(link, newFile, clbk); + } else { + fs.lstat(srcDir + '/' + link, function (err, stats) { + if (stats.isDirectory()) { + copyDirRecursive(srcDir + '/' + link, newFile, opts, clbk); + } else { + handleFile(srcDir + '/' + link, newFile, clbk); + } + }); + } + }); + }; + + var copyDirRecInner = function() { + fs.readdir(srcDir, function (err, files) { if (err) return clbk(err); - fs.mkdir(newDir, srcDirStat.mode, function(err){ + (function copyFiles(err) { if (err) return clbk(err); - fs.readdir(srcDir, function(err, files){ + + var filename = files.shift(); + + while (filename && opts.excludeHiddenUnix && /^\./.test(filename)) { + filename = files.shift(); + } + + if (filename === null || typeof filename == 'undefined') { + return clbk(); + } + + var file = srcDir + '/' + filename, + newFile = newDir + '/' + filename; + + fs.stat(file, function (err, fileStat) { + if (fileStat.isDirectory()) { + copyDirRecursive(file, newFile, opts, copyFiles); + } + else if (fileStat.isSymbolicLink()) { + handleSymlink(file, newFile, copyFiles); + } + else { + handleFile(file, newFile, copyFiles); + } + + }); + })(); + }); + }; + + fs.stat(newDir, function(err, newDirStat){ + if (!err) { + if ((typeof opts !== 'undefined' && typeof opts !== 'function' && !opts.preserve) && (newDirStat.isDirectory())) { + return exports.rmdirRecursive(newDir, function(err){ + copyDirRecursive(srcDir, newDir, opts, clbk); + }); + } else { + copyDirRecInner(); + } + } else { + fs.stat(srcDir, function (err, srcDirStat) { + if (err) { + clbk(new Error('The source directory (probably) doesn\'t exist. error: ' + err)); + } + mkdirp(newDir, srcDirStat.mode, function(err){ if (err) return clbk(err); - (function copyFiles(err){ - if (err) return clbk(err); - - var filename = files.shift(); - if (filename === null || typeof filename == 'undefined') - return clbk(null); - - var file = srcDir+'/'+filename, - newFile = newDir+'/'+filename; - - fs.stat(file, function(err, fileStat){ - if (fileStat.isDirectory()) - copyDirRecursive(file, newFile, copyFiles); - else if (fileStat.isSymbolicLink()) - fs.readlink(file, function(err, link){ - fs.symlink(link, newFile, copyFiles); - }); - else - fs.readFile(file, function(err, data){ - fs.writeFile(newFile, data, copyFiles); - }); - }); - })(); + copyDirRecInner(); }); }); - }); + } }); }; diff --git a/package.json b/package.json index 065aeab..47cbc15 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "dependencies": { + "mkdirp": "*" }, "devDependencies": {