Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor copy API in async/await #1021

Merged
merged 15 commits into from Oct 24, 2023
71 changes: 31 additions & 40 deletions lib/copy/copy.js
Expand Up @@ -36,27 +36,22 @@ async function copy (src, dest, opts = {}) {

if (!include) return

return checkParentDir(destStat, src, dest, opts)
}

async function checkParentDir (destStat, src, dest, opts) {
// check if the parent of dest exists, and create it if it doesn't exist
const destParent = path.dirname(dest)

const dirExists = await pathExists(destParent)

if (!dirExists) {
await mkdirs(destParent)
}

return getStats(destStat, src, dest, opts)
await getStatsAndPerformCopy(destStat, src, dest, opts)
}

async function runFilter (src, dest, opts) {
if (!opts.filter) return true
return opts.filter(src, dest)
}

async function getStats (destStat, src, dest, opts) {
async function getStatsAndPerformCopy (destStat, src, dest, opts) {
const statFn = opts.dereference ? fs.stat : fs.lstat
const srcStat = await statFn(src)

Expand Down Expand Up @@ -101,19 +96,10 @@ async function handleTimestampsAndMode (srcMode, src, dest) {
if (fileIsNotWritable(srcMode)) {
await makeFileWritable(dest, srcMode)
}
return setDestTimestampsAndMode(srcMode, src, dest)
}

function fileIsNotWritable (srcMode) {
return (srcMode & 0o200) === 0
}
// Set timestamps and mode correspondingly

function makeFileWritable (dest, srcMode) {
return setDestMode(dest, srcMode | 0o200)
}

async function setDestTimestampsAndMode (srcMode, src, dest) {
// The initial srcStat.atime cannot be trusted
// Note that The initial srcStat.atime cannot be trusted
// because it is modified by the read(2) system call
// (See https://nodejs.org/api/fs.html#fs_stat_time_values)
const updatedSrcStat = await fs.stat(src)
Expand All @@ -122,43 +108,47 @@ async function setDestTimestampsAndMode (srcMode, src, dest) {
return setDestMode(dest, srcMode)
}

function fileIsNotWritable (srcMode) {
return (srcMode & 0o200) === 0
}

function makeFileWritable (dest, srcMode) {
return setDestMode(dest, srcMode | 0o200)
}

function setDestMode (dest, srcMode) {
return fs.chmod(dest, srcMode)
}

async function onDir (srcStat, destStat, src, dest, opts) {
// the dest direcotry might not exist, create it
SukkaW marked this conversation as resolved.
Show resolved Hide resolved
if (!destStat) {
await fs.mkdir(dest)
}
await copyDir(src, dest, opts)
if (!destStat) {
await setDestMode(dest, srcStat.mode)
}
}

async function copyDir (src, dest, opts) {
const items = await fs.readdir(src)
return copyDirItems(items, src, dest, opts)
}

function copyDirItems (items, src, dest, opts) {
const item = items.pop()
if (!item) return
return copyDirItem(items, item, src, dest, opts)
}
// loop through the files in the current directory to copy everything
for (let i = 0, len = items.length; i < len; i++) {
const item = items[i]
SukkaW marked this conversation as resolved.
Show resolved Hide resolved

async function copyDirItem (items, item, src, dest, opts) {
const srcItem = path.join(src, item)
const destItem = path.join(dest, item)
const srcItem = path.join(src, item)
const destItem = path.join(dest, item)

const include = await runFilter(srcItem, destItem, opts)
if (!include) return copyDirItems(items, src, dest, opts)
// skip the item if it is matches by the filter function
const include = await runFilter(srcItem, destItem, opts)
if (!include) continue

const { destStat } = await stat.checkPathsAsync(srcItem, destItem, 'copy', opts)
const { destStat } = await stat.checkPathsAsync(srcItem, destItem, 'copy', opts)

await getStats(destStat, srcItem, destItem, opts)
// If the item is a copyable file, `getStatsAndPerformCopy` will copy it
// If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively
await getStatsAndPerformCopy(destStat, srcItem, destItem, opts)
}

return copyDirItems(items, src, dest, opts)
if (!destStat) {
await setDestMode(dest, srcStat.mode)
}
}

async function onLink (destStat, src, dest, opts) {
Expand Down Expand Up @@ -194,6 +184,7 @@ async function onLink (destStat, src, dest, opts) {
throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)
}

// copy the link
await fs.unlink(dest)
return fs.symlink(resolvedSrc, dest)
}
Expand Down