2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2022-09-05 04:55:53 +00:00
|
|
|
|
2024-04-29 02:57:30 +00:00
|
|
|
import { basename } from "@std/path/basename";
|
|
|
|
import { join } from "@std/path/join";
|
|
|
|
import { resolve } from "@std/path/resolve";
|
2019-05-16 16:19:17 +00:00
|
|
|
import { ensureDir, ensureDirSync } from "./ensure_dir.ts";
|
2023-12-21 07:39:51 +00:00
|
|
|
import { getFileInfoType } from "./_get_file_info_type.ts";
|
|
|
|
import { toPathString } from "./_to_path_string.ts";
|
|
|
|
import { isSubdir } from "./_is_subdir.ts";
|
2023-08-25 09:07:43 +00:00
|
|
|
|
2024-10-24 05:44:27 +00:00
|
|
|
// deno-lint-ignore no-explicit-any
|
|
|
|
const isWindows = (globalThis as any).Deno?.build.os === "windows";
|
2020-05-18 22:46:02 +00:00
|
|
|
|
2023-12-05 08:52:56 +00:00
|
|
|
/** Options for {@linkcode copy} and {@linkcode copySync}. */
|
2019-05-16 16:19:17 +00:00
|
|
|
export interface CopyOptions {
|
|
|
|
/**
|
2024-03-27 06:28:06 +00:00
|
|
|
* Whether to overwrite existing file or directory.
|
|
|
|
*
|
2022-11-25 11:40:23 +00:00
|
|
|
* @default {false}
|
2019-05-16 16:19:17 +00:00
|
|
|
*/
|
|
|
|
overwrite?: boolean;
|
|
|
|
/**
|
2024-03-27 06:28:06 +00:00
|
|
|
* When `true`, will set last modification and access times to the ones of
|
|
|
|
* the original source files. When `false`, timestamp behavior is
|
|
|
|
* OS-dependent.
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-07-29 11:31:14 +00:00
|
|
|
* > [!NOTE]
|
2024-07-25 06:49:22 +00:00
|
|
|
* > This option is currently unsupported for symbolic links.
|
2024-06-26 03:21:48 +00:00
|
|
|
*
|
2022-11-25 11:40:23 +00:00
|
|
|
* @default {false}
|
2019-05-16 16:19:17 +00:00
|
|
|
*/
|
|
|
|
preserveTimestamps?: boolean;
|
|
|
|
}
|
|
|
|
|
2020-11-12 22:13:13 +00:00
|
|
|
interface InternalCopyOptions extends CopyOptions {
|
2022-11-25 11:40:23 +00:00
|
|
|
/** @default {false} */
|
2020-11-12 22:13:13 +00:00
|
|
|
isFolder?: boolean;
|
|
|
|
}
|
|
|
|
|
2024-06-05 01:39:33 +00:00
|
|
|
function assertIsDate(date: Date | null, name: string): asserts date is Date {
|
|
|
|
if (date === null) {
|
|
|
|
throw new Error(`${name} is unavailable`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-16 16:19:17 +00:00
|
|
|
async function ensureValidCopy(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-11-12 22:13:13 +00:00
|
|
|
options: InternalCopyOptions,
|
2020-02-08 20:15:59 +00:00
|
|
|
): Promise<Deno.FileInfo | undefined> {
|
|
|
|
let destStat: Deno.FileInfo;
|
2019-12-18 14:45:19 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
destStat = await Deno.lstat(dest);
|
|
|
|
} catch (err) {
|
2020-02-24 20:48:35 +00:00
|
|
|
if (err instanceof Deno.errors.NotFound) {
|
2019-12-18 14:45:19 +00:00
|
|
|
return;
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
2020-02-08 20:15:59 +00:00
|
|
|
throw err;
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 22:13:13 +00:00
|
|
|
if (options.isFolder && !destStat.isDirectory) {
|
2019-12-18 14:45:19 +00:00
|
|
|
throw new Error(
|
2024-08-26 04:31:34 +00:00
|
|
|
`Cannot overwrite non-directory '${dest}' with directory '${src}'`,
|
2019-12-18 14:45:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if (!options.overwrite) {
|
2022-08-31 07:04:53 +00:00
|
|
|
throw new Deno.errors.AlreadyExists(`'${dest}' already exists.`);
|
2019-12-18 14:45:19 +00:00
|
|
|
}
|
|
|
|
|
2020-02-08 20:15:59 +00:00
|
|
|
return destStat;
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function ensureValidCopySync(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-11-12 22:13:13 +00:00
|
|
|
options: InternalCopyOptions,
|
2020-02-08 20:15:59 +00:00
|
|
|
): Deno.FileInfo | undefined {
|
|
|
|
let destStat: Deno.FileInfo;
|
2019-05-16 16:19:17 +00:00
|
|
|
try {
|
|
|
|
destStat = Deno.lstatSync(dest);
|
2019-12-18 14:45:19 +00:00
|
|
|
} catch (err) {
|
2020-02-24 20:48:35 +00:00
|
|
|
if (err instanceof Deno.errors.NotFound) {
|
2019-12-18 14:45:19 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-02-08 20:15:59 +00:00
|
|
|
throw err;
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 22:13:13 +00:00
|
|
|
if (options.isFolder && !destStat.isDirectory) {
|
2019-12-18 14:45:19 +00:00
|
|
|
throw new Error(
|
2024-08-26 04:31:34 +00:00
|
|
|
`Cannot overwrite non-directory '${dest}' with directory '${src}'`,
|
2019-12-18 14:45:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if (!options.overwrite) {
|
2024-08-26 04:31:34 +00:00
|
|
|
throw new Deno.errors.AlreadyExists(`'${dest}' already exists`);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
2020-02-08 20:15:59 +00:00
|
|
|
return destStat;
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* copy file to dest */
|
|
|
|
async function copyFile(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-11-12 22:13:13 +00:00
|
|
|
options: InternalCopyOptions,
|
2021-04-05 11:49:05 +00:00
|
|
|
) {
|
2019-05-16 16:19:17 +00:00
|
|
|
await ensureValidCopy(src, dest, options);
|
|
|
|
await Deno.copyFile(src, dest);
|
|
|
|
if (options.preserveTimestamps) {
|
|
|
|
const statInfo = await Deno.stat(src);
|
2024-06-05 01:39:33 +00:00
|
|
|
assertIsDate(statInfo.atime, "statInfo.atime");
|
|
|
|
assertIsDate(statInfo.mtime, "statInfo.mtime");
|
2022-09-05 04:55:53 +00:00
|
|
|
await Deno.utime(dest, statInfo.atime, statInfo.mtime);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* copy file to dest synchronously */
|
2020-11-12 22:13:13 +00:00
|
|
|
function copyFileSync(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-11-12 22:13:13 +00:00
|
|
|
options: InternalCopyOptions,
|
2022-08-24 01:21:57 +00:00
|
|
|
) {
|
2019-05-16 16:19:17 +00:00
|
|
|
ensureValidCopySync(src, dest, options);
|
|
|
|
Deno.copyFileSync(src, dest);
|
|
|
|
if (options.preserveTimestamps) {
|
|
|
|
const statInfo = Deno.statSync(src);
|
2024-06-05 01:39:33 +00:00
|
|
|
assertIsDate(statInfo.atime, "statInfo.atime");
|
|
|
|
assertIsDate(statInfo.mtime, "statInfo.mtime");
|
2022-09-05 04:55:53 +00:00
|
|
|
Deno.utimeSync(dest, statInfo.atime, statInfo.mtime);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy symlink to dest */
|
|
|
|
async function copySymLink(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-11-12 22:13:13 +00:00
|
|
|
options: InternalCopyOptions,
|
2021-04-05 11:49:05 +00:00
|
|
|
) {
|
2019-05-16 16:19:17 +00:00
|
|
|
await ensureValidCopy(src, dest, options);
|
2020-04-29 20:39:37 +00:00
|
|
|
const originSrcFilePath = await Deno.readLink(src);
|
2019-05-16 16:19:17 +00:00
|
|
|
const type = getFileInfoType(await Deno.lstat(src));
|
2020-05-18 22:46:02 +00:00
|
|
|
if (isWindows) {
|
|
|
|
await Deno.symlink(originSrcFilePath, dest, {
|
|
|
|
type: type === "dir" ? "dir" : "file",
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
await Deno.symlink(originSrcFilePath, dest);
|
|
|
|
}
|
2019-05-16 16:19:17 +00:00
|
|
|
if (options.preserveTimestamps) {
|
|
|
|
const statInfo = await Deno.lstat(src);
|
2024-06-05 01:39:33 +00:00
|
|
|
assertIsDate(statInfo.atime, "statInfo.atime");
|
|
|
|
assertIsDate(statInfo.mtime, "statInfo.mtime");
|
2022-09-05 04:55:53 +00:00
|
|
|
await Deno.utime(dest, statInfo.atime, statInfo.mtime);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy symlink to dest synchronously */
|
|
|
|
function copySymlinkSync(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-11-12 22:13:13 +00:00
|
|
|
options: InternalCopyOptions,
|
2022-08-24 01:21:57 +00:00
|
|
|
) {
|
2019-05-16 16:19:17 +00:00
|
|
|
ensureValidCopySync(src, dest, options);
|
2020-04-29 20:39:37 +00:00
|
|
|
const originSrcFilePath = Deno.readLinkSync(src);
|
2019-05-16 16:19:17 +00:00
|
|
|
const type = getFileInfoType(Deno.lstatSync(src));
|
2020-05-18 22:46:02 +00:00
|
|
|
if (isWindows) {
|
|
|
|
Deno.symlinkSync(originSrcFilePath, dest, {
|
|
|
|
type: type === "dir" ? "dir" : "file",
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
Deno.symlinkSync(originSrcFilePath, dest);
|
|
|
|
}
|
|
|
|
|
2019-05-16 16:19:17 +00:00
|
|
|
if (options.preserveTimestamps) {
|
|
|
|
const statInfo = Deno.lstatSync(src);
|
2024-06-05 01:39:33 +00:00
|
|
|
assertIsDate(statInfo.atime, "statInfo.atime");
|
|
|
|
assertIsDate(statInfo.mtime, "statInfo.mtime");
|
2022-09-05 04:55:53 +00:00
|
|
|
Deno.utimeSync(dest, statInfo.atime, statInfo.mtime);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy folder from src to dest. */
|
|
|
|
async function copyDir(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-07-14 19:24:17 +00:00
|
|
|
options: CopyOptions,
|
2021-04-05 11:49:05 +00:00
|
|
|
) {
|
2020-11-12 22:13:13 +00:00
|
|
|
const destStat = await ensureValidCopy(src, dest, {
|
|
|
|
...options,
|
|
|
|
isFolder: true,
|
|
|
|
});
|
2019-05-16 16:19:17 +00:00
|
|
|
|
|
|
|
if (!destStat) {
|
|
|
|
await ensureDir(dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.preserveTimestamps) {
|
|
|
|
const srcStatInfo = await Deno.stat(src);
|
2024-06-05 01:39:33 +00:00
|
|
|
assertIsDate(srcStatInfo.atime, "statInfo.atime");
|
|
|
|
assertIsDate(srcStatInfo.mtime, "statInfo.mtime");
|
2022-09-05 04:55:53 +00:00
|
|
|
await Deno.utime(dest, srcStatInfo.atime, srcStatInfo.mtime);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
2022-08-30 03:58:48 +00:00
|
|
|
src = toPathString(src);
|
|
|
|
dest = toPathString(dest);
|
|
|
|
|
2023-10-12 06:16:53 +00:00
|
|
|
const promises = [];
|
|
|
|
|
2020-04-29 20:39:37 +00:00
|
|
|
for await (const entry of Deno.readDir(src)) {
|
2023-08-14 07:08:42 +00:00
|
|
|
const srcPath = join(src, entry.name);
|
|
|
|
const destPath = join(dest, basename(srcPath as string));
|
2020-04-29 20:00:31 +00:00
|
|
|
if (entry.isSymlink) {
|
2023-10-12 06:16:53 +00:00
|
|
|
promises.push(copySymLink(srcPath, destPath, options));
|
2020-04-29 20:00:31 +00:00
|
|
|
} else if (entry.isDirectory) {
|
2023-10-12 06:16:53 +00:00
|
|
|
promises.push(copyDir(srcPath, destPath, options));
|
2020-04-29 20:00:31 +00:00
|
|
|
} else if (entry.isFile) {
|
2023-10-12 06:16:53 +00:00
|
|
|
promises.push(copyFile(srcPath, destPath, options));
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-12 06:16:53 +00:00
|
|
|
|
|
|
|
await Promise.all(promises);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* copy folder from src to dest synchronously */
|
2022-08-30 03:58:48 +00:00
|
|
|
function copyDirSync(
|
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
|
|
|
options: CopyOptions,
|
|
|
|
) {
|
2020-11-12 22:13:13 +00:00
|
|
|
const destStat = ensureValidCopySync(src, dest, {
|
|
|
|
...options,
|
|
|
|
isFolder: true,
|
|
|
|
});
|
2019-05-16 16:19:17 +00:00
|
|
|
|
|
|
|
if (!destStat) {
|
|
|
|
ensureDirSync(dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.preserveTimestamps) {
|
|
|
|
const srcStatInfo = Deno.statSync(src);
|
2024-06-05 01:39:33 +00:00
|
|
|
assertIsDate(srcStatInfo.atime, "statInfo.atime");
|
|
|
|
assertIsDate(srcStatInfo.mtime, "statInfo.mtime");
|
2022-09-05 04:55:53 +00:00
|
|
|
Deno.utimeSync(dest, srcStatInfo.atime, srcStatInfo.mtime);
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
2022-08-30 03:58:48 +00:00
|
|
|
src = toPathString(src);
|
|
|
|
dest = toPathString(dest);
|
|
|
|
|
2020-04-29 20:39:37 +00:00
|
|
|
for (const entry of Deno.readDirSync(src)) {
|
2023-08-14 07:08:42 +00:00
|
|
|
const srcPath = join(src, entry.name);
|
|
|
|
const destPath = join(dest, basename(srcPath as string));
|
2020-04-29 20:00:31 +00:00
|
|
|
if (entry.isSymlink) {
|
|
|
|
copySymlinkSync(srcPath, destPath, options);
|
|
|
|
} else if (entry.isDirectory) {
|
2019-05-16 16:19:17 +00:00
|
|
|
copyDirSync(srcPath, destPath, options);
|
2020-04-29 20:00:31 +00:00
|
|
|
} else if (entry.isFile) {
|
2019-05-16 16:19:17 +00:00
|
|
|
copyFileSync(srcPath, destPath, options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-06-07 03:54:50 +00:00
|
|
|
* Asynchronously copy a file or directory (along with its contents), like
|
|
|
|
* {@linkcode https://www.ibm.com/docs/en/aix/7.3?topic=c-cp-command#cp__cp_flagr | cp -r}.
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
2024-06-07 03:54:50 +00:00
|
|
|
* Both `src` and `dest` must both be a file or directory.
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
2024-06-07 03:54:50 +00:00
|
|
|
* Requires `--allow-read` and `--allow-write` permissions.
|
|
|
|
*
|
|
|
|
* @see {@link https://docs.deno.com/runtime/manual/basics/permissions#file-system-access}
|
|
|
|
* for more information on Deno's permissions system.
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-03-27 06:28:06 +00:00
|
|
|
* @param src The source file/directory path as a string or URL.
|
|
|
|
* @param dest The destination file/directory path as a string or URL.
|
|
|
|
* @param options Options for copying.
|
2024-06-07 03:54:50 +00:00
|
|
|
*
|
2024-03-27 06:28:06 +00:00
|
|
|
* @returns A promise that resolves once the copy operation completes.
|
|
|
|
*
|
|
|
|
* @example Basic usage
|
2024-09-19 23:29:31 +00:00
|
|
|
* ```ts ignore
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { copy } from "@std/fs/copy";
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* await copy("./foo", "./bar");
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This will copy the file or directory at `./foo` to `./bar` without
|
|
|
|
* overwriting.
|
|
|
|
*
|
|
|
|
* @example Overwriting files/directories
|
2024-09-19 23:29:31 +00:00
|
|
|
* ```ts ignore
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { copy } from "@std/fs/copy";
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* await copy("./foo", "./bar", { overwrite: true });
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This will copy the file or directory at `./foo` to `./bar` and overwrite
|
|
|
|
* any existing files or directories.
|
|
|
|
*
|
|
|
|
* @example Preserving timestamps
|
2024-09-19 23:29:31 +00:00
|
|
|
* ```ts ignore
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { copy } from "@std/fs/copy";
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* await copy("./foo", "./bar", { preserveTimestamps: true });
|
2022-11-25 11:40:23 +00:00
|
|
|
* ```
|
|
|
|
*
|
2024-03-27 06:28:06 +00:00
|
|
|
* This will copy the file or directory at `./foo` to `./bar` and set the
|
|
|
|
* last modification and access times to the ones of the original source files.
|
2019-05-16 16:19:17 +00:00
|
|
|
*/
|
|
|
|
export async function copy(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-07-14 19:24:17 +00:00
|
|
|
options: CopyOptions = {},
|
2021-04-05 11:49:05 +00:00
|
|
|
) {
|
2023-08-14 07:08:42 +00:00
|
|
|
src = resolve(toPathString(src));
|
|
|
|
dest = resolve(toPathString(dest));
|
2019-05-16 16:19:17 +00:00
|
|
|
|
|
|
|
if (src === dest) {
|
2024-08-26 04:31:34 +00:00
|
|
|
throw new Error("Source and destination cannot be the same");
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const srcStat = await Deno.lstat(src);
|
|
|
|
|
2020-04-16 05:40:30 +00:00
|
|
|
if (srcStat.isDirectory && isSubdir(src, dest)) {
|
2019-05-16 16:19:17 +00:00
|
|
|
throw new Error(
|
2024-08-26 04:31:34 +00:00
|
|
|
`Cannot copy '${src}' to a subdirectory of itself: '${dest}'`,
|
2019-05-16 16:19:17 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-29 20:00:31 +00:00
|
|
|
if (srcStat.isSymlink) {
|
|
|
|
await copySymLink(src, dest, options);
|
|
|
|
} else if (srcStat.isDirectory) {
|
2019-05-16 16:19:17 +00:00
|
|
|
await copyDir(src, dest, options);
|
2020-04-16 05:40:30 +00:00
|
|
|
} else if (srcStat.isFile) {
|
2019-05-16 16:19:17 +00:00
|
|
|
await copyFile(src, dest, options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-06-07 03:54:50 +00:00
|
|
|
* Synchronously copy a file or directory (along with its contents), like
|
|
|
|
* {@linkcode https://www.ibm.com/docs/en/aix/7.3?topic=c-cp-command#cp__cp_flagr | cp -r}.
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
2024-06-07 03:54:50 +00:00
|
|
|
* Both `src` and `dest` must both be a file or directory.
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
2024-06-07 03:54:50 +00:00
|
|
|
* Requires `--allow-read` and `--allow-write` permissions.
|
|
|
|
*
|
|
|
|
* @see {@link https://docs.deno.com/runtime/manual/basics/permissions#file-system-access}
|
|
|
|
* for more information on Deno's permissions system.
|
2022-11-25 11:40:23 +00:00
|
|
|
*
|
2024-03-27 06:28:06 +00:00
|
|
|
* @param src The source file/directory path as a string or URL.
|
|
|
|
* @param dest The destination file/directory path as a string or URL.
|
|
|
|
* @param options Options for copying.
|
2024-06-07 03:54:50 +00:00
|
|
|
*
|
2024-03-27 06:28:06 +00:00
|
|
|
* @returns A void value that returns once the copy operation completes.
|
|
|
|
*
|
|
|
|
* @example Basic usage
|
2024-09-19 23:29:31 +00:00
|
|
|
* ```ts ignore
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { copySync } from "@std/fs/copy";
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* copySync("./foo", "./bar");
|
2022-11-25 11:40:23 +00:00
|
|
|
* ```
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* This will copy the file or directory at `./foo` to `./bar` without
|
|
|
|
* overwriting.
|
|
|
|
*
|
|
|
|
* @example Overwriting files/directories
|
2024-09-19 23:29:31 +00:00
|
|
|
* ```ts ignore
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { copySync } from "@std/fs/copy";
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* copySync("./foo", "./bar", { overwrite: true });
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This will copy the file or directory at `./foo` to `./bar` and overwrite
|
|
|
|
* any existing files or directories.
|
|
|
|
*
|
|
|
|
* @example Preserving timestamps
|
2024-09-19 23:29:31 +00:00
|
|
|
* ```ts ignore
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { copySync } from "@std/fs/copy";
|
2024-03-27 06:28:06 +00:00
|
|
|
*
|
|
|
|
* copySync("./foo", "./bar", { preserveTimestamps: true });
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This will copy the file or directory at `./foo` to `./bar` and set the
|
|
|
|
* last modification and access times to the ones of the original source files.
|
2019-05-16 16:19:17 +00:00
|
|
|
*/
|
|
|
|
export function copySync(
|
2022-08-30 03:58:48 +00:00
|
|
|
src: string | URL,
|
|
|
|
dest: string | URL,
|
2020-07-14 19:24:17 +00:00
|
|
|
options: CopyOptions = {},
|
2022-08-24 01:21:57 +00:00
|
|
|
) {
|
2023-08-14 07:08:42 +00:00
|
|
|
src = resolve(toPathString(src));
|
|
|
|
dest = resolve(toPathString(dest));
|
2019-05-16 16:19:17 +00:00
|
|
|
|
|
|
|
if (src === dest) {
|
2024-08-26 04:31:34 +00:00
|
|
|
throw new Error("Source and destination cannot be the same");
|
2019-05-16 16:19:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const srcStat = Deno.lstatSync(src);
|
|
|
|
|
2020-04-16 05:40:30 +00:00
|
|
|
if (srcStat.isDirectory && isSubdir(src, dest)) {
|
2019-05-16 16:19:17 +00:00
|
|
|
throw new Error(
|
2024-08-26 04:31:34 +00:00
|
|
|
`Cannot copy '${src}' to a subdirectory of itself: '${dest}'`,
|
2019-05-16 16:19:17 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-29 20:00:31 +00:00
|
|
|
if (srcStat.isSymlink) {
|
|
|
|
copySymlinkSync(src, dest, options);
|
|
|
|
} else if (srcStat.isDirectory) {
|
2019-05-16 16:19:17 +00:00
|
|
|
copyDirSync(src, dest, options);
|
2020-04-16 05:40:30 +00:00
|
|
|
} else if (srcStat.isFile) {
|
2019-05-16 16:19:17 +00:00
|
|
|
copyFileSync(src, dest, options);
|
|
|
|
}
|
|
|
|
}
|