From 58380677c2790a038a7de983c785733f1ce1618c Mon Sep 17 00:00:00 2001 From: refaelos Date: Mon, 20 May 2013 19:17:12 +0300 Subject: [PATCH 1/7] assigning original file's mode to the copied file --- lib/wrench.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/wrench.js b/lib/wrench.js index 6cfa8c6..75125b7 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -202,6 +202,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()) { From 02bd67c8a6659b709579cacbd24c9800fcac4709 Mon Sep 17 00:00:00 2001 From: refaelos Date: Mon, 20 May 2013 19:38:17 +0300 Subject: [PATCH 2/7] in 'copyDirRecursive': - replaces 'forceDelete' with 'preserve'. - added an option to get 'excludeHiddenUnix' = added an option to get 'inflateSymlinks' --- lib/wrench.js | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/lib/wrench.js b/lib/wrench.js index 75125b7..b63a455 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -317,6 +317,78 @@ exports.rmdirRecursive = function rmdirRecursive(dir, failSilent, clbk){ }); }; +exports.copyDirRecursive = function copyDirRecursive(srcDir, newDir, opts, clbk) { + + if (typeof opts === 'function') + clbk = opts; + + var copyDirRecInner = function() { + fs.stat(srcDir, function (err1, srcDirStat) { + if (err1) return clbk(err1); + fs.readdir(srcDir, function (err, files) { + 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(); + } + + if (opts.excludeHiddenUnix && /^\./.test(filename)) + 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()) { + fs.readlink(file, function (err, link) { + if (!opts.inflateSymlinks) { + fs.symlink(link, newFile, copyFiles); + } else { + fs.lstat(srcDir + '/' + link, function (err, stats) { + if (stats.isDirectory()) { + copyDirRecursive(srcDir + '/' + link, newFile, opts, copyFiles); + } else { + fs.readFile(srcDir + '/' + link, function (err, data) { + fs.writeFile(newFile, data, copyFiles); + }); + } + }); + } + }); + } + else + fs.readFile(file, function (err, data) { + fs.writeFile(newFile, data, 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.mkdir(newDir, srcDirStat.mode, function(err){ + if (err) return clbk(err); + copyDirRecInner(); + }); + } + }); +}; + /* wrench.copyDirRecursive("directory_to_copy", "new_location", {forceDelete: bool}, callback); * * Recursively dives through a directory and moves all its files to a new From fee7f769aef5006b761e00ea62535ee488a96775 Mon Sep 17 00:00:00 2001 From: refaelos Date: Mon, 20 May 2013 19:43:27 +0300 Subject: [PATCH 3/7] removed previous function fixed docs --- lib/wrench.js | 63 ++++++--------------------------------------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/lib/wrench.js b/lib/wrench.js index b63a455..cc27397 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -317,6 +317,13 @@ exports.rmdirRecursive = function rmdirRecursive(dir, failSilent, clbk){ }); }; +/* 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. + * + * Note: Directories should be passed to this function without a trailing slash. + */ exports.copyDirRecursive = function copyDirRecursive(srcDir, newDir, opts, clbk) { if (typeof opts === 'function') @@ -389,62 +396,6 @@ exports.copyDirRecursive = function copyDirRecursive(srcDir, newDir, opts, clbk) }); }; -/* wrench.copyDirRecursive("directory_to_copy", "new_location", {forceDelete: bool}, callback); - * - * Recursively dives through a directory and moves all its files to a new - * location. Specify forceDelete to force directory overwrite. - * - * 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; - - fs.stat(srcDir, function(err, srcDirStat){ - if (err) return clbk(err); - fs.mkdir(newDir, srcDirStat.mode, function(err){ - if (err) return clbk(err); - fs.readdir(srcDir, function(err, files){ - 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); - }); - }); - })(); - }); - }); - }); - }); -}; - var mkdirSyncRecursive = function(path, mode) { var self = this; path = _path.normalize(path) From d32c9f46bca9aaca71f672fe91832a97e0a986ce Mon Sep 17 00:00:00 2001 From: refaelos Date: Wed, 22 May 2013 10:37:47 +0300 Subject: [PATCH 4/7] changed the way copyDirRecursive works. - paths needed to be normalized - using 'preserve' instead of 'forceDelete'. it makes more sense to let users decide if they want to keep the existing folders/subfolders then to ask them if they want to 'forceDelete' the old ones. The default operation will be to keep existing folders. - added (and fixed) 'inflateSymLinks'. It's a new option that allows users do decide if they want to copy symlinks from original folder as new folders or just copy the symlink. --- lib/wrench.js | 110 +++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/lib/wrench.js b/lib/wrench.js index cc27397..1066ee7 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 { @@ -292,7 +293,7 @@ exports.chownSyncRecursive = function(sourceDir, uid, gid) { */ exports.rmdirRecursive = function rmdirRecursive(dir, failSilent, clbk){ fs.readdir(dir, function(err, files){ - if(err && typeof failSilent === 'boolean' && !failSilent) + if(err && typeof failSilent === 'boolean' && !failSilent) return clbk(err); if(typeof failSilent === 'function') @@ -328,53 +329,63 @@ exports.copyDirRecursive = function copyDirRecursive(srcDir, newDir, opts, clbk) if (typeof opts === 'function') clbk = opts; + srcDir = _path.normalize(srcDir); + newDir = _path.normalize(newDir); + + 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.stat(srcDir, function (err1, srcDirStat) { - if (err1) return clbk(err1); - fs.readdir(srcDir, function (err, files) { + fs.readdir(srcDir, function (err, files) { + if (err) return clbk(err); + (function copyFiles(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(); + 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); } - if (opts.excludeHiddenUnix && /^\./.test(filename)) - 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()) { - fs.readlink(file, function (err, link) { - if (!opts.inflateSymlinks) { - fs.symlink(link, newFile, copyFiles); - } else { - fs.lstat(srcDir + '/' + link, function (err, stats) { - if (stats.isDirectory()) { - copyDirRecursive(srcDir + '/' + link, newFile, opts, copyFiles); - } else { - fs.readFile(srcDir + '/' + link, function (err, data) { - fs.writeFile(newFile, data, copyFiles); - }); - } - }); - } - }); - } - else - fs.readFile(file, function (err, data) { - fs.writeFile(newFile, data, copyFiles); - }); - }); - })(); - }); + }); + })(); }); }; @@ -388,9 +399,14 @@ exports.copyDirRecursive = function copyDirRecursive(srcDir, newDir, opts, clbk) copyDirRecInner(); } } else { - fs.mkdir(newDir, srcDirStat.mode, function(err){ - if (err) return clbk(err); - copyDirRecInner(); + 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); + copyDirRecInner(); + }); }); } }); From 8fbe19ffed28ff2b3f36b4098948e872b6663657 Mon Sep 17 00:00:00 2001 From: refaelos Date: Wed, 22 May 2013 10:43:42 +0300 Subject: [PATCH 5/7] added 'mkdirp' to package,json 'mkdirp' is a useful tool to async mkdir recursive that doesn't fail if the folder exists. --- package.json | 1 + 1 file changed, 1 insertion(+) 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": { From 5b747d9bb148f8185d4f900d5dedabdb365488c6 Mon Sep 17 00:00:00 2001 From: refaelos Date: Wed, 12 Jun 2013 18:56:12 +0300 Subject: [PATCH 6/7] fixed an issue with error handling in 'rmdirRecursive' --- lib/wrench.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/wrench.js b/lib/wrench.js index 1066ee7..3092012 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -293,11 +293,16 @@ exports.chownSyncRecursive = function(sourceDir, uid, gid) { */ exports.rmdirRecursive = function rmdirRecursive(dir, failSilent, clbk){ 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); From 261c8d61a8cd39533684d43da2efa491801d0031 Mon Sep 17 00:00:00 2001 From: refaelos Date: Wed, 26 Jun 2013 17:53:19 +0300 Subject: [PATCH 7/7] if clbk is not given, create a dummy clbk --- lib/wrench.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/wrench.js b/lib/wrench.js index 3092012..c8b919b 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -292,6 +292,10 @@ 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) { if (typeof failSilent === 'boolean' && failSilent) {