Skip to content

Commit

Permalink
fix(fs/walk): no root path in error message
Browse files Browse the repository at this point in the history
This adds the root path to error message.
The `root` property is set to properly handle errors in case of
recursion.

Fix #863
  • Loading branch information
Nautigsam committed Apr 29, 2021
1 parent 2509338 commit 9740193
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 24 deletions.
63 changes: 40 additions & 23 deletions fs/walk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ function include(
return true;
}

function wrapErrorWithRootPath(err: Error & { root: string }, root: string) {
if (err.root) return err;
err.root = root;
err.message = `${err.message} for path "${root}"`;
return err;
}

export interface WalkEntry extends Deno.DirEntry {
path: string;
}
Expand Down Expand Up @@ -105,33 +112,37 @@ export async function* walk(
if (maxDepth < 1 || !include(root, undefined, undefined, skip)) {
return;
}
for await (const entry of Deno.readDir(root)) {
assert(entry.name != null);
let path = join(root, entry.name);
try {
for await (const entry of Deno.readDir(root)) {
assert(entry.name != null);
let path = join(root, entry.name);

if (entry.isSymlink) {
if (followSymlinks) {
path = await Deno.realPath(path);
} else {
continue;
if (entry.isSymlink) {
if (followSymlinks) {
path = await Deno.realPath(path);
} else {
continue;
}
}
}

if (entry.isFile) {
if (includeFiles && include(path, exts, match, skip)) {
yield { path, ...entry };
if (entry.isFile) {
if (includeFiles && include(path, exts, match, skip)) {
yield { path, ...entry };
}
} else {
yield* walk(path, {
maxDepth: maxDepth - 1,
includeFiles,
includeDirs,
followSymlinks,
exts,
match,
skip,
});
}
} else {
yield* walk(path, {
maxDepth: maxDepth - 1,
includeFiles,
includeDirs,
followSymlinks,
exts,
match,
skip,
});
}
} catch (err) {
throw wrapErrorWithRootPath(err, normalize(root));
}
}

Expand All @@ -157,7 +168,13 @@ export function* walkSync(
if (maxDepth < 1 || !include(root, undefined, undefined, skip)) {
return;
}
for (const entry of Deno.readDirSync(root)) {
let entries;
try {
entries = Deno.readDirSync(root);
} catch (err) {
throw wrapErrorWithRootPath(err, normalize(root));
}
for (const entry of entries) {
assert(entry.name != null);
let path = join(root, entry.name);

Expand Down
47 changes: 46 additions & 1 deletion fs/walk_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
import { walk, WalkEntry, WalkOptions, walkSync } from "./walk.ts";
import { assert, assertEquals, assertThrowsAsync } from "../testing/asserts.ts";
import {
assert,
assertEquals,
assertThrows,
assertThrowsAsync,
} from "../testing/asserts.ts";

export function testWalk(
setup: (arg0: string) => void | Promise<void>,
Expand Down Expand Up @@ -260,3 +265,43 @@ testWalk(
assert(arr.some((f): boolean => f.endsWith("/b/z")));
},
);

testWalk(
async (d: string) => {
await Deno.mkdir(d + "/a/b", { recursive: true });
await Deno.chmod(d + "/a/b", 0o000);
},
async function subDirNoPermissionAsync() {
try {
await assertThrowsAsync(
async () => {
await walkArray("a");
},
Deno.errors.PermissionDenied,
'for path "a/b"',
);
} finally {
await Deno.chmod("a/b", 0o755);
}
},
);

testWalk(
async (d: string) => {
await Deno.mkdir(d + "/a/b", { recursive: true });
await Deno.chmod(d + "/a/b", 0o000);
},
async function subDirNoPermissionSync() {
try {
assertThrows(
() => {
return [...walkSync("a")];
},
Deno.errors.PermissionDenied,
'for path "a/b"',
);
} finally {
await Deno.chmod("a/b", 0o755);
}
},
);

0 comments on commit 9740193

Please sign in to comment.