Refactor copy to use opendir (#1028)

* refactor(copy): backport https://github.com/nodejs/node/pull/41351

* perf(copy): parallel copy

* perf(copy): run filter in parallel as well
This commit is contained in:
Sukka 2024-02-11 02:11:25 +08:00 committed by GitHub
parent acf5585558
commit 1d931c88b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 14 deletions

View File

@ -106,7 +106,17 @@ function mkDirAndCopy (srcMode, src, dest, opts) {
}
function copyDir (src, dest, opts) {
fs.readdirSync(src).forEach(item => copyDirItem(item, src, dest, opts))
const dir = fs.opendirSync(src)
try {
let dirent
while ((dirent = dir.readSync()) !== null) {
copyDirItem(dirent.name, src, dest, opts)
}
} finally {
dir.closeSync()
}
}
function copyDirItem (item, src, dest, opts) {

View File

@ -113,23 +113,28 @@ async function onDir (srcStat, destStat, src, dest, opts) {
await fs.mkdir(dest)
}
const items = await fs.readdir(src)
const promises = []
// loop through the files in the current directory to copy everything
await Promise.all(items.map(async item => {
const srcItem = path.join(src, item)
const destItem = path.join(dest, item)
for await (const item of await fs.opendir(src)) {
const srcItem = path.join(src, item.name)
const destItem = path.join(dest, item.name)
// skip the item if it is matches by the filter function
const include = await runFilter(srcItem, destItem, opts)
if (!include) return
promises.push(
runFilter(srcItem, destItem, opts).then(include => {
if (include) {
// only copy the item if it matches the filter function
return stat.checkPaths(srcItem, destItem, 'copy', opts).then(({ destStat }) => {
// If the item is a copyable file, `getStatsAndPerformCopy` will copy it
// If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively
return getStatsAndPerformCopy(destStat, srcItem, destItem, opts)
})
}
})
)
}
const { destStat } = await stat.checkPaths(srcItem, destItem, 'copy', opts)
// If the item is a copyable file, `getStatsAndPerformCopy` will copy it
// If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively
return getStatsAndPerformCopy(destStat, srcItem, destItem, opts)
}))
await Promise.all(promises)
if (!destStat) {
await fs.chmod(dest, srcStat.mode)