mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
BREAKING(fs): throw Deno.errors.NotFound
instead of WalkError
in walk[Sync]()
(#5477)
This commit is contained in:
parent
e689f43eee
commit
0dc7ce1a1c
128
fs/walk.ts
128
fs/walk.ts
@ -3,7 +3,6 @@
|
|||||||
// https://golang.org/pkg/path/filepath/#Walk
|
// https://golang.org/pkg/path/filepath/#Walk
|
||||||
// Copyright 2009 The Go Authors. All rights reserved. BSD license.
|
// Copyright 2009 The Go Authors. All rights reserved. BSD license.
|
||||||
import { join } from "@std/path/join";
|
import { join } from "@std/path/join";
|
||||||
import { normalize } from "@std/path/normalize";
|
|
||||||
import { toPathString } from "./_to_path_string.ts";
|
import { toPathString } from "./_to_path_string.ts";
|
||||||
import {
|
import {
|
||||||
createWalkEntry,
|
createWalkEntry,
|
||||||
@ -11,56 +10,6 @@ import {
|
|||||||
type WalkEntry,
|
type WalkEntry,
|
||||||
} from "./_create_walk_entry.ts";
|
} from "./_create_walk_entry.ts";
|
||||||
|
|
||||||
/**
|
|
||||||
* Error thrown in {@linkcode walk} or {@linkcode walkSync} during iteration.
|
|
||||||
*
|
|
||||||
* @example Usage
|
|
||||||
* ```ts no-eval
|
|
||||||
* import { walk, WalkError } from "@std/fs/walk";
|
|
||||||
*
|
|
||||||
* try {
|
|
||||||
* for await (const entry of walk("./non_existent_root")) {
|
|
||||||
* console.log(entry.path);
|
|
||||||
* }
|
|
||||||
* } catch (error) {
|
|
||||||
* if (error instanceof WalkError) {
|
|
||||||
* console.error(error.message);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export class WalkError extends Error {
|
|
||||||
/**
|
|
||||||
* File path of the root that's being walked.
|
|
||||||
*
|
|
||||||
* @example Usage
|
|
||||||
* ```ts
|
|
||||||
* import { WalkError } from "@std/fs/walk";
|
|
||||||
* import { assertEquals } from "@std/assert";
|
|
||||||
*
|
|
||||||
* const error = new WalkError("error message", "./foo");
|
|
||||||
*
|
|
||||||
* assertEquals(error.root, "./foo");
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
root: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance.
|
|
||||||
*
|
|
||||||
* @param cause The cause of the error.
|
|
||||||
* @param root The root directory that's being walked.
|
|
||||||
*/
|
|
||||||
constructor(cause: unknown, root: string) {
|
|
||||||
super(
|
|
||||||
`${cause instanceof Error ? cause.message : cause} for path "${root}"`,
|
|
||||||
);
|
|
||||||
this.cause = cause;
|
|
||||||
this.name = this.constructor.name;
|
|
||||||
this.root = root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function include(
|
function include(
|
||||||
path: string,
|
path: string,
|
||||||
exts?: string[],
|
exts?: string[],
|
||||||
@ -79,11 +28,6 @@ function include(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapErrorWithPath(err: unknown, root: string) {
|
|
||||||
if (err instanceof WalkError) return err;
|
|
||||||
return new WalkError(err, root);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Options for {@linkcode walk} and {@linkcode walkSync}. */
|
/** Options for {@linkcode walk} and {@linkcode walkSync}. */
|
||||||
export interface WalkOptions {
|
export interface WalkOptions {
|
||||||
/**
|
/**
|
||||||
@ -163,6 +107,7 @@ export type { WalkEntry };
|
|||||||
*
|
*
|
||||||
* @param root The root directory to start the walk from, as a string or URL.
|
* @param root The root directory to start the walk from, as a string or URL.
|
||||||
* @param options The options for the walk.
|
* @param options The options for the walk.
|
||||||
|
* @throws {Deno.errors.NotFound} If the root directory does not exist.
|
||||||
*
|
*
|
||||||
* @returns An async iterable iterator that yields the walk entry objects.
|
* @returns An async iterable iterator that yields the walk entry objects.
|
||||||
*
|
*
|
||||||
@ -532,46 +477,42 @@ export async function* walk(
|
|||||||
if (maxDepth < 1 || !include(root, undefined, undefined, skip)) {
|
if (maxDepth < 1 || !include(root, undefined, undefined, skip)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
for await (const entry of Deno.readDir(root)) {
|
||||||
for await (const entry of Deno.readDir(root)) {
|
let path = join(root, entry.name);
|
||||||
let path = join(root, entry.name);
|
|
||||||
|
|
||||||
let { isSymlink, isDirectory } = entry;
|
let { isSymlink, isDirectory } = entry;
|
||||||
|
|
||||||
if (isSymlink) {
|
if (isSymlink) {
|
||||||
if (!followSymlinks) {
|
if (!followSymlinks) {
|
||||||
if (includeSymlinks && include(path, exts, match, skip)) {
|
if (includeSymlinks && include(path, exts, match, skip)) {
|
||||||
yield { path, ...entry };
|
yield { path, ...entry };
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const realPath = await Deno.realPath(path);
|
continue;
|
||||||
if (canonicalize) {
|
|
||||||
path = realPath;
|
|
||||||
}
|
|
||||||
// Caveat emptor: don't assume |path| is not a symlink. realpath()
|
|
||||||
// resolves symlinks but another process can replace the file system
|
|
||||||
// entity with a different type of entity before we call lstat().
|
|
||||||
({ isSymlink, isDirectory } = await Deno.lstat(realPath));
|
|
||||||
}
|
}
|
||||||
|
const realPath = await Deno.realPath(path);
|
||||||
if (isSymlink || isDirectory) {
|
if (canonicalize) {
|
||||||
yield* walk(path, {
|
path = realPath;
|
||||||
maxDepth: maxDepth - 1,
|
|
||||||
includeFiles,
|
|
||||||
includeDirs,
|
|
||||||
includeSymlinks,
|
|
||||||
followSymlinks,
|
|
||||||
exts,
|
|
||||||
match,
|
|
||||||
skip,
|
|
||||||
});
|
|
||||||
} else if (includeFiles && include(path, exts, match, skip)) {
|
|
||||||
yield { path, ...entry };
|
|
||||||
}
|
}
|
||||||
|
// Caveat emptor: don't assume |path| is not a symlink. realpath()
|
||||||
|
// resolves symlinks but another process can replace the file system
|
||||||
|
// entity with a different type of entity before we call lstat().
|
||||||
|
({ isSymlink, isDirectory } = await Deno.lstat(realPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSymlink || isDirectory) {
|
||||||
|
yield* walk(path, {
|
||||||
|
maxDepth: maxDepth - 1,
|
||||||
|
includeFiles,
|
||||||
|
includeDirs,
|
||||||
|
includeSymlinks,
|
||||||
|
followSymlinks,
|
||||||
|
exts,
|
||||||
|
match,
|
||||||
|
skip,
|
||||||
|
});
|
||||||
|
} else if (includeFiles && include(path, exts, match, skip)) {
|
||||||
|
yield { path, ...entry };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
throw wrapErrorWithPath(err, normalize(root));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -958,12 +899,7 @@ export function* walkSync(
|
|||||||
if (maxDepth < 1 || !include(root, undefined, undefined, skip)) {
|
if (maxDepth < 1 || !include(root, undefined, undefined, skip)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let entries;
|
const entries = Deno.readDirSync(root);
|
||||||
try {
|
|
||||||
entries = Deno.readDirSync(root);
|
|
||||||
} catch (err) {
|
|
||||||
throw wrapErrorWithPath(err, normalize(root));
|
|
||||||
}
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
let path = join(root, entry.name);
|
let path = join(root, entry.name);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
import { walk, WalkError, type WalkOptions, walkSync } from "./walk.ts";
|
import { walk, type WalkOptions, walkSync } from "./walk.ts";
|
||||||
import {
|
import {
|
||||||
assertArrayIncludes,
|
assertArrayIncludes,
|
||||||
assertEquals,
|
assertEquals,
|
||||||
@ -234,16 +234,19 @@ Deno.test({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("walk() rejects with WalkError when root is removed during execution", async () => {
|
Deno.test("walk() rejects with `Deno.errors.NotFound` when root is removed during execution", async () => {
|
||||||
const root = resolve(testdataDir, "error");
|
const root = resolve(testdataDir, "error");
|
||||||
await Deno.mkdir(root);
|
await Deno.mkdir(root);
|
||||||
try {
|
try {
|
||||||
await assertRejects(async () => {
|
await assertRejects(
|
||||||
await Array.fromAsync(
|
async () => {
|
||||||
walk(root),
|
await Array.fromAsync(
|
||||||
async () => await Deno.remove(root, { recursive: true }),
|
walk(root),
|
||||||
);
|
async () => await Deno.remove(root, { recursive: true }),
|
||||||
}, WalkError);
|
);
|
||||||
|
},
|
||||||
|
Deno.errors.NotFound,
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await Deno.remove(root, { recursive: true });
|
await Deno.remove(root, { recursive: true });
|
||||||
throw err;
|
throw err;
|
||||||
|
Loading…
Reference in New Issue
Block a user