summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--js/deno.ts10
-rw-r--r--js/os.ts75
-rw-r--r--js/unit_tests.ts64
-rw-r--r--src/handlers.rs55
-rw-r--r--src/msg.fbs16
5 files changed, 219 insertions, 1 deletions
diff --git a/js/deno.ts b/js/deno.ts
index 7a5c4217e..e24345ccd 100644
--- a/js/deno.ts
+++ b/js/deno.ts
@@ -1,5 +1,13 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
// Public deno module.
-export { exit, makeTempDirSync, readFileSync, writeFileSync } from "./os";
+export {
+ exit,
+ FileInfo,
+ makeTempDirSync,
+ readFileSync,
+ statSync,
+ lStatSync,
+ writeFileSync
+} from "./os";
export { libdeno } from "./libdeno";
export const argv: string[] = [];
diff --git a/js/os.ts b/js/os.ts
index 10ba32f9d..f0f8897cc 100644
--- a/js/os.ts
+++ b/js/os.ts
@@ -169,6 +169,81 @@ export function readFileSync(filename: string): Uint8Array {
return new Uint8Array(dataArray!);
}
+export class FileInfo {
+ private _isFile: boolean;
+ private _isSymlink: boolean;
+ len: number;
+ modified: number;
+ accessed: number;
+ // Creation time is not available on all platforms.
+ created: number | null;
+
+ /* @internal */
+ constructor(private _msg: fbs.StatSyncRes) {
+ const created = this._msg.created().toFloat64();
+
+ this._isFile = this._msg.isFile();
+ this._isSymlink = this._msg.isSymlink();
+ this.len = this._msg.len().toFloat64();
+ this.modified = this._msg.modified().toFloat64();
+ this.accessed = this._msg.accessed().toFloat64();
+ this.created = created ? created: null;
+ }
+
+ isFile() {
+ return this._isFile;
+ }
+
+ isDirectory() {
+ return !this._isFile && !this._isSymlink;
+ }
+
+ isSymlink() {
+ return this._isSymlink;
+ }
+}
+
+export function lStatSync(filename: string): FileInfo {
+ return statSyncInner(filename, true);
+}
+
+export function statSync(filename: string): FileInfo {
+ return statSyncInner(filename, false);
+}
+
+function statSyncInner(filename: string, lstat: boolean): FileInfo {
+ /* Ideally we could write
+ const res = send({
+ command: fbs.Command.STAT_FILE_SYNC,
+ StatFilename: filename,
+ StatLStat: lstat,
+ });
+ return new FileInfo(res);
+ */
+ const builder = new flatbuffers.Builder();
+ const filename_ = builder.createString(filename);
+ fbs.StatSync.startStatSync(builder);
+ fbs.StatSync.addFilename(builder, filename_);
+ fbs.StatSync.addLstat(builder, lstat);
+ const msg = fbs.StatSync.endStatSync(builder);
+ fbs.Base.startBase(builder);
+ fbs.Base.addMsg(builder, msg);
+ fbs.Base.addMsgType(builder, fbs.Any.StatSync);
+ builder.finish(fbs.Base.endBase(builder));
+ const resBuf = libdeno.send(builder.asUint8Array());
+ assert(resBuf != null);
+ // TypeScript does not track `assert` from a CFA perspective, therefore not
+ // null assertion `!`
+ const bb = new flatbuffers.ByteBuffer(new Uint8Array(resBuf!));
+ const baseRes = fbs.Base.getRootAsBase(bb);
+ maybeThrowError(baseRes);
+ assert(fbs.Any.StatSyncRes === baseRes.msgType());
+ const res = new fbs.StatSyncRes();
+ assert(baseRes.msg(res) != null);
+ // TypeScript cannot track assertion above, therefore not null assertion
+ return new FileInfo(baseRes.msg(res)!);
+}
+
export function writeFileSync(
filename: string,
data: Uint8Array,
diff --git a/js/unit_tests.ts b/js/unit_tests.ts
index 92957c493..e1b04d4c4 100644
--- a/js/unit_tests.ts
+++ b/js/unit_tests.ts
@@ -13,6 +13,70 @@ test(async function tests_test() {
assert(true);
});
+// TODO Add tests for modified, accessed, and created fields once there is a way
+// to create temp files.
+test(async function statSyncSuccess() {
+ const packageInfo = deno.statSync("package.json");
+ assert(packageInfo.isFile());
+ assert(!packageInfo.isSymlink());
+
+ const testingInfo = deno.statSync("testing");
+ assert(testingInfo.isDirectory());
+ assert(!testingInfo.isSymlink());
+
+ const srcInfo = deno.statSync("src");
+ assert(srcInfo.isDirectory());
+ assert(!srcInfo.isSymlink());
+})
+
+test(async function statSyncNotFound() {
+ let caughtError = false;
+ let badInfo;
+
+ try {
+ badInfo = deno.statSync("bad_file_name");
+ } catch (err) {
+ caughtError = true;
+ // TODO assert(err instanceof deno.NotFound).
+ assert(err);
+ assertEqual(err.name, "deno.NotFound");
+ }
+
+ assert(caughtError);
+ assertEqual(badInfo, undefined);
+});
+
+test(async function lStatSyncSuccess() {
+ const packageInfo = deno.lStatSync("package.json");
+ assert(packageInfo.isFile());
+ assert(!packageInfo.isSymlink());
+
+ const testingInfo = deno.lStatSync("testing");
+ assert(!testingInfo.isDirectory());
+ assert(testingInfo.isSymlink());
+
+ const srcInfo = deno.lStatSync("src");
+ assert(srcInfo.isDirectory());
+ assert(!srcInfo.isSymlink());
+})
+
+test(async function lStatSyncNotFound() {
+ let caughtError = false;
+ let badInfo;
+
+ try {
+ badInfo = deno.lStatSync("bad_file_name");
+ } catch (err) {
+ caughtError = true;
+ // TODO assert(err instanceof deno.NotFound).
+ assert(err);
+ assertEqual(err.name, "deno.NotFound");
+ }
+
+ assert(caughtError);
+ assertEqual(badInfo, undefined);
+});
+
test(async function tests_readFileSync() {
const data = deno.readFileSync("package.json");
if (!data.byteLength) {
diff --git a/src/handlers.rs b/src/handlers.rs
index 7ee6018cc..564f5e5be 100644
--- a/src/handlers.rs
+++ b/src/handlers.rs
@@ -14,6 +14,7 @@ use hyper::Client;
use msg_generated::deno as msg;
use std;
use std::fs;
+use std::time::UNIX_EPOCH;
use std::path::Path;
use std::time::{Duration, Instant};
use tokio::prelude::future;
@@ -78,6 +79,13 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) {
let filename = msg.filename().unwrap();
handle_read_file_sync(d, &mut builder, filename)
}
+ msg::Any::StatSync => {
+ // TODO base.msg_as_StatSync();
+ let msg = msg::StatSync::init_from_table(base.msg().unwrap());
+ let filename = msg.filename().unwrap();
+ let lstat = msg.lstat();
+ handle_stat_sync(d, &mut builder, filename, lstat)
+ }
msg::Any::WriteFileSync => {
// TODO base.msg_as_WriteFileSync();
let msg = msg::WriteFileSync::init_from_table(base.msg().unwrap());
@@ -467,6 +475,53 @@ fn handle_read_file_sync(
))
}
+macro_rules! to_seconds {
+ ($time:expr) => {{
+ // Unwrap is safe here as if the file is before the unix epoch
+ // something is very wrong.
+ $time.and_then(|t| Ok(t.duration_since(UNIX_EPOCH).unwrap().as_secs()))
+ .unwrap_or(0)
+ }}
+}
+
+
+fn handle_stat_sync(
+ _d: *const DenoC,
+ builder: &mut FlatBufferBuilder,
+ filename: &str,
+ lstat: bool,
+) -> HandlerResult {
+ debug!("handle_stat_sync {} {}", filename, lstat);
+ let path = Path::new(filename);
+ let metadata = if lstat {
+ fs::symlink_metadata(path)?
+ } else {
+ fs::metadata(path)?
+ };
+
+ let msg = msg::StatSyncRes::create(
+ builder,
+ &msg::StatSyncResArgs {
+ 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()),
+ ..Default::default()
+ },
+ );
+
+ Ok(create_msg(
+ builder,
+ &msg::BaseArgs {
+ msg: Some(flatbuffers::Offset::new(msg.value())),
+ msg_type: msg::Any::StatSyncRes,
+ ..Default::default()
+ },
+ ))
+}
+
fn handle_write_file_sync(
d: *const DenoC,
_builder: &mut FlatBufferBuilder,
diff --git a/src/msg.fbs b/src/msg.fbs
index 162a8ddee..eb3753d75 100644
--- a/src/msg.fbs
+++ b/src/msg.fbs
@@ -16,6 +16,8 @@ union Any {
MakeTempDirRes,
ReadFileSync,
ReadFileSyncRes,
+ StatSync,
+ StatSyncRes,
WriteFileSync,
}
@@ -153,6 +155,20 @@ table ReadFileSyncRes {
data: [ubyte];
}
+table StatSync {
+ filename: string;
+ lstat: bool;
+}
+
+table StatSyncRes {
+ is_file: bool;
+ is_symlink: bool;
+ len: ulong;
+ modified:ulong;
+ accessed:ulong;
+ created:ulong;
+}
+
table WriteFileSync {
filename: string;
data: [ubyte];