Skip to content

Commit

Permalink
fix(fs/expand_glob): handle broken symlinks
Browse files Browse the repository at this point in the history
- add `includeSymlinks` flag
  • Loading branch information
joehillen committed Jan 5, 2024
1 parent 6e18e67 commit 9b5d76e
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 6 deletions.
49 changes: 45 additions & 4 deletions fs/expand_glob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ export interface ExpandGlobOptions extends Omit<GlobOptions, "os"> {
* @default {true}
*/
includeDirs?: boolean;
/**
* Indicates whether symlink entries should be included or not.
*
* This will include any broken symlinks, when `followSymlinks` is `true`.
* @default {true}
*/
includeSymlinks?: boolean;
/**
* Whether to follow symbolic links.
*
Expand Down Expand Up @@ -101,6 +108,7 @@ export async function* expandGlob(
root,
exclude = [],
includeDirs = true,
includeSymlinks = true,
extended = true,
globstar = true,
caseInsensitive,
Expand Down Expand Up @@ -145,9 +153,23 @@ export async function* expandGlob(
walkInfo: WalkEntry,
globSegment: string,
): AsyncIterableIterator<WalkEntry> {
if (!walkInfo.isDirectory) {
let isDir = walkInfo.isDirectory;
if (walkInfo.isSymlink) {
if (!followSymlinks) {
return;
}
try {
isDir = await Deno.stat(walkInfo.path).then((stat) => stat.isDirectory);
} catch (error) {
throwUnlessNotFound(error);
}
}

if (!isDir) {
return;
} else if (globSegment === "..") {
}

if (globSegment === "..") {
const parentPath = joinGlobs([walkInfo.path, ".."], globOptions);
try {
if (shouldInclude(parentPath)) {
Expand All @@ -161,6 +183,7 @@ export async function* expandGlob(
return yield* walk(walkInfo.path, {
skip: excludePatterns,
maxDepth: globstar ? Infinity : 1,
includeSymlinks,
followSymlinks,
canonicalize,
});
Expand All @@ -170,6 +193,7 @@ export async function* expandGlob(
const walkEntry of walk(walkInfo.path, {
maxDepth: 1,
skip: excludePatterns,
includeSymlinks,
followSymlinks,
})
) {
Expand Down Expand Up @@ -227,6 +251,7 @@ export function* expandGlobSync(
root,
exclude = [],
includeDirs = true,
includeSymlinks = true,
extended = true,
globstar = true,
caseInsensitive,
Expand Down Expand Up @@ -271,9 +296,23 @@ export function* expandGlobSync(
walkInfo: WalkEntry,
globSegment: string,
): IterableIterator<WalkEntry> {
if (!walkInfo.isDirectory) {
let isDir = walkInfo.isDirectory;
if (walkInfo.isSymlink) {
if (!followSymlinks) {
return;
}
try {
isDir = Deno.statSync(walkInfo.path).isDirectory;
} catch (error) {
throwUnlessNotFound(error);
}
}

if (!isDir) {
return;
} else if (globSegment === "..") {
}

if (globSegment === "..") {
const parentPath = joinGlobs([walkInfo.path, ".."], globOptions);
try {
if (shouldInclude(parentPath)) {
Expand All @@ -287,6 +326,7 @@ export function* expandGlobSync(
return yield* walkSync(walkInfo.path, {
skip: excludePatterns,
maxDepth: globstar ? Infinity : 1,
includeSymlinks,
followSymlinks,
canonicalize,
});
Expand All @@ -296,6 +336,7 @@ export function* expandGlobSync(
const walkEntry of walkSync(walkInfo.path, {
maxDepth: 1,
skip: excludePatterns,
includeSymlinks,
followSymlinks,
})
) {
Expand Down
40 changes: 38 additions & 2 deletions fs/expand_glob_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Deno.test("expandGlob() with wildcard input returns all test data", async functi
"abc",
"abcdef",
"abcdefghi",
"broken-link",
"link",
"subdir",
]);
Expand All @@ -79,6 +80,7 @@ Deno.test("expandGlobSync() with wildcard input returns all test data", function
"abc",
"abcdef",
"abcdefghi",
"broken-link",
"link",
"subdir",
]);
Expand Down Expand Up @@ -107,6 +109,7 @@ Deno.test("expandGlob() with subdir/../* input expands parent", async function (
"abc",
"abcdef",
"abcdefghi",
"broken-link",
"link",
"subdir",
]);
Expand All @@ -119,6 +122,7 @@ Deno.test("expandGlobSync() with subdir/../* input expands parent", function ()
"abc",
"abcdef",
"abcdefghi",
"broken-link",
"link",
"subdir",
]);
Expand Down Expand Up @@ -204,6 +208,7 @@ Deno.test("expandGlob() with globstar parent and globstar option set to false re
"abc",
"abcdef",
"abcdefghi",
"broken-link",
"link",
"subdir",
]);
Expand All @@ -217,6 +222,7 @@ Deno.test("expandGlobSync() with globstar parent and globstar option set to fals
"abc",
"abcdef",
"abcdefghi",
"broken-link",
"link",
"subdir",
]);
Expand Down Expand Up @@ -261,7 +267,7 @@ Deno.test("expandGlob() accepts followSymlinks option set to true", async functi
root: join(EG_OPTIONS.root!, "link"),
followSymlinks: true,
};
assertEquals(await expandGlobArray("*", options), ["abc"]);
assertEquals(await expandGlobArray("*", options), ["abc", "broken-link"]);
});

Deno.test("expandGlobSync() accepts followSymlinks option set to true", function () {
Expand All @@ -270,7 +276,7 @@ Deno.test("expandGlobSync() accepts followSymlinks option set to true", function
root: join(EG_OPTIONS.root!, "link"),
followSymlinks: true,
};
assertEquals(expandGlobSyncArray("*", options), ["abc"]);
assertEquals(expandGlobSyncArray("*", options), ["abc", "broken-link"]);
});

Deno.test("expandGlob() accepts followSymlinks option set to true with canonicalize", async function () {
Expand Down Expand Up @@ -323,6 +329,36 @@ Deno.test("expandGlobSync() accepts followSymlinks option set to true without ca
);
});

Deno.test("expandGlob() ignores broken symlinks when includeSymlinks is false", async function () {
const options = {
...EG_OPTIONS,
includeSymlinks: false,
followSymlinks: true,
};
assertEquals(await expandGlobArray("*", options), [
"a[b]c",
"abc",
"abcdef",
"abcdefghi",
"subdir",
]);
});

Deno.test("expandGlobSync() ignores broken symlinks when includeSymlinks is false", function () {
const options = {
...EG_OPTIONS,
includeSymlinks: false,
followSymlinks: true,
};
assertEquals(expandGlobSyncArray("*", options), [
"a[b]c",
"abc",
"abcdef",
"abcdefghi",
"subdir",
]);
});

Deno.test(
"expandGlob() does not require read permissions when root path is specified",
{
Expand Down
1 change: 1 addition & 0 deletions fs/testdata/glob/broken-link
1 change: 1 addition & 0 deletions fs/testdata/glob/subdir/broken-link

0 comments on commit 9b5d76e

Please sign in to comment.