Skip to content

Commit

Permalink
refactor copy to be less complex (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdistin committed Dec 17, 2018
1 parent 1afe969 commit 9e59275
Showing 1 changed file with 38 additions and 26 deletions.
64 changes: 38 additions & 26 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,39 +139,51 @@ exports.startCopy = async (mySource, options) => {
if (options.filter && !options.filter(mySource, options.targetPath)) return null;
const myStat = options.dereference ? stat : lstat;
const stats = await myStat(mySource);
let target = mySource.replace(options.currentPath, this.replaceEsc(options.targetPath));

if (stats.isDirectory()) {
const target = mySource.replace(options.currentPath, options.targetPath.replace('$', '$$$$'));
if (this.isSrcKid(mySource, target)) throw new Error('FS-NEXTRA: Copying a parent directory into a child will result in an infinite loop.');
if (await this.isWritable(target)) {
await mkdir(target, stats.mode);
await chmod(target, stats.mode);
}
const items = await readdir(mySource);
return Promise.all(items.map(item => this.startCopy(join(mySource, item), options)));
} else if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
let target = mySource.replace(options.currentPath, options.targetPath.replace('$', '$$$$'));
return this.copyDir(mySource, target, stats, options);
} else if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice() || stats.isSymbolicLink()) {
const tstats = await stat(target).catch(() => null);
if (tstats && tstats.isDirectory()) target = join(target, basename(mySource));
if (await this.isWritable(target)) return copyFile(mySource, target, options);
else if (options.overwrite) return unlink(target).then(() => copyFile(mySource, target, options));
else if (options.errorOnExist) throw new Error(`${target} already exists`);
} else if (stats.isSymbolicLink()) {
let target = mySource.replace(options.currentPath, options.targetPath);
const tstats = await stat(target).catch(() => null);
if (tstats && tstats.isDirectory()) target = join(target, basename(mySource));
let resolvedPath = await readlink(mySource);
if (options.dereference) resolvedPath = resolve(process.cwd(), resolvedPath);
if (await this.isWritable(target)) return symlink(resolvedPath, target);
let targetDest = await readlink(target);
if (options.dereference) targetDest = resolve(process.cwd(), targetDest);
if (targetDest === resolvedPath) return null;
await unlink(target);
return symlink(resolvedPath, target);

return stats.isSymbolicLink() ?
this.copyLink(mySource, target, options) :
this.copyFile(mySource, target, options);
}
throw new Error('FS-NEXTRA: An Unknown error has occurred in startCopy.');
};

exports.copyDir = async (mySource, target, stats, options) => {
if (this.isSrcKid(mySource, target)) throw new Error('FS-NEXTRA: Copying a parent directory into a child will result in an infinite loop.');
if (await this.isWritable(target)) {
await mkdir(target, stats.mode);
await chmod(target, stats.mode);
}
throw new Error('FS-NEXTRA: An Unkown error has occured in startCopy.');
const items = await readdir(mySource);
return Promise.all(items.map(item => this.startCopy(join(mySource, item), options)));
};

exports.copyFile = async (mySource, target, options) => {
if (await this.isWritable(target)) return copyFile(mySource, target, options);
else if (options.overwrite) return unlink(target).then(() => copyFile(mySource, target, options));
else if (options.errorOnExist) throw new Error(`${target} already exists`);
return null;
};

exports.copyLink = async (mySource, target, options) => {
let resolvedPath = await readlink(mySource);
if (options.dereference) resolvedPath = resolve(process.cwd(), resolvedPath);
if (await this.isWritable(target)) return symlink(resolvedPath, target);
let targetDest = await readlink(target);
if (options.dereference) targetDest = resolve(process.cwd(), targetDest);
if (targetDest === resolvedPath) return null;
await unlink(target);
return symlink(resolvedPath, target);
};

exports.replaceEsc = (str) => str.replace(/\$/g, '$$');

exports.isSrcKid = (src, dest) => {
src = resolve(src);
dest = resolve(dest);
Expand Down

0 comments on commit 9e59275

Please sign in to comment.