diff options
Diffstat (limited to 'std/fs')
-rw-r--r-- | std/fs/README.md | 4 | ||||
-rw-r--r-- | std/fs/copy.ts | 38 | ||||
-rw-r--r-- | std/fs/expand_glob.ts | 82 | ||||
-rw-r--r-- | std/fs/expand_glob_test.ts | 6 | ||||
-rw-r--r-- | std/fs/walk.ts | 80 | ||||
-rw-r--r-- | std/fs/walk_test.ts | 4 |
6 files changed, 121 insertions, 93 deletions
diff --git a/std/fs/README.md b/std/fs/README.md index 289069694..8d1be54bf 100644 --- a/std/fs/README.md +++ b/std/fs/README.md @@ -156,8 +156,8 @@ for (const fileInfo of walkSync(".")) { // Async async function printFilesNames() { - for await (const fileInfo of walk()) { - console.log(fileInfo.filename); + for await (const entry of walk()) { + console.log(entry.path); } } diff --git a/std/fs/copy.ts b/std/fs/copy.ts index 27b3c2a3c..d442e46ae 100644 --- a/std/fs/copy.ts +++ b/std/fs/copy.ts @@ -157,15 +157,15 @@ async function copyDir( await Deno.utime(dest, srcStatInfo.atime, srcStatInfo.mtime); } - for await (const file of Deno.readdir(src)) { - const srcPath = path.join(src, file.name); + for await (const entry of Deno.readdir(src)) { + const srcPath = path.join(src, entry.name); const destPath = path.join(dest, path.basename(srcPath as string)); - if (file.isDirectory) { + if (entry.isSymlink) { + await copySymLink(srcPath, destPath, options); + } else if (entry.isDirectory) { await copyDir(srcPath, destPath, options); - } else if (file.isFile) { + } else if (entry.isFile) { await copyFile(srcPath, destPath, options); - } else if (file.isSymlink) { - await copySymLink(srcPath, destPath, options); } } } @@ -185,16 +185,16 @@ function copyDirSync(src: string, dest: string, options: CopyOptions): void { Deno.utimeSync(dest, srcStatInfo.atime, srcStatInfo.mtime); } - for (const file of Deno.readdirSync(src)) { - assert(file.name != null, "file.name must be set"); - const srcPath = path.join(src, file.name); + for (const entry of Deno.readdirSync(src)) { + assert(entry.name != null, "file.name must be set"); + const srcPath = path.join(src, entry.name); const destPath = path.join(dest, path.basename(srcPath as string)); - if (file.isDirectory) { + if (entry.isSymlink) { + copySymlinkSync(srcPath, destPath, options); + } else if (entry.isDirectory) { copyDirSync(srcPath, destPath, options); - } else if (file.isFile) { + } else if (entry.isFile) { copyFileSync(srcPath, destPath, options); - } else if (file.isSymlink) { - copySymlinkSync(srcPath, destPath, options); } } } @@ -229,12 +229,12 @@ export async function copy( ); } - if (srcStat.isDirectory) { + if (srcStat.isSymlink) { + await copySymLink(src, dest, options); + } else if (srcStat.isDirectory) { await copyDir(src, dest, options); } else if (srcStat.isFile) { await copyFile(src, dest, options); - } else if (srcStat.isSymlink) { - await copySymLink(src, dest, options); } } @@ -268,11 +268,11 @@ export function copySync( ); } - if (srcStat.isDirectory) { + if (srcStat.isSymlink) { + copySymlinkSync(src, dest, options); + } else if (srcStat.isDirectory) { copyDirSync(src, dest, options); } else if (srcStat.isFile) { copyFileSync(src, dest, options); - } else if (srcStat.isSymlink) { - copySymlinkSync(src, dest, options); } } diff --git a/std/fs/expand_glob.ts b/std/fs/expand_glob.ts index 386f61ad5..803c67cdf 100644 --- a/std/fs/expand_glob.ts +++ b/std/fs/expand_glob.ts @@ -8,9 +8,15 @@ import { joinGlobs, normalize, } from "../path/mod.ts"; -import { WalkEntry, walk, walkSync } from "./walk.ts"; +import { + WalkEntry, + createWalkEntry, + createWalkEntrySync, + walk, + walkSync, +} from "./walk.ts"; import { assert } from "../testing/asserts.ts"; -const { cwd, stat, statSync } = Deno; +const { cwd } = Deno; type FileInfo = Deno.FileInfo; export interface ExpandGlobOptions extends GlobOptions { @@ -48,6 +54,12 @@ function throwUnlessNotFound(error: Error): void { } } +function comparePath(a: WalkEntry, b: WalkEntry): number { + if (a.path < b.path) return -1; + if (a.path > b.path) return 1; + return 0; +} + /** * Expand the glob string from the specified `root` directory and yield each * result as a `WalkEntry` object. @@ -73,8 +85,8 @@ export async function* expandGlob( const excludePatterns = exclude .map(resolveFromRoot) .map((s: string): RegExp => globToRegExp(s, globOptions)); - const shouldInclude = (filename: string): boolean => - !excludePatterns.some((p: RegExp): boolean => !!filename.match(p)); + const shouldInclude = (path: string): boolean => + !excludePatterns.some((p: RegExp): boolean => !!path.match(p)); const { segments, hasTrailingSep, winRoot } = split(resolveFromRoot(glob)); let fixedRoot = winRoot != undefined ? winRoot : "/"; @@ -86,7 +98,7 @@ export async function* expandGlob( let fixedRootInfo: WalkEntry; try { - fixedRootInfo = { filename: fixedRoot, info: await stat(fixedRoot) }; + fixedRootInfo = await createWalkEntry(fixedRoot); } catch (error) { return throwUnlessNotFound(error); } @@ -95,29 +107,29 @@ export async function* expandGlob( walkInfo: WalkEntry, globSegment: string ): AsyncIterableIterator<WalkEntry> { - if (!walkInfo.info.isDirectory) { + if (!walkInfo.isDirectory) { return; } else if (globSegment == "..") { - const parentPath = joinGlobs([walkInfo.filename, ".."], globOptions); + const parentPath = joinGlobs([walkInfo.path, ".."], globOptions); try { if (shouldInclude(parentPath)) { - return yield { filename: parentPath, info: await stat(parentPath) }; + return yield await createWalkEntry(parentPath); } } catch (error) { throwUnlessNotFound(error); } return; } else if (globSegment == "**") { - return yield* walk(walkInfo.filename, { + return yield* walk(walkInfo.path, { includeFiles: false, skip: excludePatterns, }); } - yield* walk(walkInfo.filename, { + yield* walk(walkInfo.path, { maxDepth: 1, match: [ globToRegExp( - joinGlobs([walkInfo.filename, globSegment], globOptions), + joinGlobs([walkInfo.path, globSegment], globOptions), globOptions ), ], @@ -129,27 +141,22 @@ export async function* expandGlob( for (const segment of segments) { // Advancing the list of current matches may introduce duplicates, so we // pass everything through this Map. - const nextMatchMap: Map<string, FileInfo> = new Map(); + const nextMatchMap: Map<string, WalkEntry> = new Map(); for (const currentMatch of currentMatches) { for await (const nextMatch of advanceMatch(currentMatch, segment)) { - nextMatchMap.set(nextMatch.filename, nextMatch.info); + nextMatchMap.set(nextMatch.path, nextMatch); } } - currentMatches = [...nextMatchMap].sort().map( - ([filename, info]): WalkEntry => ({ - filename, - info, - }) - ); + currentMatches = [...nextMatchMap.values()].sort(comparePath); } if (hasTrailingSep) { currentMatches = currentMatches.filter( - ({ info }): boolean => info.isDirectory + (entry: WalkEntry): boolean => entry.isDirectory ); } if (!includeDirs) { currentMatches = currentMatches.filter( - ({ info }): boolean => !info.isDirectory + (entry: WalkEntry): boolean => !entry.isDirectory ); } yield* currentMatches; @@ -177,8 +184,8 @@ export function* expandGlobSync( const excludePatterns = exclude .map(resolveFromRoot) .map((s: string): RegExp => globToRegExp(s, globOptions)); - const shouldInclude = (filename: string): boolean => - !excludePatterns.some((p: RegExp): boolean => !!filename.match(p)); + const shouldInclude = (path: string): boolean => + !excludePatterns.some((p: RegExp): boolean => !!path.match(p)); const { segments, hasTrailingSep, winRoot } = split(resolveFromRoot(glob)); let fixedRoot = winRoot != undefined ? winRoot : "/"; @@ -190,7 +197,7 @@ export function* expandGlobSync( let fixedRootInfo: WalkEntry; try { - fixedRootInfo = { filename: fixedRoot, info: statSync(fixedRoot) }; + fixedRootInfo = createWalkEntrySync(fixedRoot); } catch (error) { return throwUnlessNotFound(error); } @@ -199,29 +206,29 @@ export function* expandGlobSync( walkInfo: WalkEntry, globSegment: string ): IterableIterator<WalkEntry> { - if (!walkInfo.info.isDirectory) { + if (!walkInfo.isDirectory) { return; } else if (globSegment == "..") { - const parentPath = joinGlobs([walkInfo.filename, ".."], globOptions); + const parentPath = joinGlobs([walkInfo.path, ".."], globOptions); try { if (shouldInclude(parentPath)) { - return yield { filename: parentPath, info: statSync(parentPath) }; + return yield createWalkEntrySync(parentPath); } } catch (error) { throwUnlessNotFound(error); } return; } else if (globSegment == "**") { - return yield* walkSync(walkInfo.filename, { + return yield* walkSync(walkInfo.path, { includeFiles: false, skip: excludePatterns, }); } - yield* walkSync(walkInfo.filename, { + yield* walkSync(walkInfo.path, { maxDepth: 1, match: [ globToRegExp( - joinGlobs([walkInfo.filename, globSegment], globOptions), + joinGlobs([walkInfo.path, globSegment], globOptions), globOptions ), ], @@ -233,27 +240,22 @@ export function* expandGlobSync( for (const segment of segments) { // Advancing the list of current matches may introduce duplicates, so we // pass everything through this Map. - const nextMatchMap: Map<string, FileInfo> = new Map(); + const nextMatchMap: Map<string, WalkEntry> = new Map(); for (const currentMatch of currentMatches) { for (const nextMatch of advanceMatch(currentMatch, segment)) { - nextMatchMap.set(nextMatch.filename, nextMatch.info); + nextMatchMap.set(nextMatch.path, nextMatch); } } - currentMatches = [...nextMatchMap].sort().map( - ([filename, info]): WalkEntry => ({ - filename, - info, - }) - ); + currentMatches = [...nextMatchMap.values()].sort(comparePath); } if (hasTrailingSep) { currentMatches = currentMatches.filter( - ({ info }): boolean => info.isDirectory + (entry: WalkEntry): boolean => entry.isDirectory ); } if (!includeDirs) { currentMatches = currentMatches.filter( - ({ info }): boolean => !info.isDirectory + (entry: WalkEntry): boolean => !entry.isDirectory ); } yield* currentMatches; diff --git a/std/fs/expand_glob_test.ts b/std/fs/expand_glob_test.ts index a2e6b4333..98abe0d73 100644 --- a/std/fs/expand_glob_test.ts +++ b/std/fs/expand_glob_test.ts @@ -19,12 +19,12 @@ async function expandGlobArray( options: ExpandGlobOptions ): Promise<string[]> { const paths: string[] = []; - for await (const { filename } of expandGlob(globString, options)) { - paths.push(filename); + for await (const { path } of expandGlob(globString, options)) { + paths.push(path); } paths.sort(); const pathsSync = [...expandGlobSync(globString, options)].map( - ({ filename }): string => filename + ({ path }): string => path ); pathsSync.sort(); assertEquals(paths, pathsSync); diff --git a/std/fs/walk.ts b/std/fs/walk.ts index e4cf4674f..a99d35a50 100644 --- a/std/fs/walk.ts +++ b/std/fs/walk.ts @@ -2,9 +2,35 @@ // https://golang.org/pkg/path/filepath/#Walk // Copyright 2009 The Go Authors. All rights reserved. BSD license. import { unimplemented, assert } from "../testing/asserts.ts"; -import { join } from "../path/mod.ts"; +import { basename, join, normalize } from "../path/mod.ts"; const { readdir, readdirSync, stat, statSync } = Deno; +export function createWalkEntrySync(path: string): WalkEntry { + path = normalize(path); + const name = basename(path); + const info = statSync(path); + return { + path, + name, + isFile: info.isFile, + isDirectory: info.isDirectory, + isSymlink: info.isSymlink, + }; +} + +export async function createWalkEntry(path: string): Promise<WalkEntry> { + path = normalize(path); + const name = basename(path); + const info = await stat(path); + return { + path, + name, + isFile: info.isFile, + isDirectory: info.isDirectory, + isSymlink: info.isSymlink, + }; +} + export interface WalkOptions { maxDepth?: number; includeFiles?: boolean; @@ -16,26 +42,25 @@ export interface WalkOptions { } function include( - filename: string, + path: string, exts?: string[], match?: RegExp[], skip?: RegExp[] ): boolean { - if (exts && !exts.some((ext): boolean => filename.endsWith(ext))) { + if (exts && !exts.some((ext): boolean => path.endsWith(ext))) { return false; } - if (match && !match.some((pattern): boolean => !!filename.match(pattern))) { + if (match && !match.some((pattern): boolean => !!path.match(pattern))) { return false; } - if (skip && skip.some((pattern): boolean => !!filename.match(pattern))) { + if (skip && skip.some((pattern): boolean => !!path.match(pattern))) { return false; } return true; } -export interface WalkEntry { - filename: string; - info: Deno.FileInfo; +export interface WalkEntry extends Deno.DirEntry { + path: string; } /** Walks the file tree rooted at root, yielding each file or directory in the @@ -52,8 +77,8 @@ export interface WalkEntry { * - match?: RegExp[]; * - skip?: RegExp[]; * - * for await (const { filename, info } of walk(".")) { - * console.log(filename); + * for await (const { name, info } of walk(".")) { + * console.log(name); * assert(info.isFile); * }; */ @@ -73,13 +98,13 @@ export async function* walk( return; } if (includeDirs && include(root, exts, match, skip)) { - yield { filename: root, info: await stat(root) }; + yield await createWalkEntry(root); } if (maxDepth < 1 || !include(root, undefined, undefined, skip)) { return; } - for await (const dirEntry of readdir(root)) { - if (dirEntry.isSymlink) { + for await (const entry of readdir(root)) { + if (entry.isSymlink) { if (followSymlinks) { // TODO(ry) Re-enable followSymlinks. unimplemented(); @@ -88,14 +113,15 @@ export async function* walk( } } - const filename = join(root, dirEntry.name); + assert(entry.name != null); + const path = join(root, entry.name); - if (dirEntry.isFile) { - if (includeFiles && include(filename, exts, match, skip)) { - yield { filename, info: dirEntry }; + if (entry.isFile) { + if (includeFiles && include(path, exts, match, skip)) { + yield { path, ...entry }; } } else { - yield* walk(filename, { + yield* walk(path, { maxDepth: maxDepth - 1, includeFiles, includeDirs, @@ -125,13 +151,13 @@ export function* walkSync( return; } if (includeDirs && include(root, exts, match, skip)) { - yield { filename: root, info: statSync(root) }; + yield createWalkEntrySync(root); } if (maxDepth < 1 || !include(root, undefined, undefined, skip)) { return; } - for (const dirEntry of readdirSync(root)) { - if (dirEntry.isSymlink) { + for (const entry of readdirSync(root)) { + if (entry.isSymlink) { if (followSymlinks) { unimplemented(); } else { @@ -139,15 +165,15 @@ export function* walkSync( } } - assert(dirEntry.name != null); - const filename = join(root, dirEntry.name); + assert(entry.name != null); + const path = join(root, entry.name); - if (dirEntry.isFile) { - if (includeFiles && include(filename, exts, match, skip)) { - yield { filename, info: dirEntry }; + if (entry.isFile) { + if (includeFiles && include(path, exts, match, skip)) { + yield { path, ...entry }; } } else { - yield* walkSync(filename, { + yield* walkSync(path, { maxDepth: maxDepth - 1, includeFiles, includeDirs, diff --git a/std/fs/walk_test.ts b/std/fs/walk_test.ts index ea9a33773..8bd4577b9 100644 --- a/std/fs/walk_test.ts +++ b/std/fs/walk_test.ts @@ -24,8 +24,8 @@ export function testWalk( Deno.test({ ignore, name: `[walk] ${name}`, fn }); } -function normalize({ filename }: WalkEntry): string { - return filename.replace(/\\/g, "/"); +function normalize({ path }: WalkEntry): string { + return path.replace(/\\/g, "/"); } export async function walkArray( |