From d32dfd698adce832ead657fc2118a31754ffa0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sat, 24 Aug 2019 13:48:15 +0200 Subject: [PATCH] port cli/ops/fs.rs to json ops, part 2 --- cli/msg.fbs | 41 ------- cli/ops/dispatch_flatbuffers.rs | 8 +- cli/ops/fs.rs | 183 ++++++++++++++++---------------- cli/ops/mod.rs | 14 +++ js/copy_file.ts | 18 +--- js/dispatch.ts | 8 ++ js/file_info.ts | 22 ++-- js/read_dir.ts | 34 +++--- js/remove.ts | 17 +-- js/stat.ts | 54 ++++++---- 10 files changed, 180 insertions(+), 219 deletions(-) diff --git a/cli/msg.fbs b/cli/msg.fbs index e02f7518334111..5f0ff34bd4b7e7 100644 --- a/cli/msg.fbs +++ b/cli/msg.fbs @@ -1,21 +1,15 @@ union Any { - CopyFile, Cwd, CwdRes, Link, MakeTempDir, MakeTempDirRes, Read, - ReadDir, - ReadDirRes, ReadRes, Readlink, ReadlinkRes, - Remove, Rename, Seek, - Stat, - StatRes, Symlink, Truncate, Write, @@ -133,24 +127,6 @@ table MakeTempDirRes { path: string; } -table Remove { - path: string; - recursive: bool; -} - -table ReadDir { - path: string; -} - -table ReadDirRes { - entries: [StatRes]; -} - -table CopyFile { - from: string; - to: string; -} - table Rename { oldpath: string; newpath: string; @@ -174,23 +150,6 @@ table Link { newname: string; } -table Stat { - filename: string; - lstat: bool; -} - -table StatRes { - is_file: bool; - is_symlink: bool; - len: ulong; - modified:ulong; - accessed:ulong; - created:ulong; - mode: uint; - has_mode: bool; // false on windows - name: string; -} - table Truncate { name: string; len: uint; diff --git a/cli/ops/dispatch_flatbuffers.rs b/cli/ops/dispatch_flatbuffers.rs index 8829c3cab94dd6..97ec67b4574820 100644 --- a/cli/ops/dispatch_flatbuffers.rs +++ b/cli/ops/dispatch_flatbuffers.rs @@ -8,8 +8,8 @@ use hyper::rt::Future; use super::files::{op_read, op_write}; use super::fs::{ - op_copy_file, op_cwd, op_link, op_make_temp_dir, op_read_dir, op_read_link, - op_remove, op_rename, op_stat, op_symlink, op_truncate, + op_cwd, op_link, op_make_temp_dir, op_read_link, op_rename, op_symlink, + op_truncate, }; type CliDispatchFn = fn( @@ -124,16 +124,12 @@ pub fn serialize_response( /// Standard ops set for most isolates pub fn op_selector_std(inner_type: msg::Any) -> Option { match inner_type { - msg::Any::CopyFile => Some(op_copy_file), msg::Any::Cwd => Some(op_cwd), msg::Any::Link => Some(op_link), msg::Any::MakeTempDir => Some(op_make_temp_dir), msg::Any::Read => Some(op_read), - msg::Any::ReadDir => Some(op_read_dir), msg::Any::Readlink => Some(op_read_link), - msg::Any::Remove => Some(op_remove), msg::Any::Rename => Some(op_rename), - msg::Any::Stat => Some(op_stat), msg::Any::Symlink => Some(op_symlink), msg::Any::Truncate => Some(op_truncate), msg::Any::Write => Some(op_write), diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 505023d64170fc..5ef45b2d96a1a4 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -121,19 +121,27 @@ pub fn op_chown( }) } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct RemoveArgs { + promise_id: Option, + path: String, + recursive: bool, +} + pub fn op_remove( state: &ThreadSafeState, - base: &msg::Base<'_>, - data: Option, -) -> CliOpResult { - assert!(data.is_none()); - let inner = base.inner_as_remove().unwrap(); - let (path, path_) = deno_fs::resolve_from_cwd(inner.path().unwrap())?; - let recursive = inner.recursive(); + args: Value, + _zero_copy: Option, +) -> Result { + let args: RemoveArgs = serde_json::from_value(args)?; + let (path, path_) = deno_fs::resolve_from_cwd(args.path.as_ref())?; + let recursive = args.recursive; state.check_write(&path_)?; - blocking(base.sync(), move || { + let is_sync = args.promise_id.is_none(); + blocking_json(is_sync, move || { debug!("op_remove {}", path.display()); let metadata = fs::metadata(&path)?; if metadata.is_file() { @@ -143,25 +151,34 @@ pub fn op_remove( } else { fs::remove_dir(&path)?; } - Ok(empty_buf()) + Ok(json!({})) }) } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct CopyFileArgs { + promise_id: Option, + from: String, + to: String, +} + pub fn op_copy_file( state: &ThreadSafeState, - base: &msg::Base<'_>, - data: Option, -) -> CliOpResult { - assert!(data.is_none()); - let inner = base.inner_as_copy_file().unwrap(); - let (from, from_) = deno_fs::resolve_from_cwd(inner.from().unwrap())?; - let (to, to_) = deno_fs::resolve_from_cwd(inner.to().unwrap())?; + args: Value, + _zero_copy: Option, +) -> Result { + let args: CopyFileArgs = serde_json::from_value(args)?; + + let (from, from_) = deno_fs::resolve_from_cwd(args.from.as_ref())?; + let (to, to_) = deno_fs::resolve_from_cwd(args.to.as_ref())?; state.check_read(&from_)?; state.check_write(&to_)?; debug!("op_copy_file {} {}", from.display(), to.display()); - blocking(base.sync(), move || { + let is_sync = args.promise_id.is_none(); + blocking_json(is_sync, move || { // On *nix, Rust deem non-existent path as invalid input // See https://github.com/rust-lang/rust/issues/54800 // Once the issue is reolved, we should remove this workaround. @@ -173,7 +190,7 @@ pub fn op_copy_file( } fs::copy(&from, &to)?; - Ok(empty_buf()) + Ok(json!({})) }) } @@ -197,22 +214,29 @@ fn get_mode(_perm: &fs::Permissions) -> u32 { 0 } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct StatArgs { + promise_id: Option, + filename: String, + lstat: bool, +} + pub fn op_stat( state: &ThreadSafeState, - base: &msg::Base<'_>, - data: Option, -) -> CliOpResult { - assert!(data.is_none()); - let inner = base.inner_as_stat().unwrap(); - let cmd_id = base.cmd_id(); + args: Value, + _zero_copy: Option, +) -> Result { + let args: StatArgs = serde_json::from_value(args)?; + let (filename, filename_) = - deno_fs::resolve_from_cwd(inner.filename().unwrap())?; - let lstat = inner.lstat(); + deno_fs::resolve_from_cwd(args.filename.as_ref())?; + let lstat = args.lstat; state.check_read(&filename_)?; - blocking(base.sync(), move || { - let builder = &mut FlatBufferBuilder::new(); + let is_sync = args.promise_id.is_none(); + blocking_json(is_sync, move || { debug!("op_stat {} {}", filename.display(), lstat); let metadata = if lstat { fs::symlink_metadata(&filename)? @@ -220,88 +244,61 @@ pub fn op_stat( fs::metadata(&filename)? }; - let inner = msg::StatRes::create( - builder, - &msg::StatResArgs { - is_file: metadata.is_file(), - is_symlink: metadata.file_type().is_symlink(), - len: metadata.len(), - modified: to_seconds!(metadata.modified()), - accessed: to_seconds!(metadata.accessed()), - created: to_seconds!(metadata.created()), - mode: get_mode(&metadata.permissions()), - has_mode: cfg!(target_family = "unix"), - ..Default::default() - }, - ); - - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - inner: Some(inner.as_union_value()), - inner_type: msg::Any::StatRes, - ..Default::default() - }, - )) + Ok(json!({ + "isFile": metadata.is_file(), + "isSymlink": metadata.file_type().is_symlink(), + "len": metadata.len(), + "modified":to_seconds!(metadata.modified()), + "accessed":to_seconds!(metadata.accessed()), + "created":to_seconds!(metadata.created()), + "mode": get_mode(&metadata.permissions()), + "hasMode": cfg!(target_family = "unix"), // false on windows, + })) }) } +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct ReadDirArgs { + promise_id: Option, + path: String, +} + pub fn op_read_dir( state: &ThreadSafeState, - base: &msg::Base<'_>, - data: Option, -) -> CliOpResult { - assert!(data.is_none()); - let inner = base.inner_as_read_dir().unwrap(); - let cmd_id = base.cmd_id(); - let (path, path_) = deno_fs::resolve_from_cwd(inner.path().unwrap())?; + args: Value, + _zero_copy: Option, +) -> Result { + let args: ReadDirArgs = serde_json::from_value(args)?; + let (path, path_) = deno_fs::resolve_from_cwd(args.path.as_ref())?; state.check_read(&path_)?; - blocking(base.sync(), move || { + let is_sync = args.promise_id.is_none(); + blocking_json(is_sync, move || { debug!("op_read_dir {}", path.display()); - let builder = &mut FlatBufferBuilder::new(); + let entries: Vec<_> = fs::read_dir(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()); - - 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), - mode: get_mode(&metadata.permissions()), - has_mode: cfg!(target_family = "unix"), - }, - ) + + json!({ + "isFile": file_type.is_file(), + "isSymlink": file_type.is_symlink(), + "len": metadata.len(), + "modified": to_seconds!(metadata.modified()), + "accessed": to_seconds!(metadata.accessed()), + "created": to_seconds!(metadata.created()), + "mode": get_mode(&metadata.permissions()), + "name": entry.file_name().to_str().unwrap(), + "hasMode": cfg!(target_family = "unix"), // false on windows, + }) }) .collect(); - let entries = builder.create_vector(&entries); - let inner = msg::ReadDirRes::create( - builder, - &msg::ReadDirResArgs { - entries: Some(entries), - }, - ); - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - inner: Some(inner.as_union_value()), - inner_type: msg::Any::ReadDirRes, - ..Default::default() - }, - )) + Ok(json!({ "entries": entries })) }) } diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index eb32248ef530e4..dbf558f8bb42e7 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -72,6 +72,10 @@ pub const OP_CHDIR: OpId = 42; pub const OP_MKDIR: OpId = 43; pub const OP_CHMOD: OpId = 44; pub const OP_CHOWN: OpId = 45; +pub const OP_REMOVE: OpId = 46; +pub const OP_COPY_FILE: OpId = 47; +pub const OP_STAT: OpId = 48; +pub const OP_READ_DIR: OpId = 49; pub fn dispatch( state: &ThreadSafeState, @@ -258,6 +262,16 @@ pub fn dispatch( OP_CHOWN => { dispatch_json::dispatch(fs::op_chown, state, control, zero_copy) } + OP_REMOVE => { + dispatch_json::dispatch(fs::op_remove, state, control, zero_copy) + } + OP_COPY_FILE => { + dispatch_json::dispatch(fs::op_copy_file, state, control, zero_copy) + } + OP_STAT => dispatch_json::dispatch(fs::op_stat, state, control, zero_copy), + OP_READ_DIR => { + dispatch_json::dispatch(fs::op_read_dir, state, control, zero_copy) + } OP_FLATBUFFER => dispatch_flatbuffers::dispatch(state, control, zero_copy), _ => panic!("bad op_id"), }; diff --git a/js/copy_file.ts b/js/copy_file.ts index 4c62ed1b0a5f9d..b299a52bc556cf 100644 --- a/js/copy_file.ts +++ b/js/copy_file.ts @@ -1,16 +1,6 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers"; - -function req( - from: string, - to: string -): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] { - const builder = flatbuffers.createBuilder(); - const from_ = builder.createString(from); - const to_ = builder.createString(to); - const inner = msg.CopyFile.createCopyFile(builder, from_, to_); - return [builder, msg.Any.CopyFile, inner]; -} +import { sendSync, sendAsync } from "./dispatch_json"; +import * as dispatch from "./dispatch"; /** Copies the contents of a file to another by name synchronously. * Creates a new file if target does not exists, and if target exists, @@ -22,7 +12,7 @@ function req( * Deno.copyFileSync("from.txt", "to.txt"); */ export function copyFileSync(from: string, to: string): void { - sendSync(...req(from, to)); + sendSync(dispatch.OP_COPY_FILE, { from, to }); } /** Copies the contents of a file to another by name. @@ -36,5 +26,5 @@ export function copyFileSync(from: string, to: string): void { * await Deno.copyFile("from.txt", "to.txt"); */ export async function copyFile(from: string, to: string): Promise { - await sendAsync(...req(from, to)); + await sendAsync(dispatch.OP_COPY_FILE, { from, to }); } diff --git a/js/dispatch.ts b/js/dispatch.ts index 4bdd7f87c694da..65b604e19d099e 100644 --- a/js/dispatch.ts +++ b/js/dispatch.ts @@ -50,6 +50,10 @@ export const OP_CHDIR = 42; export const OP_MKDIR = 43; export const OP_CHMOD = 44; export const OP_CHOWN = 45; +export const OP_REMOVE = 46; +export const OP_COPY_FILE = 47; +export const OP_STAT = 48; +export const OP_READ_DIR = 49; export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void { switch (opId) { @@ -80,6 +84,10 @@ export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void { case OP_MKDIR: case OP_CHMOD: case OP_CHOWN: + case OP_REMOVE: + case OP_COPY_FILE: + case OP_STAT: + case OP_READ_DIR: json.asyncMsgFromRust(opId, ui8); break; default: diff --git a/js/file_info.ts b/js/file_info.ts index f2e5a88aecb120..c124e06bfdf1cb 100644 --- a/js/file_info.ts +++ b/js/file_info.ts @@ -1,5 +1,5 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import * as msg from "gen/cli/msg_generated"; +import { StatResponse } from "./stat"; /** A FileInfo describes a file and is returned by `stat`, `lstat`, * `statSync`, `lstatSync`. @@ -58,17 +58,17 @@ export class FileInfoImpl implements FileInfo { name: string | null; /* @internal */ - constructor(private _inner: msg.StatRes) { - const modified = this._inner.modified().toFloat64(); - const accessed = this._inner.accessed().toFloat64(); - const created = this._inner.created().toFloat64(); - const hasMode = this._inner.hasMode(); - const mode = this._inner.mode(); // negative for invalid mode (Windows) - const name = this._inner.name(); + constructor(private _res: StatResponse) { + const modified = this._res.modified; + const accessed = this._res.accessed; + const created = this._res.created; + const hasMode = this._res.hasMode; + const mode = this._res.mode; // negative for invalid mode (Windows) + const name = this._res.name; - this._isFile = this._inner.isFile(); - this._isSymlink = this._inner.isSymlink(); - this.len = this._inner.len().toFloat64(); + this._isFile = this._res.isFile; + this._isSymlink = this._res.isSymlink; + this.len = this._res.len; this.modified = modified ? modified : null; this.accessed = accessed ? accessed : null; this.created = created ? created : null; diff --git a/js/read_dir.ts b/js/read_dir.ts index 13c620916e6c54..1abd437f486524 100644 --- a/js/read_dir.ts +++ b/js/read_dir.ts @@ -1,25 +1,21 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers"; +import { sendSync, sendAsync } from "./dispatch_json"; +import * as dispatch from "./dispatch"; import { FileInfo, FileInfoImpl } from "./file_info"; -import { assert } from "./util"; +import { StatResponse } from "./stat"; -function req(path: string): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] { - const builder = flatbuffers.createBuilder(); - const path_ = builder.createString(path); - const inner = msg.ReadDir.createReadDir(builder, path_); - return [builder, msg.Any.ReadDir, inner]; +// NOTE: "entries" contains list of serialized `StatResponse`s that need +// to be deserialized +interface ReadDirResponse { + entries: StatResponse[]; } -function res(baseRes: null | msg.Base): FileInfo[] { - assert(baseRes != null); - assert(msg.Any.ReadDirRes === baseRes!.innerType()); - const res = new msg.ReadDirRes(); - assert(baseRes!.inner(res) != null); - const fileInfos: FileInfo[] = []; - for (let i = 0; i < res.entriesLength(); i++) { - fileInfos.push(new FileInfoImpl(res.entries(i)!)); - } - return fileInfos; +function res(response: ReadDirResponse): FileInfo[] { + return response.entries.map( + (statRes: StatResponse): FileInfo => { + return new FileInfoImpl(statRes); + } + ); } /** Reads the directory given by path and returns a list of file info @@ -28,7 +24,7 @@ function res(baseRes: null | msg.Base): FileInfo[] { * const files = Deno.readDirSync("/"); */ export function readDirSync(path: string): FileInfo[] { - return res(sendSync(...req(path))); + return res(sendSync(dispatch.OP_READ_DIR, { path })); } /** Reads the directory given by path and returns a list of file info. @@ -36,5 +32,5 @@ export function readDirSync(path: string): FileInfo[] { * const files = await Deno.readDir("/"); */ export async function readDir(path: string): Promise { - return res(await sendAsync(...req(path))); + return res(await sendAsync(dispatch.OP_READ_DIR, { path })); } diff --git a/js/remove.ts b/js/remove.ts index 95294e6cfcab9c..f2a94f395359aa 100644 --- a/js/remove.ts +++ b/js/remove.ts @@ -1,20 +1,11 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers"; +import { sendSync, sendAsync } from "./dispatch_json"; +import * as dispatch from "./dispatch"; export interface RemoveOption { recursive?: boolean; } -function req( - path: string, - options: RemoveOption -): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] { - const builder = flatbuffers.createBuilder(); - const path_ = builder.createString(path); - const inner = msg.Remove.createRemove(builder, path_, !!options.recursive); - return [builder, msg.Any.Remove, inner]; -} - /** Removes the named file or directory synchronously. Would throw * error if permission denied, not found, or directory not empty if `recursive` * set to false. @@ -23,7 +14,7 @@ function req( * Deno.removeSync("/path/to/dir/or/file", {recursive: false}); */ export function removeSync(path: string, options: RemoveOption = {}): void { - sendSync(...req(path, options)); + sendSync(dispatch.OP_REMOVE, { path, recursive: !!options.recursive }); } /** Removes the named file or directory. Would throw error if @@ -37,5 +28,5 @@ export async function remove( path: string, options: RemoveOption = {} ): Promise { - await sendAsync(...req(path, options)); + await sendAsync(dispatch.OP_REMOVE, { path, recursive: !!options.recursive }); } diff --git a/js/stat.ts b/js/stat.ts index 1fcce82afde4d8..1cc8d070a9388b 100644 --- a/js/stat.ts +++ b/js/stat.ts @@ -1,24 +1,18 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers"; -import { assert } from "./util"; +import { sendSync, sendAsync } from "./dispatch_json"; +import * as dispatch from "./dispatch"; import { FileInfo, FileInfoImpl } from "./file_info"; -function req( - filename: string, - lstat: boolean -): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] { - const builder = flatbuffers.createBuilder(); - const filename_ = builder.createString(filename); - const inner = msg.Stat.createStat(builder, filename_, lstat); - return [builder, msg.Any.Stat, inner]; -} - -function res(baseRes: null | msg.Base): FileInfo { - assert(baseRes != null); - assert(msg.Any.StatRes === baseRes!.innerType()); - const res = new msg.StatRes(); - assert(baseRes!.inner(res) != null); - return new FileInfoImpl(res); +export interface StatResponse { + isFile: boolean; + isSymlink: boolean; + len: number; + modified: number; + accessed: number; + created: number; + mode: number; + hasMode: boolean; // false on windows + name: string | null; } /** Queries the file system for information on the path provided. If the given @@ -28,7 +22,11 @@ function res(baseRes: null | msg.Base): FileInfo { * assert(fileInfo.isFile()); */ export async function lstat(filename: string): Promise { - return res(await sendAsync(...req(filename, true))); + const res = (await sendAsync(dispatch.OP_STAT, { + filename, + lstat: true + })) as StatResponse; + return new FileInfoImpl(res); } /** Queries the file system for information on the path provided synchronously. @@ -39,7 +37,11 @@ export async function lstat(filename: string): Promise { * assert(fileInfo.isFile()); */ export function lstatSync(filename: string): FileInfo { - return res(sendSync(...req(filename, true))); + const res = sendSync(dispatch.OP_STAT, { + filename, + lstat: true + }) as StatResponse; + return new FileInfoImpl(res); } /** Queries the file system for information on the path provided. `stat` Will @@ -49,7 +51,11 @@ export function lstatSync(filename: string): FileInfo { * assert(fileInfo.isFile()); */ export async function stat(filename: string): Promise { - return res(await sendAsync(...req(filename, false))); + const res = (await sendAsync(dispatch.OP_STAT, { + filename, + lstat: false + })) as StatResponse; + return new FileInfoImpl(res); } /** Queries the file system for information on the path provided synchronously. @@ -59,5 +65,9 @@ export async function stat(filename: string): Promise { * assert(fileInfo.isFile()); */ export function statSync(filename: string): FileInfo { - return res(sendSync(...req(filename, false))); + const res = sendSync(dispatch.OP_STAT, { + filename, + lstat: false + }) as StatResponse; + return new FileInfoImpl(res); }