2019-06-06 12:33:11 +02:00
|
|
|
import path from 'path'
|
2020-05-02 06:10:19 +02:00
|
|
|
import { promises, constants } from 'fs'
|
2020-03-29 00:27:09 +01:00
|
|
|
import { Sema } from 'next/dist/compiled/async-sema'
|
2019-06-06 12:33:11 +02:00
|
|
|
|
2020-05-02 06:10:19 +02:00
|
|
|
const COPYFILE_EXCL = constants.COPYFILE_EXCL
|
2019-06-06 12:33:11 +02:00
|
|
|
|
|
|
|
export async function recursiveCopy(
|
|
|
|
source: string,
|
|
|
|
dest: string,
|
|
|
|
{
|
2019-11-15 22:53:59 +01:00
|
|
|
concurrency = 32,
|
|
|
|
overwrite = false,
|
2019-06-06 12:33:11 +02:00
|
|
|
filter = () => true,
|
2019-11-15 22:53:59 +01:00
|
|
|
}: {
|
|
|
|
concurrency?: number
|
|
|
|
overwrite?: boolean
|
|
|
|
filter?(path: string): boolean
|
|
|
|
} = {}
|
2020-05-19 10:59:03 +02:00
|
|
|
): Promise<void> {
|
2019-06-06 12:33:11 +02:00
|
|
|
const cwdPath = process.cwd()
|
|
|
|
const from = path.resolve(cwdPath, source)
|
|
|
|
const to = path.resolve(cwdPath, dest)
|
|
|
|
|
|
|
|
const sema = new Sema(concurrency)
|
|
|
|
|
2020-05-25 00:44:05 +02:00
|
|
|
async function _copy(item: string): Promise<void> {
|
2019-06-06 12:33:11 +02:00
|
|
|
const target = item.replace(from, to)
|
2020-05-02 06:10:19 +02:00
|
|
|
const stats = await promises.stat(item)
|
2019-06-06 12:33:11 +02:00
|
|
|
|
|
|
|
await sema.acquire()
|
|
|
|
|
|
|
|
if (stats.isDirectory()) {
|
|
|
|
try {
|
2020-05-02 06:10:19 +02:00
|
|
|
await promises.mkdir(target)
|
2019-06-06 12:33:11 +02:00
|
|
|
} catch (err) {
|
|
|
|
// do not throw `folder already exists` errors
|
|
|
|
if (err.code !== 'EEXIST') {
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
}
|
2019-11-15 22:53:59 +01:00
|
|
|
sema.release()
|
2020-05-02 06:10:19 +02:00
|
|
|
const files = await promises.readdir(item)
|
2020-05-18 21:24:37 +02:00
|
|
|
await Promise.all(files.map((file) => _copy(path.join(item, file))))
|
2019-06-06 12:33:11 +02:00
|
|
|
} else if (
|
|
|
|
stats.isFile() &&
|
|
|
|
// before we send the path to filter
|
|
|
|
// we remove the base path (from) and replace \ by / (windows)
|
|
|
|
filter(item.replace(from, '').replace(/\\/g, '/'))
|
|
|
|
) {
|
2020-05-02 06:10:19 +02:00
|
|
|
await promises.copyFile(
|
|
|
|
item,
|
|
|
|
target,
|
|
|
|
overwrite ? undefined : COPYFILE_EXCL
|
|
|
|
)
|
2019-11-15 22:53:59 +01:00
|
|
|
sema.release()
|
2019-06-06 12:33:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await _copy(from)
|
|
|
|
}
|