44 lines
1.1 KiB
TypeScript
44 lines
1.1 KiB
TypeScript
/**
|
|
* Recursive copy for scripts that must not call `cpSync`: it fails EACCES
|
|
* against a macOS docker bind mount, where the toolkit's job dirs live.
|
|
*/
|
|
|
|
import {
|
|
chmodSync,
|
|
copyFileSync,
|
|
lstatSync,
|
|
mkdirSync,
|
|
readdirSync,
|
|
readlinkSync,
|
|
rmSync,
|
|
statSync,
|
|
symlinkSync,
|
|
} from 'fs';
|
|
import { join } from 'path';
|
|
|
|
/** Copy one entry — symlink, directory or file — preserving its mode. */
|
|
export function copyPath(src: string, dest: string) {
|
|
const st = lstatSync(src);
|
|
if (st.isSymbolicLink()) {
|
|
rmSync(dest, { force: true });
|
|
symlinkSync(readlinkSync(src), dest);
|
|
return;
|
|
}
|
|
if (st.isDirectory()) {
|
|
copyTree(src, dest);
|
|
return;
|
|
}
|
|
// Unlink first: copyFileSync onto an existing file keeps that file's mode.
|
|
rmSync(dest, { force: true });
|
|
copyFileSync(src, dest);
|
|
chmodSync(dest, statSync(src).mode & 0o777);
|
|
}
|
|
|
|
/** Copy `src`'s contents into `dest`, creating `dest` if it doesn't exist. */
|
|
export function copyTree(src: string, dest: string) {
|
|
mkdirSync(dest, { recursive: true });
|
|
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
copyPath(join(src, entry.name), join(dest, entry.name));
|
|
}
|
|
}
|