Skip to content

Commit 1d931c8

Browse files
authored
Refactor copy to use opendir (#1028)
* refactor(copy): backport nodejs/node#41351 * perf(copy): parallel copy * perf(copy): run filter in parallel as well
1 parent acf5585 commit 1d931c8

File tree

2 files changed

+30
-15
lines changed

2 files changed

+30
-15
lines changed

lib/copy/copy-sync.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,17 @@ function mkDirAndCopy (srcMode, src, dest, opts) {
106106
}
107107

108108
function copyDir (src, dest, opts) {
109-
fs.readdirSync(src).forEach(item => copyDirItem(item, src, dest, opts))
109+
const dir = fs.opendirSync(src)
110+
111+
try {
112+
let dirent
113+
114+
while ((dirent = dir.readSync()) !== null) {
115+
copyDirItem(dirent.name, src, dest, opts)
116+
}
117+
} finally {
118+
dir.closeSync()
119+
}
110120
}
111121

112122
function copyDirItem (item, src, dest, opts) {

lib/copy/copy.js

+19-14
Original file line numberDiff line numberDiff line change
@@ -113,23 +113,28 @@ async function onDir (srcStat, destStat, src, dest, opts) {
113113
await fs.mkdir(dest)
114114
}
115115

116-
const items = await fs.readdir(src)
116+
const promises = []
117117

118118
// loop through the files in the current directory to copy everything
119-
await Promise.all(items.map(async item => {
120-
const srcItem = path.join(src, item)
121-
const destItem = path.join(dest, item)
122-
123-
// skip the item if it is matches by the filter function
124-
const include = await runFilter(srcItem, destItem, opts)
125-
if (!include) return
126-
127-
const { destStat } = await stat.checkPaths(srcItem, destItem, 'copy', opts)
119+
for await (const item of await fs.opendir(src)) {
120+
const srcItem = path.join(src, item.name)
121+
const destItem = path.join(dest, item.name)
122+
123+
promises.push(
124+
runFilter(srcItem, destItem, opts).then(include => {
125+
if (include) {
126+
// only copy the item if it matches the filter function
127+
return stat.checkPaths(srcItem, destItem, 'copy', opts).then(({ destStat }) => {
128+
// If the item is a copyable file, `getStatsAndPerformCopy` will copy it
129+
// If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively
130+
return getStatsAndPerformCopy(destStat, srcItem, destItem, opts)
131+
})
132+
}
133+
})
134+
)
135+
}
128136

129-
// If the item is a copyable file, `getStatsAndPerformCopy` will copy it
130-
// If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively
131-
return getStatsAndPerformCopy(destStat, srcItem, destItem, opts)
132-
}))
137+
await Promise.all(promises)
133138

134139
if (!destStat) {
135140
await fs.chmod(dest, srcStat.mode)

0 commit comments

Comments
 (0)