0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

Implemented readDirSync, readDir

This commit is contained in:
J2P 2018-10-04 06:56:56 +09:00 committed by Ryan Dahl
parent 4c0517c339
commit ea87034e26
9 changed files with 294 additions and 93 deletions

View file

@ -75,6 +75,7 @@ ts_sources = [
"js/dom_types.ts",
"js/errors.ts",
"js/fetch.ts",
"js/fileinfo.ts",
"js/files.ts",
"js/io.ts",
"js/global-eval.ts",
@ -88,6 +89,7 @@ ts_sources = [
"js/platform.ts",
"js/plugins.d.ts",
"js/read_file.ts",
"js/read_dir.ts",
"js/remove.ts",
"js/rename.ts",
"js/read_link.ts",

View file

@ -9,9 +9,10 @@ export { makeTempDirSync, makeTempDir } from "./make_temp_dir";
export { removeSync, remove, removeAllSync, removeAll } from "./remove";
export { renameSync, rename } from "./rename";
export { readFileSync, readFile } from "./read_file";
export { readDirSync, readDir } from "./read_dir";
export { copyFileSync, copyFile } from "./copy_file";
export { readlinkSync, readlink } from "./read_link";
export { FileInfo, statSync, lstatSync, stat, lstat } from "./stat";
export { statSync, lstatSync, stat, lstat } from "./stat";
export { symlinkSync, symlink } from "./symlink";
export { writeFileSync, writeFile } from "./write_file";
export { ErrorKind, DenoError } from "./errors";
@ -19,4 +20,5 @@ export { libdeno } from "./libdeno";
export { platform } from "./platform";
export { trace } from "./trace";
export { truncateSync, truncate } from "./truncate";
export { FileInfo } from "./fileinfo";
export const args: string[] = [];

108
js/fileinfo.ts Normal file
View file

@ -0,0 +1,108 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as fbs from "gen/msg_generated";
/**
* A FileInfo describes a file and is returned by `stat`, `lstat`,
* `statSync`, `lstatSync`.
*/
export interface FileInfo {
readonly _isFile: boolean;
readonly _isSymlink: boolean;
/** The size of the file, in bytes. */
len: number;
/**
* The last modification time of the file. This corresponds to the `mtime`
* field from `stat` on Unix and `ftLastWriteTime` on Windows. This may not
* be available on all platforms.
*/
modified: number | null;
/**
* The last access time of the file. This corresponds to the `atime`
* field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not
* be available on all platforms.
*/
accessed: number | null;
/**
* The last access time of the file. This corresponds to the `birthtime`
* field from `stat` on Unix and `ftCreationTime` on Windows. This may not
* be available on all platforms.
*/
created: number | null;
/**
* The underlying raw st_mode bits that contain the standard Unix permissions
* for this file/directory. TODO Match behavior with Go on windows for mode.
*/
mode: number | null;
/**
* Returns the file or directory name.
*/
name: string | null;
/** Returns the file or directory path. */
path: string | null;
/**
* Returns whether this is info for a regular file. This result is mutually
* exclusive to `FileInfo.isDirectory` and `FileInfo.isSymlink`.
*/
isFile(): boolean;
/**
* Returns whether this is info for a regular directory. This result is
* mutually exclusive to `FileInfo.isFile` and `FileInfo.isSymlink`.
*/
isDirectory(): boolean;
/**
* Returns whether this is info for a symlink. This result is
* mutually exclusive to `FileInfo.isFile` and `FileInfo.isDirectory`.
*/
isSymlink(): boolean;
}
export class FileInfoImpl implements FileInfo {
readonly _isFile: boolean;
readonly _isSymlink: boolean;
len: number;
modified: number | null;
accessed: number | null;
created: number | null;
mode: number | null;
name: string | null;
path: string | null;
/* @internal */
constructor(private _msg: fbs.StatRes) {
const modified = this._msg.modified().toFloat64();
const accessed = this._msg.accessed().toFloat64();
const created = this._msg.created().toFloat64();
const hasMode = this._msg.hasMode();
const mode = this._msg.mode(); // negative for invalid mode (Windows)
const name = this._msg.name();
const path = this._msg.path();
this._isFile = this._msg.isFile();
this._isSymlink = this._msg.isSymlink();
this.len = this._msg.len().toFloat64();
this.modified = modified ? modified : null;
this.accessed = accessed ? accessed : null;
this.created = created ? created : null;
// null on Windows
this.mode = hasMode ? mode : null;
this.name = name ? name : null;
this.path = path ? path : null;
}
isFile() {
return this._isFile;
}
isDirectory() {
return !this._isFile && !this._isSymlink;
}
isSymlink() {
return this._isSymlink;
}
}

49
js/read_dir.ts Normal file
View file

@ -0,0 +1,49 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as fbs from "gen/msg_generated";
import { flatbuffers } from "flatbuffers";
import * as dispatch from "./dispatch";
import { FileInfo, FileInfoImpl } from "./fileinfo";
import { assert } from "./util";
/**
* Reads the directory given by path and returns
* a list of file info synchronously.
*
* import { readDirSync } from "deno";
* const files = readDirSync("/");
*/
export function readDirSync(path: string): FileInfo[] {
return res(dispatch.sendSync(...req(path)));
}
/**
* Reads the directory given by path and returns a list of file info.
*
* import { readDir } from "deno";
* const files = await readDir("/");
*
*/
export async function readDir(path: string): Promise<FileInfo[]> {
return res(await dispatch.sendAsync(...req(path)));
}
function req(path: string): [flatbuffers.Builder, fbs.Any, flatbuffers.Offset] {
const builder = new flatbuffers.Builder();
const path_ = builder.createString(path);
fbs.ReadDir.startReadDir(builder);
fbs.ReadDir.addPath(builder, path_);
const msg = fbs.ReadDir.endReadDir(builder);
return [builder, fbs.Any.ReadDir, msg];
}
function res(baseRes: null | fbs.Base): FileInfo[] {
assert(baseRes != null);
assert(fbs.Any.ReadDirRes === baseRes!.msgType());
const res = new fbs.ReadDirRes();
assert(baseRes!.msg(res) != null);
const fileInfos: FileInfo[] = [];
for (let i = 0; i < res.entriesLength(); i++) {
fileInfos.push(new FileInfoImpl(res.entries(i)!));
}
return fileInfos;
}

60
js/read_dir_test.ts Normal file
View file

@ -0,0 +1,60 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import { test, testPerm, assert, assertEqual } from "./test_util.ts";
import * as deno from "deno";
import { FileInfo } from "deno";
function assertSameContent(files: FileInfo[]) {
let counter = 0;
for (const file of files) {
if (file.name == "subdir") {
assert(file.isDirectory());
counter++;
}
if (file.name === "002_hello.ts") {
assertEqual(file.path, `tests/${file.name}`);
counter++;
}
}
assertEqual(counter, 2);
}
testPerm({ write: true }, function readDirSyncSuccess() {
const files = deno.readDirSync("tests/");
assertSameContent(files);
});
test(function readDirSyncNotDir() {
let caughtError = false;
let src;
try {
src = deno.readDirSync("package.json");
} catch (err) {
caughtError = true;
assertEqual(err.kind, deno.ErrorKind.Other);
}
assert(caughtError);
assertEqual(src, undefined);
});
test(function readDirSyncNotFound() {
let caughtError = false;
let src;
try {
src = deno.readDirSync("bad_dir_name");
} catch (err) {
caughtError = true;
assertEqual(err.kind, deno.ErrorKind.NotFound);
}
assert(caughtError);
assertEqual(src, undefined);
});
testPerm({ write: true }, async function readDirSuccess() {
const files = await deno.readDir("tests/");
assertSameContent(files);
});

View file

@ -3,98 +3,7 @@ import * as fbs from "gen/msg_generated";
import { flatbuffers } from "flatbuffers";
import * as dispatch from "./dispatch";
import { assert } from "./util";
/**
* A FileInfo describes a file and is returned by `stat`, `lstat`,
* `statSync`, `lstatSync`.
*/
export interface FileInfo {
readonly _isFile: boolean;
readonly _isSymlink: boolean;
/** The size of the file, in bytes. */
len: number;
/**
* The last modification time of the file. This corresponds to the `mtime`
* field from `stat` on Unix and `ftLastWriteTime` on Windows. This may not
* be available on all platforms.
*/
modified: number | null;
/**
* The last access time of the file. This corresponds to the `atime`
* field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not
* be available on all platforms.
*/
accessed: number | null;
/**
* The last access time of the file. This corresponds to the `birthtime`
* field from `stat` on Unix and `ftCreationTime` on Windows. This may not
* be available on all platforms.
*/
created: number | null;
/**
* The underlying raw st_mode bits that contain the standard Unix permissions
* for this file/directory. TODO Match behavior with Go on windows for mode.
*/
mode: number | null;
/**
* Returns whether this is info for a regular file. This result is mutually
* exclusive to `FileInfo.isDirectory` and `FileInfo.isSymlink`.
*/
isFile(): boolean;
/**
* Returns whether this is info for a regular directory. This result is
* mutually exclusive to `FileInfo.isFile` and `FileInfo.isSymlink`.
*/
isDirectory(): boolean;
/**
* Returns whether this is info for a symlink. This result is
* mutually exclusive to `FileInfo.isFile` and `FileInfo.isDirectory`.
*/
isSymlink(): boolean;
}
class FileInfoImpl implements FileInfo {
readonly _isFile: boolean;
readonly _isSymlink: boolean;
len: number;
modified: number | null;
accessed: number | null;
created: number | null;
mode: number | null;
/* @internal */
constructor(private _msg: fbs.StatRes) {
const modified = this._msg.modified().toFloat64();
const accessed = this._msg.accessed().toFloat64();
const created = this._msg.created().toFloat64();
const hasMode = this._msg.hasMode();
const mode = this._msg.mode(); // negative for invalid mode (Windows)
this._isFile = this._msg.isFile();
this._isSymlink = this._msg.isSymlink();
this.len = this._msg.len().toFloat64();
this.modified = modified ? modified : null;
this.accessed = accessed ? accessed : null;
this.created = created ? created : null;
// null on Windows
this.mode = hasMode ? mode : null;
}
isFile() {
return this._isFile;
}
isDirectory() {
return !this._isFile && !this._isSymlink;
}
isSymlink() {
return this._isSymlink;
}
}
import { FileInfo, FileInfoImpl } from "./fileinfo";
/**
* Queries the file system for information on the path provided.

View file

@ -7,6 +7,7 @@ import "./fetch_test.ts";
import "./os_test.ts";
import "./files_test.ts";
import "./read_file_test.ts";
import "./read_dir_test.ts";
import "./write_file_test.ts";
import "./copy_file_test.ts";
import "./mkdir_test.ts";

View file

@ -76,6 +76,7 @@ pub fn msg_from_js(
msg::Any::Write => handle_write,
msg::Any::Remove => handle_remove,
msg::Any::ReadFile => handle_read_file,
msg::Any::ReadDir => handle_read_dir,
msg::Any::Rename => handle_rename,
msg::Any::Readlink => handle_read_link,
msg::Any::Symlink => handle_symlink,
@ -816,6 +817,63 @@ fn handle_stat(
})
}
fn handle_read_dir(
_state: Arc<IsolateState>,
base: &msg::Base,
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
let msg = base.msg_as_read_dir().unwrap();
let cmd_id = base.cmd_id();
let path = String::from(msg.path().unwrap());
blocking!(base.sync(), || -> OpResult {
debug!("handle_read_dir {}", path);
let builder = &mut FlatBufferBuilder::new();
let entries: Vec<_> = fs::read_dir(Path::new(&path))?
.map(|entry| {
let entry = entry.unwrap();
let metadata = entry.metadata().unwrap();
let file_type = metadata.file_type();
let name = builder.create_string(entry.file_name().to_str().unwrap());
let path = builder.create_string(entry.path().to_str().unwrap());
msg::StatRes::create(
builder,
&msg::StatResArgs {
is_file: file_type.is_file(),
is_symlink: file_type.is_symlink(),
len: metadata.len(),
modified: to_seconds!(metadata.modified()),
accessed: to_seconds!(metadata.accessed()),
created: to_seconds!(metadata.created()),
name: Some(name),
path: Some(path),
..Default::default()
},
)
}).collect();
let entries = builder.create_vector(&entries);
let msg = msg::ReadDirRes::create(
builder,
&msg::ReadDirResArgs {
entries: Some(entries),
..Default::default()
},
);
Ok(serialize_response(
cmd_id,
builder,
msg::BaseArgs {
msg: Some(msg.as_union_value()),
msg_type: msg::Any::ReadDirRes,
..Default::default()
},
))
})
}
fn handle_write_file(
state: Arc<IsolateState>,
base: &msg::Base,

View file

@ -16,6 +16,8 @@ union Any {
Remove,
ReadFile,
ReadFileRes,
ReadDir,
ReadDirRes,
WriteFile,
CopyFile,
Rename,
@ -191,6 +193,14 @@ table ReadFileRes {
data: [ubyte];
}
table ReadDir {
path: string;
}
table ReadDirRes {
entries: [StatRes];
}
table WriteFile {
filename: string;
data: [ubyte];
@ -235,6 +245,8 @@ table StatRes {
created:ulong;
mode: uint;
has_mode: bool; // false on windows
name: string;
path: string;
}
table Truncate {