diff --git a/BUILD.gn b/BUILD.gn index 172026fdda..5532850c0f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -196,6 +196,7 @@ run_node("gen_declarations") { "js/global-eval.ts", "js/globals.ts", "js/os.ts", + "js/read_file.ts", "js/text_encoding.ts", "js/timers.ts", "js/tsconfig.generated.json", @@ -234,6 +235,7 @@ run_node("bundle") { "js/main.ts", "js/os.ts", "js/plugins.d.ts", + "js/read_file.ts", "js/text_encoding.ts", "js/timers.ts", "js/types.ts", diff --git a/js/deno.ts b/js/deno.ts index ba4a5151e6..ce01c5dad6 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -7,12 +7,12 @@ export { FileInfo, makeTempDirSync, mkdirSync, - readFileSync, renameSync, statSync, lstatSync, writeFileSync } from "./os"; +export { readFileSync, readFile } from "./read_file"; export { ErrorKind, DenoError } from "./errors"; export { libdeno } from "./libdeno"; export const argv: string[] = []; diff --git a/js/os.ts b/js/os.ts index 3adfb5c1e8..d29d0d74a5 100644 --- a/js/os.ts +++ b/js/os.ts @@ -126,37 +126,6 @@ export function mkdirSync(path: string, mode = 0o777): void { sendSync(builder, fbs.Any.MkdirSync, msg); } -/** - * Read the file. - * import { readFileSync } from "deno"; - * - * const decoder = new TextDecoder("utf-8"); - * const data = readFileSync("hello.txt"); - * console.log(decoder.decode(data)); - */ -export function readFileSync(filename: string): Uint8Array { - /* Ideally we could write - const res = sendSync({ - command: fbs.Command.READ_FILE_SYNC, - readFileSyncFilename: filename - }); - return res.readFileSyncData; - */ - const builder = new flatbuffers.Builder(); - const filename_ = builder.createString(filename); - fbs.ReadFileSync.startReadFileSync(builder); - fbs.ReadFileSync.addFilename(builder, filename_); - const msg = fbs.ReadFileSync.endReadFileSync(builder); - const baseRes = sendSync(builder, fbs.Any.ReadFileSync, msg); - assert(baseRes != null); - assert(fbs.Any.ReadFileSyncRes === baseRes!.msgType()); - const res = new fbs.ReadFileSyncRes(); - assert(baseRes!.msg(res) != null); - const dataArray = res.dataArray(); - assert(dataArray != null); - return new Uint8Array(dataArray!); -} - function createEnv(_msg: fbs.EnvironRes): { [index: string]: string } { const env: { [index: string]: string } = {}; @@ -365,13 +334,6 @@ export function writeFileSync( * renameSync(oldpath, newpath); */ export function renameSync(oldpath: string, newpath: string): void { - /* Ideally we could write: - const res = sendSync({ - command: fbs.Command.RENAME_SYNC, - renameOldPath: oldpath, - renameNewPath: newpath - }); - */ const builder = new flatbuffers.Builder(); const _oldpath = builder.createString(oldpath); const _newpath = builder.createString(newpath); diff --git a/js/os_test.ts b/js/os_test.ts index 7a252cb737..544d7d49f0 100644 --- a/js/os_test.ts +++ b/js/os_test.ts @@ -85,34 +85,6 @@ test(async function lstatSyncNotFound() { assertEqual(badInfo, undefined); }); -test(async function readFileSyncSuccess() { - const data = deno.readFileSync("package.json"); - if (!data.byteLength) { - throw Error( - `Expected positive value for data.byteLength ${data.byteLength}` - ); - } - const decoder = new TextDecoder("utf-8"); - const json = decoder.decode(data); - const pkg = JSON.parse(json); - assertEqual(pkg.name, "deno"); -}); - -/* TODO We should be able to catch specific types. -test(function tests_readFileSync_NotFound() { - let caughtError = false; - let data; - try { - data = deno.readFileSync("bad_filename"); - } catch (e) { - caughtError = true; - assert(e instanceof deno.NotFound); - } - assert(caughtError); - assert(data === undefined); -}); -*/ - testPerm({ write: true }, function writeFileSyncSuccess() { const enc = new TextEncoder(); const data = enc.encode("Hello"); diff --git a/js/read_file.ts b/js/read_file.ts new file mode 100644 index 0000000000..2afea42f11 --- /dev/null +++ b/js/read_file.ts @@ -0,0 +1,50 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. +import * as fbs from "gen/msg_generated"; +import { flatbuffers } from "flatbuffers"; +import { assert } from "./util"; +import * as dispatch from "./dispatch"; + +/** + * Read the entire contents of a file synchronously. + * + * import { readFileSync } from "deno"; + * const decoder = new TextDecoder("utf-8"); + * const data = readFileSync("hello.txt"); + * console.log(decoder.decode(data)); + */ +export function readFileSync(filename: string): Uint8Array { + return res(dispatch.sendSync(...req(filename))); +} + +/** + * Read the entire contents of a file. + * + * import { readFile } from "deno"; + * const decoder = new TextDecoder("utf-8"); + * const data = await readFile("hello.txt"); + * console.log(decoder.decode(data)); + */ +export async function readFile(filename: string): Promise { + return res(await dispatch.sendAsync(...req(filename))); +} + +function req( + filename: string +): [flatbuffers.Builder, fbs.Any, flatbuffers.Offset] { + const builder = new flatbuffers.Builder(); + const filename_ = builder.createString(filename); + fbs.ReadFile.startReadFile(builder); + fbs.ReadFile.addFilename(builder, filename_); + const msg = fbs.ReadFile.endReadFile(builder); + return [builder, fbs.Any.ReadFile, msg]; +} + +function res(baseRes: null | fbs.Base): Uint8Array { + assert(baseRes != null); + assert(fbs.Any.ReadFileRes === baseRes!.msgType()); + const msg = new fbs.ReadFileRes(); + assert(baseRes!.msg(msg) != null); + const dataArray = msg.dataArray(); + assert(dataArray != null); + return new Uint8Array(dataArray!); +} diff --git a/js/read_file_test.ts b/js/read_file_test.ts new file mode 100644 index 0000000000..6d4f71b624 --- /dev/null +++ b/js/read_file_test.ts @@ -0,0 +1,34 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. +import { test, assert, assertEqual } from "./test_util.ts"; +import * as deno from "deno"; + +test(function readFileSyncSuccess() { + const data = deno.readFileSync("package.json"); + assert(data.byteLength > 0); + const decoder = new TextDecoder("utf-8"); + const json = decoder.decode(data); + const pkg = JSON.parse(json); + assertEqual(pkg.name, "deno"); +}); + +test(function readFileSyncNotFound() { + let caughtError = false; + let data; + try { + data = deno.readFileSync("bad_filename"); + } catch (e) { + caughtError = true; + assertEqual(e.kind, deno.ErrorKind.NotFound); + } + assert(caughtError); + assert(data === undefined); +}); + +test(async function readFileSuccess() { + const data = await deno.readFile("package.json"); + assert(data.byteLength > 0); + const decoder = new TextDecoder("utf-8"); + const json = decoder.decode(data); + const pkg = JSON.parse(json); + assertEqual(pkg.name, "deno"); +}); diff --git a/js/unit_tests.ts b/js/unit_tests.ts index 0e877dea65..efbc7383c7 100644 --- a/js/unit_tests.ts +++ b/js/unit_tests.ts @@ -3,5 +3,6 @@ // But it can also be run manually: ./out/debug/deno js/unit_tests.ts import "./compiler_test.ts"; import "./console_test.ts"; -import "./os_test.ts"; import "./fetch_test.ts"; +import "./os_test.ts"; +import "./read_file_test.ts"; diff --git a/src/handlers.rs b/src/handlers.rs index 780c9d2e4f..586f3dbbf0 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -50,7 +50,7 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) { msg::Any::TimerClear => handle_timer_clear, msg::Any::MakeTempDir => handle_make_temp_dir, msg::Any::MkdirSync => handle_mkdir_sync, - msg::Any::ReadFileSync => handle_read_file_sync, + msg::Any::ReadFile => handle_read_file, msg::Any::RenameSync => handle_rename_sync, msg::Any::SetEnv => handle_set_env, msg::Any::StatSync => handle_stat_sync, @@ -430,20 +430,20 @@ fn handle_mkdir_sync(d: *const DenoC, base: &msg::Base) -> Box { } // Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184 -fn handle_read_file_sync(_d: *const DenoC, base: &msg::Base) -> Box { - let msg = base.msg_as_read_file_sync().unwrap(); +fn handle_read_file(_d: *const DenoC, base: &msg::Base) -> Box { + let msg = base.msg_as_read_file().unwrap(); let cmd_id = base.cmd_id(); let filename = String::from(msg.filename().unwrap()); Box::new(futures::future::result(|| -> OpResult { - debug!("handle_read_file_sync {}", filename); + debug!("handle_read_file {}", filename); let vec = fs::read(Path::new(&filename))?; // Build the response message. memcpy data into msg. // TODO(ry) zero-copy. let builder = &mut FlatBufferBuilder::new(); let data_off = builder.create_vector(vec.as_slice()); - let msg = msg::ReadFileSyncRes::create( + let msg = msg::ReadFileRes::create( builder, - &msg::ReadFileSyncResArgs { + &msg::ReadFileResArgs { data: Some(data_off), ..Default::default() }, @@ -453,7 +453,7 @@ fn handle_read_file_sync(_d: *const DenoC, base: &msg::Base) -> Box { builder, msg::BaseArgs { msg: Some(msg.as_union_value()), - msg_type: msg::Any::ReadFileSyncRes, + msg_type: msg::Any::ReadFileRes, ..Default::default() }, )) diff --git a/src/msg.fbs b/src/msg.fbs index 5d55253b97..77aae8ffb6 100644 --- a/src/msg.fbs +++ b/src/msg.fbs @@ -15,8 +15,8 @@ union Any { MakeTempDir, MakeTempDirRes, MkdirSync, - ReadFileSync, - ReadFileSyncRes, + ReadFile, + ReadFileRes, RenameSync, StatSync, StatSyncRes, @@ -173,11 +173,11 @@ table MkdirSync { // mode specified by https://godoc.org/os#FileMode } -table ReadFileSync { +table ReadFile { filename: string; } -table ReadFileSyncRes { +table ReadFileRes { data: [ubyte]; }