diff --git a/lib/wrench.js b/lib/wrench.js index 01f5e95..c8b919b 100644 --- a/lib/wrench.js +++ b/lib/wrench.js @@ -13,7 +13,8 @@ var fs = require("fs"), _path = require("path"), - isWindows = !!process.platform.match(/^win/); + mkdirp = require("mkdirp"); + /* wrench.readdirSyncRecursive("directory_path"); * @@ -28,7 +29,7 @@ exports.readdirSyncRecursive = function(baseDir) { curFiles, nextDirs, isDir = function(fname){ - return fs.existsSync(_path.join(baseDir, fname)) ? fs.statSync( _path.join(baseDir, fname) ).isDirectory() : false; + return fs.statSync( _path.join(baseDir, fname) ).isDirectory(); }, prependBaseDir = function(fname){ return _path.join(baseDir, fname); @@ -121,9 +122,7 @@ exports.readdirRecursive = function(baseDir, fn) { - - -/* wrench.rmdirSyncRecursive("directory_path", failSilent); +/* wrench.rmdirSyncRecursive("directory_path", forceDelete, failSilent); * * Recursively dives through directories and obliterates everything about it. This is a * Sync-function, which blocks things until it's done. No idea why anybody would want an @@ -135,34 +134,22 @@ exports.rmdirSyncRecursive = function(path, failSilent) { try { files = fs.readdirSync(path); } catch (err) { - if(failSilent) return; throw new Error(err.message); } /* Loop through and delete everything in the sub-tree after checking it */ for(var i = 0; i < files.length; i++) { - var file = _path.join(path, files[i]); - var currFile = fs.lstatSync(file); + var currFile = fs.lstatSync(_path.join(path, files[i])); - if(currFile.isDirectory()) { - // Recursive function back to the beginning - exports.rmdirSyncRecursive(file); - } else if(currFile.isSymbolicLink()) { - // Unlink symlinks - if (isWindows) { - fs.chmodSync(file, 666) // Windows needs this unless joyent/node#3006 is resolved.. - } + if(currFile.isDirectory()) // Recursive function back to the beginning + exports.rmdirSyncRecursive(_path.join(path, files[i])); - fs.unlinkSync(file); - } else { - // Assume it's a file - perhaps a try/catch belongs here? - if (isWindows) { - fs.chmodSync(file, 666) // Windows needs this unless joyent/node#3006 is resolved.. - } + else if(currFile.isSymbolicLink()) // Unlink symlinks + fs.unlinkSync(_path.join(path, files[i])); - fs.unlinkSync(file); - } + else // Assume it's a file - perhaps a try/catch belongs here? + fs.unlinkSync(_path.join(path, files[i])); } /* Now that we know everything in the sub-tree has been deleted, we can delete the main @@ -170,55 +157,6 @@ exports.rmdirSyncRecursive = function(path, failSilent) { return fs.rmdirSync(path); }; - - -function isFileIncluded(opts, dir, filename) { - - function isMatch(filter) { - if (typeof filter === 'function') { - return filter(filename, dir) === true; - } - else { - // Maintain backwards compatibility and use just the filename - return filename.match(filter); - } - } - - if (opts.include || opts.exclude) { - if (opts.exclude) { - if (isMatch(opts.exclude)) { - return false; - } - } - - if (opts.include) { - if (isMatch(opts.include)) { - return true; - } - else { - return false; - } - } - - return true; - } - else if (opts.filter) { - var filter = opts.filter; - - if (!opts.whitelist) { - // if !opts.whitelist is false every file or directory - // which does match opts.filter will be ignored - return isMatch(filter) ? false : true; - } else { - // if opts.whitelist is true every file or directory - // which doesn't match opts.filter will be ignored - return !isMatch(filter) ? false : true; - } - } - - return true; -} - /* wrench.copyDirSyncRecursive("directory_to_copy", "new_directory_location", opts); * * Recursively dives through a directory and moves all its files to a new location. This is a @@ -228,16 +166,14 @@ function isFileIncluded(opts, dir, filename) { * Note: Directories should be passed to this function without a trailing slash. */ exports.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts) { - opts = opts || {}; - try { - if(fs.statSync(newDirLocation).isDirectory()) { - if(opts.forceDelete) { - exports.rmdirSyncRecursive(newDirLocation); - } else { - return new Error('You are trying to delete a directory that already exists. Specify forceDelete in the opts argument to override this. Bailing~'); - } - } + if(fs.statSync(newDirLocation).isDirectory()) { + if(typeof opts !== 'undefined' && opts.forceDelete) { + exports.rmdirSyncRecursive(newDirLocation); + } else { + return new Error('You are trying to delete a directory that already exists. Specify forceDelete in the opts argument to override this. Bailing~'); + } + } } catch(e) { } /* Create the directory where all our junk is moving to; read the mode of the source directory and mirror it */ @@ -250,19 +186,13 @@ exports.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts) { } var files = fs.readdirSync(sourceDir); - var hasFilter = opts.filter || opts.include || opts.exclude; - var preserveFiles = opts.preserveFiles === true; - var preserveTimestamps = opts.preserveTimestamps === true; for(var i = 0; i < files.length; i++) { // ignores all files or directories which match the RegExp in opts.filter - if(typeof opts !== 'undefined') { - if (hasFilter) { - if (!isFileIncluded(opts, sourceDir, files[i])) { - continue; - } - } - + if(typeof opts !== 'undefined') { + if(!opts.whitelist && opts.filter && files[i].match(opts.filter)) continue; + // if opts.whitelist is true every file or directory which doesn't match opts.filter will be ignored + if(opts.whitelist && opts.filter && !files[i].match(opts.filter)) continue; if (opts.excludeHiddenUnix && /^\./.test(files[i])) continue; } @@ -275,9 +205,6 @@ exports.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts) { fs.writeFileSync(destFile, contents); var stat = fs.lstatSync(srcFile); fs.chmodSync(destFile, stat.mode); - if (preserveTimestamps) { - fs.utimesSync(destFile, stat.atime, stat.mtime) - } }; if(currFile.isDirectory()) { @@ -285,19 +212,18 @@ exports.copyDirSyncRecursive = function(sourceDir, newDirLocation, opts) { exports.copyDirSyncRecursive(_path.join(sourceDir, files[i]), _path.join(newDirLocation, files[i]), opts); } else if(currFile.isSymbolicLink()) { var symlinkFull = fs.readlinkSync(_path.join(sourceDir, files[i])); - symlinkFull = _path.resolve(fs.realpathSync(sourceDir), symlinkFull); if (typeof opts !== 'undefined' && !opts.inflateSymlinks) { fs.symlinkSync(symlinkFull, _path.join(newDirLocation, files[i])); continue; } - var tmpCurrFile = fs.lstatSync(symlinkFull); + var tmpCurrFile = fs.lstatSync(_path.join(sourceDir, symlinkFull)); if (tmpCurrFile.isDirectory()) { - exports.copyDirSyncRecursive(symlinkFull, _path.join(newDirLocation, files[i]), opts); + exports.copyDirSyncRecursive(_path.join(sourceDir, symlinkFull), _path.join(newDirLocation, files[i]), opts); } else { /* At this point, we've hit a file actually worth copying... so copy it on over. */ - fCopyFile(symlinkFull, _path.join(newDirLocation, files[i])); + fCopyFile(_path.join(sourceDir, symlinkFull), _path.join(newDirLocation, files[i])); } } else { /* At this point, we've hit a file actually worth copying... so copy it on over. */ @@ -366,16 +292,22 @@ 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) {}; + if (clbk === null || typeof clbk == 'undefined') { + clbk = function(err) {}; + } + + fs.readdir(dir, function(err, files){ + if(err) { + if (typeof failSilent === 'boolean' && failSilent) { + return clbk(null); + } else { + return clbk(err); + } + } - fs.readdir(dir, function(err, files) { - if(err && typeof failSilent === 'boolean' && !failSilent) - return clbk(err); + if(typeof failSilent === 'function') + clbk = failSilent; - if(typeof failSilent === 'function') - clbk = failSilent; - (function rmFile(err){ if (err) return clbk(err); @@ -395,66 +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) { - var originalArguments = Array.prototype.slice.apply(arguments); + + if (typeof opts === 'function') + clbk = opts; srcDir = _path.normalize(srcDir); newDir = _path.normalize(newDir); - 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, originalArguments); + 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); + } }); - 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){ + 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 (err) return clbk(err); - if (fileStat.isDirectory()) - copyDirRecursive(file, newFile, copyFiles, clbk); - else if (fileStat.isSymbolicLink()) - fs.readlink(file, function(err, link){ - if (err) return clbk(err); - fs.symlink(link, newFile, copyFiles); - }); - else - fs.readFile(file, function(err, data){ - if (err) return clbk(err); - fs.writeFile(newFile, data, copyFiles); - }); - }); - })(); + copyDirRecInner(); }); }); - }); + } }); }; @@ -521,7 +484,7 @@ exports.LineReader.prototype = { getNextLine: function() { var lineEnd = this.buffer.indexOf("\n"), - result = this.buffer.substring(0, lineEnd != -1 ? lineEnd : this.buffer.length); + result = this.buffer.substring(0, lineEnd ? lineEnd : this.buffer.length); this.buffer = this.buffer.substring(result.length + 1, this.buffer.length); return result; diff --git a/package.json b/package.json index 742b2b3..47cbc15 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "wrench", "description": "Recursive filesystem (and other) operations that Node *should* have.", - "version": "1.5.9", + "version": "1.5.1", "author": "Ryan McGrath ", "repository": { @@ -18,6 +18,7 @@ }, "dependencies": { + "mkdirp": "*" }, "devDependencies": { diff --git a/readme.md b/readme.md index 3749457..5d573a5 100644 --- a/readme.md +++ b/readme.md @@ -1,15 +1,3 @@ -Warning: This Project Is Deprecated! ----------------------------------------------------------------------------- -`wrench.js` is deprecated, and hasn't been updated in quite some time. **[I heavily recommend using fs-extra](https://github.com/jprichardson/node-fs-extra)** to do any extra filesystem operations. - -Wrench was built for the _early_ days of Node, and it solved a problem that needed solving. I'm proud of what it's done; at the time of writing this, it was still downloaded over 25,000 times yesterday, and over 500,000 times in the last month. The fact that it wound up being embedded in so many projects is humbling and a great source of fun for me, but I just don't have the time to keep up with this at the moment. No alternate maintainers have appeared, and fs-extra is very well maintained anyway - one community solution is likely better. - -So long, and thanks for all the fish. The original docs remain available here for anyone who may need them. If I could 301 a GitHub repository I'd do so. - -Cheers, -- Ryan McGrath - - wrench.js - Recursive file operations in Node.js ---------------------------------------------------------------------------- While I love Node.js, I've found myself missing some functions. Things like @@ -77,18 +65,11 @@ wrench.copyDirSyncRecursive('directory_to_copy', 'location_where_copy_should_end forceDelete: bool, // Whether to overwrite existing directory or not excludeHiddenUnix: bool, // Whether to copy hidden Unix files or not (preceding .) preserveFiles: bool, // If we're overwriting something and the file already exists, keep the existing - preserveTimestamps: bool, // Preserve the mtime and atime when copying files inflateSymlinks: bool, // Whether to follow symlinks or not when copying files - filter: regexpOrFunction, // A filter to match files against; if matches, do nothing (exclude). + filter: regexp, // A filter to match files against; if matches, do nothing (exclude). whitelist: bool, // if true every file or directory which doesn't match filter will be ignored - include: regexpOrFunction, // An include filter (either a regexp or a function) - exclude: regexpOrFunction // An exclude filter (either a regexp or a function) }); -// Note: If a RegExp is provided then then it will be matched against the filename. If a function is -// provided then the signature should be the following: -// function(filename, dir) { return result; } - // Read lines in from a file until you hit the end var f = new wrench.LineReader('x.txt'); while(f.hasNextLine()) { diff --git a/tests/copydirsync_unix.js b/tests/copydirsync_unix.js index c48bb62..676c9fa 100644 --- a/tests/copydirsync_unix.js +++ b/tests/copydirsync_unix.js @@ -46,21 +46,6 @@ function checkResultInflate(test, files) { test.deepEqual(fs.lstatSync(path.join(__dirname, 'testdir/bar.txt')).isSymbolicLink(), false); } -function checkResultInflateAbsolute(test, files) { - var check = [ - '.hidden', - 'absolute-bar.txt', - 'bar.txt', - 'test', - path.join('.hidden', 'dolor.md') - ]; - - test.deepEqual(files, check); - - test.deepEqual(fs.lstatSync(path.join(__dirname, 'testdir/.hidden')).isSymbolicLink(), false); - test.deepEqual(fs.lstatSync(path.join(__dirname, 'testdir/bar.txt')).isSymbolicLink(), false); -} - function checkResultDontInflate(test, files) { var check = [ '.hidden', @@ -107,6 +92,7 @@ module.exports = testCase({ test.ok(fs.existsSync(dir), 'Folders should exist'); + wrench.mkdirSyncRecursive(testdir, 0777); wrench.copyDirSyncRecursive(dir, testdir, { excludeHiddenUnix: false }); var files = wrench.readdirSyncRecursive(testdir); @@ -123,6 +109,7 @@ module.exports = testCase({ test.ok(fs.existsSync(dir), 'Folders should exist'); + wrench.mkdirSyncRecursive(testdir, 0777); wrench.copyDirSyncRecursive(dir, testdir, { excludeHiddenUnix: true }); var files = wrench.readdirSyncRecursive(testdir); @@ -139,6 +126,7 @@ module.exports = testCase({ test.ok(fs.existsSync(dir), 'Folders should exist'); + wrench.mkdirSyncRecursive(testdir, 0777); wrench.copyDirSyncRecursive(dir, testdir, { excludeHiddenUnix: false, inflateSymlinks: true }); var files = wrench.readdirSyncRecursive(testdir); @@ -149,33 +137,13 @@ module.exports = testCase({ test.done(); }, - test_copyDirSyncRecursiveInflateAbsoluteSymlinks: function(test) { - var dir = path.join(__dirname, 'withsymlinks'); - var testdir = path.join(__dirname, 'testdir'); - - fs.symlinkSync( - path.resolve(__dirname, 'shown/bar.txt'), - path.join(dir, 'absolute-bar.txt') - ); - - wrench.mkdirSyncRecursive(testdir, 0777); - wrench.copyDirSyncRecursive(dir, testdir, { forceDelete: true, excludeHiddenUnix: false, inflateSymlinks: true }); - - var files = wrench.readdirSyncRecursive(testdir); - - checkResultInflateAbsolute(test, files); - - wrench.rmdirSyncRecursive(testdir); - fs.unlinkSync(path.join(dir, 'absolute-bar.txt')); - - test.done(); - }, test_copyDirSyncRecursiveDontInflate: function(test) { var dir = path.join(__dirname, 'withsymlinks'); var testdir = path.join(__dirname, 'testdir'); test.ok(fs.existsSync(dir), 'Folders should exist'); + wrench.mkdirSyncRecursive(testdir, 0777); wrench.copyDirSyncRecursive(dir, testdir, { excludeHiddenUnix: false, inflateSymlinks: false }); var files = wrench.readdirSyncRecursive(testdir); @@ -193,14 +161,14 @@ module.exports = testCase({ test.ok(fs.existsSync(dir), 'Folders should exist'); - // wrench.mkdirSyncRecursive(testdir1, 0777); + wrench.mkdirSyncRecursive(testdir1, 0777); wrench.copyDirSyncRecursive(dir, testdir1, { excludeHiddenUnix: false }); wrench.copyDirSyncRecursive(dir, testdir2, { excludeHiddenUnix: false }); fs.writeFileSync(path.join(testdir1, ".hidden.txt"), 'just some text for .hidden.txt'); fs.writeFileSync(path.join(testdir1, "bar.txt"), 'just some text for bar.txt'); - wrench.copyDirSyncRecursive(testdir1, testdir2, { excludeHiddenUnix: false, preserveFiles: true }); + wrench.copyDirSyncRecursive(testdir1, testdir2, { preserve: true, excludeHiddenUnix: false, preserveFiles: true }); var files = wrench.readdirSyncRecursive(testdir2); @@ -218,14 +186,14 @@ module.exports = testCase({ test.ok(fs.existsSync(dir), 'Folders should exist'); - // wrench.mkdirSyncRecursive(testdir1, 0777); + wrench.mkdirSyncRecursive(testdir1, 0777); wrench.copyDirSyncRecursive(dir, testdir1, { excludeHiddenUnix: false }); wrench.copyDirSyncRecursive(dir, testdir2, { excludeHiddenUnix: false }); fs.writeFileSync(path.join(testdir1, ".hidden.txt"), 'just some text for .hidden.txt'); fs.writeFileSync(path.join(testdir1, "bar.txt"), 'just some text for bar.txt'); - wrench.copyDirSyncRecursive(testdir1, testdir2, { forceDelete: true, excludeHiddenUnix: false, preserveFiles: false }); + wrench.copyDirSyncRecursive(testdir1, testdir2, { preserve: true, excludeHiddenUnix: false, preserveFiles: false }); var files = wrench.readdirSyncRecursive(testdir2); diff --git a/tests/rmdirSyncRecursive.js b/tests/rmdirSyncRecursive.js deleted file mode 100644 index 3415e84..0000000 --- a/tests/rmdirSyncRecursive.js +++ /dev/null @@ -1,74 +0,0 @@ -var testCase = require('nodeunit').testCase; -var fs = require('fs'); -var wrench = require('../lib/wrench'); -var path = require('path'); - -module.exports = testCase({ - test_rmdirSyncRecursive: function(test) { - var dir = __dirname + '/_tmp2/foo/bar'; - - wrench.mkdirSyncRecursive(dir, '777'); - - var f1Path = path.join(dir, 'test1.txt'); - var f2Path = path.join(path.dirname(dir), 'test2.txt'); - var f3Path = path.join(path.dirname(path.dirname(dir)), 'test3.txt'); - - fs.writeFileSync(f1Path, 'foo bar baz'); - fs.writeFileSync(f2Path, 'foo bar baz'); - fs.writeFileSync(f3Path, 'foo bar baz'); - - fs.chmodSync(f1Path, '444'); - fs.chmodSync(f2Path, '444'); - fs.chmodSync(f3Path, '444'); - - test.equals(fs.existsSync(dir), true, 'Dir should exist - mkdirSyncRecursive not working?'); - test.equals(fs.existsSync(f1Path), true, 'File should exist'); - test.equals(fs.existsSync(f2Path), true, 'File should exist'); - test.equals(fs.existsSync(f3Path), true, 'File should exist'); - - wrench.rmdirSyncRecursive(dir); - - test.equals(fs.existsSync(dir), false, 'Dir should not exist now...'); - test.equals(fs.existsSync(f1Path), false, 'File should not exist'); - test.equals(fs.existsSync(f2Path), true, 'File should exist'); - test.equals(fs.existsSync(f3Path), true, 'File should exist'); - - wrench.rmdirSyncRecursive(path.dirname(path.dirname(dir))); - - test.done(); - }, - - test_rmdirSyncRecursiveFromRoot: function(test) { - var dir = __dirname + '/_tmp3/foo/bar'; - - wrench.mkdirSyncRecursive(dir, '777'); - - var f1Path = path.join(dir, 'test1.txt'); - var f2Path = path.join(path.dirname(dir), 'test2.txt'); - var f3Path = path.join(path.dirname(path.dirname(dir)), 'test3.txt'); - - fs.writeFileSync(f1Path, 'foo bar baz'); - fs.writeFileSync(f2Path, 'foo bar baz'); - fs.writeFileSync(f3Path, 'foo bar baz'); - - fs.chmodSync(f1Path, '444'); - fs.chmodSync(f2Path, '444'); - fs.chmodSync(f3Path, '444'); - - test.equals(fs.existsSync(dir), true, 'Dir should exist - mkdirSyncRecursive not working?'); - test.equals(fs.existsSync(f1Path), true, 'File should exist'); - test.equals(fs.existsSync(f2Path), true, 'File should exist'); - test.equals(fs.existsSync(f3Path), true, 'File should exist'); - - wrench.rmdirSyncRecursive(path.dirname(path.dirname(dir))); - - test.equals(fs.existsSync(dir), false, 'Dir should not exist now...'); - test.equals(fs.existsSync(f1Path), false, 'File should not exist'); - test.equals(fs.existsSync(f2Path), false, 'File should not exist'); - test.equals(fs.existsSync(f3Path), false, 'File should not exist'); - - test.done(); - } -}); - -// vim: et ts=4 sw=4 diff --git a/tests/runner.js b/tests/runner.js index e321a15..8f90dae 100644 --- a/tests/runner.js +++ b/tests/runner.js @@ -4,6 +4,5 @@ module.exports = { group_mkdir: require('./mkdir'), group_readdir: require('./readdir'), - group_copydir: require('./copydirsync_unix'), - group_rmdir: require('./rmdirSyncRecursive') + group_copydir: require('./copydirsync_unix') };