summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/BUILD.gn7
-rw-r--r--cli/main.rs2
-rw-r--r--cli/msg.fbs38
-rw-r--r--cli/ops/dispatch_flatbuffers.rs20
-rw-r--r--cli/ops/dispatch_json.rs113
-rw-r--r--cli/ops/dispatch_minimal.rs11
-rw-r--r--cli/ops/fs.rs37
-rw-r--r--cli/ops/mod.rs36
-rw-r--r--cli/ops/os.rs117
-rw-r--r--cli/ops/utils.rs2
10 files changed, 218 insertions, 165 deletions
diff --git a/cli/BUILD.gn b/cli/BUILD.gn
index c7a80907e..08050ae06 100644
--- a/cli/BUILD.gn
+++ b/cli/BUILD.gn
@@ -83,7 +83,9 @@ ts_sources = [
"../js/dir.ts",
"../js/dispatch.ts",
"../js/dispatch_flatbuffers.ts",
+ "../js/dispatch_json.ts",
"../js/dispatch_minimal.ts",
+ "../js/dom_file.ts",
"../js/dom_types.ts",
"../js/dom_util.ts",
"../js/error_stack.ts",
@@ -91,12 +93,11 @@ ts_sources = [
"../js/event.ts",
"../js/event_target.ts",
"../js/fetch.ts",
- "../js/format_error.ts",
- "../js/dom_file.ts",
"../js/file_info.ts",
"../js/files.ts",
"../js/flatbuffers.ts",
"../js/form_data.ts",
+ "../js/format_error.ts",
"../js/get_random_values.ts",
"../js/globals.ts",
"../js/headers.ts",
@@ -134,10 +135,10 @@ ts_sources = [
"../js/url_search_params.ts",
"../js/util.ts",
"../js/utime.ts",
+ "../js/version.ts",
"../js/window.ts",
"../js/workers.ts",
"../js/write_file.ts",
- "../js/version.ts",
"../js/xeval.ts",
"../tsconfig.json",
diff --git a/cli/main.rs b/cli/main.rs
index 3f8f113b2..2e82b8ee8 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -13,6 +13,8 @@ extern crate indexmap;
#[cfg(unix)]
extern crate nix;
extern crate rand;
+extern crate serde;
+extern crate serde_derive;
extern crate url;
mod ansi;
diff --git a/cli/msg.fbs b/cli/msg.fbs
index 8fb92fee9..3a40b80f5 100644
--- a/cli/msg.fbs
+++ b/cli/msg.fbs
@@ -12,9 +12,6 @@ union Any {
Cwd,
CwdRes,
Dial,
- Environ,
- EnvironRes,
- Exit,
Fetch,
FetchSourceFile,
FetchSourceFileRes,
@@ -29,8 +26,6 @@ union Any {
HostGetMessageRes,
HostGetWorkerClosed,
HostPostMessage,
- IsTTY,
- IsTTYRes,
Kill,
Link,
Listen,
@@ -77,9 +72,6 @@ union Any {
Truncate,
HomeDir,
HomeDirRes,
- ExecPath,
- ExecPathRes,
- Utime,
WorkerGetMessage,
WorkerGetMessageRes,
WorkerPostMessage,
@@ -286,21 +278,11 @@ table GlobalTimerRes { }
table GlobalTimerStop { }
-table Exit {
- code: int;
-}
-
-table Environ {}
-
table SetEnv {
key: string;
value: string;
}
-table EnvironRes {
- map: [KeyValue];
-}
-
table KeyValue {
key: string;
value: string;
@@ -469,18 +451,6 @@ table HomeDirRes {
path: string;
}
-table ExecPath {}
-
-table ExecPathRes {
- path: string;
-}
-
-table Utime {
- filename: string;
- atime: uint64;
- mtime: uint64;
-}
-
table Open {
filename: string;
perm: uint;
@@ -600,14 +570,6 @@ table NowRes {
subsec_nanos: uint32;
}
-table IsTTY {}
-
-table IsTTYRes {
- stdin: bool;
- stdout: bool;
- stderr: bool;
-}
-
table Seek {
rid: uint32;
offset: int;
diff --git a/cli/ops/dispatch_flatbuffers.rs b/cli/ops/dispatch_flatbuffers.rs
index 2b2e5050d..b9dd4d9fa 100644
--- a/cli/ops/dispatch_flatbuffers.rs
+++ b/cli/ops/dispatch_flatbuffers.rs
@@ -13,13 +13,11 @@ use super::files::{op_close, op_open, op_read, op_seek, op_write};
use super::fs::{
op_chdir, op_chmod, op_chown, op_copy_file, op_cwd, op_link,
op_make_temp_dir, op_mkdir, op_read_dir, op_read_link, op_remove, op_rename,
- op_stat, op_symlink, op_truncate, op_utime,
+ op_stat, op_symlink, op_truncate,
};
use super::metrics::op_metrics;
use super::net::{op_accept, op_dial, op_listen, op_shutdown};
-use super::os::{
- op_env, op_exec_path, op_exit, op_home_dir, op_is_tty, op_set_env, op_start,
-};
+use super::os::{op_home_dir, op_set_env, op_start};
use super::performance::op_now;
use super::permissions::{op_permissions, op_revoke_permission};
use super::process::{op_kill, op_run, op_run_status};
@@ -65,13 +63,8 @@ pub fn dispatch(
let op_result = op_func(state, &base, zero_copy);
- let state = state.clone();
-
match op_result {
- Ok(Op::Sync(buf)) => {
- state.metrics_op_completed(buf.len());
- Op::Sync(buf)
- }
+ Ok(Op::Sync(buf)) => Op::Sync(buf),
Ok(Op::Async(fut)) => {
let result_fut = Box::new(
fut
@@ -107,7 +100,6 @@ pub fn dispatch(
},
)
};
- state.metrics_op_completed(buf.len());
Ok(buf)
})
.map_err(|err| panic!("unexpected error {:?}", err)),
@@ -129,7 +121,6 @@ pub fn dispatch(
..Default::default()
},
);
- state.metrics_op_completed(response_buf.len());
Op::Sync(response_buf)
}
}
@@ -162,9 +153,6 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<CliDispatchFn> {
msg::Any::CreateWorker => Some(op_create_worker),
msg::Any::Cwd => Some(op_cwd),
msg::Any::Dial => Some(op_dial),
- msg::Any::Environ => Some(op_env),
- msg::Any::ExecPath => Some(op_exec_path),
- msg::Any::Exit => Some(op_exit),
msg::Any::Fetch => Some(op_fetch),
msg::Any::FetchSourceFile => Some(op_fetch_source_file),
msg::Any::FormatError => Some(op_format_error),
@@ -174,7 +162,6 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<CliDispatchFn> {
msg::Any::HostGetMessage => Some(op_host_get_message),
msg::Any::HostGetWorkerClosed => Some(op_host_get_worker_closed),
msg::Any::HostPostMessage => Some(op_host_post_message),
- msg::Any::IsTTY => Some(op_is_tty),
msg::Any::Kill => Some(op_kill),
msg::Any::Link => Some(op_link),
msg::Any::Listen => Some(op_listen),
@@ -203,7 +190,6 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<CliDispatchFn> {
msg::Any::Symlink => Some(op_symlink),
msg::Any::Truncate => Some(op_truncate),
msg::Any::HomeDir => Some(op_home_dir),
- msg::Any::Utime => Some(op_utime),
msg::Any::Write => Some(op_write),
// TODO(ry) split these out so that only the appropriate Workers can access
diff --git a/cli/ops/dispatch_json.rs b/cli/ops/dispatch_json.rs
new file mode 100644
index 000000000..a575aedb3
--- /dev/null
+++ b/cli/ops/dispatch_json.rs
@@ -0,0 +1,113 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+use crate::state::ThreadSafeState;
+use crate::tokio_util;
+use deno::*;
+use futures::Future;
+use futures::Poll;
+pub use serde_derive::Deserialize;
+use serde_json::json;
+pub use serde_json::Value;
+
+pub type AsyncJsonOp = Box<dyn Future<Item = Value, Error = ErrBox> + Send>;
+
+pub enum JsonOp {
+ Sync(Value),
+ Async(AsyncJsonOp),
+}
+
+fn json_err(err: ErrBox) -> Value {
+ use crate::deno_error::GetErrorKind;
+ json!({
+ "message": err.to_string(),
+ "kind": err.kind() as u32,
+ })
+}
+
+pub type Dispatcher = fn(
+ state: &ThreadSafeState,
+ args: Value,
+ zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox>;
+
+fn serialize_result(
+ promise_id: Option<u64>,
+ result: Result<Value, ErrBox>,
+) -> Buf {
+ let value = match result {
+ Ok(v) => json!({ "ok": v, "promiseId": promise_id }),
+ Err(err) => json!({ "err": json_err(err), "promiseId": promise_id }),
+ };
+ let vec = serde_json::to_vec(&value).unwrap();
+ vec.into_boxed_slice()
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct AsyncArgs {
+ promise_id: Option<u64>,
+}
+
+pub fn dispatch(
+ d: Dispatcher,
+ state: &ThreadSafeState,
+ control: &[u8],
+ zero_copy: Option<PinnedBuf>,
+) -> CoreOp {
+ let async_args: AsyncArgs = serde_json::from_slice(control).unwrap();
+ let promise_id = async_args.promise_id;
+ let is_sync = promise_id.is_none();
+
+ let result = serde_json::from_slice(control)
+ .map_err(ErrBox::from)
+ .and_then(move |args| d(state, args, zero_copy));
+ match result {
+ Ok(JsonOp::Sync(sync_value)) => {
+ assert!(promise_id.is_none());
+ CoreOp::Sync(serialize_result(promise_id, Ok(sync_value)))
+ }
+ Ok(JsonOp::Async(fut)) => {
+ assert!(promise_id.is_some());
+ let fut2 = Box::new(fut.then(move |result| -> Result<Buf, ()> {
+ Ok(serialize_result(promise_id, result))
+ }));
+ CoreOp::Async(fut2)
+ }
+ Err(sync_err) => {
+ let buf = serialize_result(promise_id, Err(sync_err));
+ if is_sync {
+ CoreOp::Sync(buf)
+ } else {
+ CoreOp::Async(Box::new(futures::future::ok(buf)))
+ }
+ }
+ }
+}
+
+// This is just type conversion. Implement From trait?
+// See https://github.com/tokio-rs/tokio/blob/ffd73a64e7ec497622b7f939e38017afe7124dc4/tokio-fs/src/lib.rs#L76-L85
+fn convert_blocking_json<F>(f: F) -> Poll<Value, ErrBox>
+where
+ F: FnOnce() -> Result<Value, ErrBox>,
+{
+ use futures::Async::*;
+ match tokio_threadpool::blocking(f) {
+ Ok(Ready(Ok(v))) => Ok(Ready(v)),
+ Ok(Ready(Err(err))) => Err(err),
+ Ok(NotReady) => Ok(NotReady),
+ Err(err) => panic!("blocking error {}", err),
+ }
+}
+
+pub fn blocking_json<F>(is_sync: bool, f: F) -> Result<JsonOp, ErrBox>
+where
+ F: 'static + Send + FnOnce() -> Result<Value, ErrBox>,
+{
+ if is_sync {
+ Ok(JsonOp::Sync(f()?))
+ } else {
+ Ok(JsonOp::Async(Box::new(futures::sync::oneshot::spawn(
+ tokio_util::poll_fn(move || convert_blocking_json(f)),
+ &tokio_executor::DefaultExecutor::current(),
+ ))))
+ }
+}
diff --git a/cli/ops/dispatch_minimal.rs b/cli/ops/dispatch_minimal.rs
index 37ad56813..22d0a92f8 100644
--- a/cli/ops/dispatch_minimal.rs
+++ b/cli/ops/dispatch_minimal.rs
@@ -74,19 +74,15 @@ fn test_parse_min_record() {
pub fn dispatch(
d: Dispatcher,
- state: &ThreadSafeState,
+ _state: &ThreadSafeState,
control: &[u8],
zero_copy: Option<PinnedBuf>,
) -> CoreOp {
let mut record = parse_min_record(control).unwrap();
let is_sync = record.promise_id == 0;
-
// TODO(ry) Currently there aren't any sync minimal ops. This is just a sanity
// check. Remove later.
assert!(!is_sync);
-
- let state = state.clone();
-
let rid = record.arg;
let min_op = d(rid, zero_copy);
@@ -102,10 +98,9 @@ pub fn dispatch(
record.result = -1;
}
}
- let buf: Buf = record.into();
- state.metrics_op_completed(buf.len());
- Ok(buf)
+ Ok(record.into())
}));
+
if is_sync {
Op::Sync(fut.wait().unwrap())
} else {
diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs
index d46ed91e1..f655e4e2d 100644
--- a/cli/ops/fs.rs
+++ b/cli/ops/fs.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use super::dispatch_flatbuffers::serialize_response;
+use super::dispatch_json::{blocking_json, Deserialize, JsonOp, Value};
use super::utils::*;
use crate::deno_error::DenoError;
use crate::deno_error::ErrorKind;
@@ -13,7 +14,6 @@ use std::convert::From;
use std::fs;
use std::path::PathBuf;
use std::time::UNIX_EPOCH;
-use utime;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
@@ -456,24 +456,27 @@ pub fn op_make_temp_dir(
})
}
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct Utime {
+ promise_id: Option<u64>,
+ filename: String,
+ atime: u64,
+ mtime: u64,
+}
+
pub fn op_utime(
state: &ThreadSafeState,
- base: &msg::Base<'_>,
- data: Option<PinnedBuf>,
-) -> CliOpResult {
- assert!(data.is_none());
-
- let inner = base.inner_as_utime().unwrap();
- let filename = String::from(inner.filename().unwrap());
- let atime = inner.atime();
- let mtime = inner.mtime();
-
- state.check_write(&filename)?;
-
- blocking(base.sync(), move || {
- debug!("op_utimes {} {} {}", filename, atime, mtime);
- utime::set_file_times(filename, atime, mtime)?;
- Ok(empty_buf())
+ args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ let args: Utime = serde_json::from_value(args)?;
+ state.check_write(&args.filename)?;
+ let is_sync = args.promise_id.is_none();
+ blocking_json(is_sync, move || {
+ debug!("op_utimes {} {} {}", args.filename, args.atime, args.mtime);
+ utime::set_file_times(args.filename, args.atime, args.mtime)?;
+ Ok(json!({}))
})
}
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs
index 92c0f8e62..240132960 100644
--- a/cli/ops/mod.rs
+++ b/cli/ops/mod.rs
@@ -4,6 +4,7 @@ use deno::*;
mod compiler;
mod dispatch_flatbuffers;
+mod dispatch_json;
mod dispatch_minimal;
mod errors;
mod fetch;
@@ -23,9 +24,16 @@ mod timers;
mod utils;
mod workers;
+// Warning! These values are duplicated in the TypeScript code (js/dispatch.ts),
+// update with care.
pub const OP_FLATBUFFER: OpId = 44;
pub const OP_READ: OpId = 1;
pub const OP_WRITE: OpId = 2;
+pub const OP_EXIT: OpId = 3;
+pub const OP_IS_TTY: OpId = 4;
+pub const OP_ENV: OpId = 5;
+pub const OP_EXEC_PATH: OpId = 6;
+pub const OP_UTIME: OpId = 7;
pub fn dispatch(
state: &ThreadSafeState,
@@ -43,10 +51,36 @@ pub fn dispatch(
OP_WRITE => {
dispatch_minimal::dispatch(io::op_write, state, control, zero_copy)
}
+ OP_EXIT => dispatch_json::dispatch(os::op_exit, state, control, zero_copy),
+ OP_IS_TTY => {
+ dispatch_json::dispatch(os::op_is_tty, state, control, zero_copy)
+ }
+ OP_ENV => dispatch_json::dispatch(os::op_env, state, control, zero_copy),
+ OP_EXEC_PATH => {
+ dispatch_json::dispatch(os::op_exec_path, state, control, zero_copy)
+ }
+ OP_UTIME => {
+ dispatch_json::dispatch(fs::op_utime, state, control, zero_copy)
+ }
OP_FLATBUFFER => dispatch_flatbuffers::dispatch(state, control, zero_copy),
_ => panic!("bad op_id"),
};
state.metrics_op_dispatched(bytes_sent_control, bytes_sent_zero_copy);
- op
+
+ match op {
+ Op::Sync(buf) => {
+ state.metrics_op_completed(buf.len());
+ Op::Sync(buf)
+ }
+ Op::Async(fut) => {
+ use crate::futures::Future;
+ let state = state.clone();
+ let result_fut = Box::new(fut.map(move |buf: Buf| {
+ state.clone().metrics_op_completed(buf.len());
+ buf
+ }));
+ Op::Async(result_fut)
+ }
+ }
}
diff --git a/cli/ops/os.rs b/cli/ops/os.rs
index fbf430d7a..53ef63c60 100644
--- a/cli/ops/os.rs
+++ b/cli/ops/os.rs
@@ -1,16 +1,18 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use super::dispatch_flatbuffers::serialize_response;
+use super::dispatch_json::{Deserialize, JsonOp, Value};
use super::utils::*;
use crate::ansi;
use crate::fs as deno_fs;
use crate::msg;
-use crate::msg_util;
use crate::state::ThreadSafeState;
use crate::version;
use atty;
use deno::*;
use flatbuffers::FlatBufferBuilder;
use log;
+use std::collections::HashMap;
+use std::env;
use url::Url;
pub fn op_start(
@@ -25,7 +27,7 @@ pub fn op_start(
let argv = state.argv.iter().map(String::as_str).collect::<Vec<_>>();
let argv_off = builder.create_vector_of_strings(argv.as_slice());
- let cwd_path = std::env::current_dir().unwrap();
+ let cwd_path = env::current_dir().unwrap();
let cwd_off =
builder.create_string(deno_fs::normalize_path(cwd_path.as_ref()).as_ref());
@@ -110,32 +112,16 @@ pub fn op_home_dir(
pub fn op_exec_path(
state: &ThreadSafeState,
- base: &msg::Base<'_>,
- data: Option<PinnedBuf>,
-) -> CliOpResult {
- assert!(data.is_none());
- let cmd_id = base.cmd_id();
-
+ _args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
state.check_env()?;
-
- let builder = &mut FlatBufferBuilder::new();
- let current_exe = std::env::current_exe().unwrap();
- // Now apply URL parser to current exe to get fully resolved path, otherwise we might get
- // `./` and `../` bits in `exec_path`
+ let current_exe = env::current_exe().unwrap();
+ // Now apply URL parser to current exe to get fully resolved path, otherwise
+ // we might get `./` and `../` bits in `exec_path`
let exe_url = Url::from_file_path(current_exe).unwrap();
- let path = exe_url.to_file_path().unwrap().to_str().unwrap().to_owned();
- let path = Some(builder.create_string(&path));
- let inner = msg::ExecPathRes::create(builder, &msg::ExecPathResArgs { path });
-
- ok_buf(serialize_response(
- cmd_id,
- builder,
- msg::BaseArgs {
- inner: Some(inner.as_union_value()),
- inner_type: msg::Any::ExecPathRes,
- ..Default::default()
- },
- ))
+ let path = exe_url.to_file_path().unwrap();
+ Ok(JsonOp::Sync(json!(path)))
}
pub fn op_set_env(
@@ -148,71 +134,42 @@ pub fn op_set_env(
let key = inner.key().unwrap();
let value = inner.value().unwrap();
state.check_env()?;
- std::env::set_var(key, value);
+ env::set_var(key, value);
ok_buf(empty_buf())
}
pub fn op_env(
state: &ThreadSafeState,
- base: &msg::Base<'_>,
- data: Option<PinnedBuf>,
-) -> CliOpResult {
- assert!(data.is_none());
- let cmd_id = base.cmd_id();
-
+ _args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
state.check_env()?;
+ let v = env::vars().collect::<HashMap<String, String>>();
+ Ok(JsonOp::Sync(json!(v)))
+}
- let builder = &mut FlatBufferBuilder::new();
- let vars: Vec<_> = std::env::vars()
- .map(|(key, value)| msg_util::serialize_key_value(builder, &key, &value))
- .collect();
- let tables = builder.create_vector(&vars);
- let inner = msg::EnvironRes::create(
- builder,
- &msg::EnvironResArgs { map: Some(tables) },
- );
- let response_buf = serialize_response(
- cmd_id,
- builder,
- msg::BaseArgs {
- inner: Some(inner.as_union_value()),
- inner_type: msg::Any::EnvironRes,
- ..Default::default()
- },
- );
- ok_buf(response_buf)
+#[derive(Deserialize)]
+struct Exit {
+ code: i32,
}
pub fn op_exit(
- _state: &ThreadSafeState,
- base: &msg::Base<'_>,
- _data: Option<PinnedBuf>,
-) -> CliOpResult {
- let inner = base.inner_as_exit().unwrap();
- std::process::exit(inner.code())
+ _s: &ThreadSafeState,
+ args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ let args: Exit = serde_json::from_value(args)?;
+ std::process::exit(args.code)
}
pub fn op_is_tty(
- _state: &ThreadSafeState,
- base: &msg::Base<'_>,
- _data: Option<PinnedBuf>,
-) -> CliOpResult {
- let builder = &mut FlatBufferBuilder::new();
- let inner = msg::IsTTYRes::create(
- builder,
- &msg::IsTTYResArgs {
- stdin: atty::is(atty::Stream::Stdin),
- stdout: atty::is(atty::Stream::Stdout),
- stderr: atty::is(atty::Stream::Stderr),
- },
- );
- ok_buf(serialize_response(
- base.cmd_id(),
- builder,
- msg::BaseArgs {
- inner: Some(inner.as_union_value()),
- inner_type: msg::Any::IsTTYRes,
- ..Default::default()
- },
- ))
+ _s: &ThreadSafeState,
+ _args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ Ok(JsonOp::Sync(json!({
+ "stdin": atty::is(atty::Stream::Stdin),
+ "stdout": atty::is(atty::Stream::Stdout),
+ "stderr": atty::is(atty::Stream::Stderr),
+ })))
}
diff --git a/cli/ops/utils.rs b/cli/ops/utils.rs
index a9b0b442c..95b13b77a 100644
--- a/cli/ops/utils.rs
+++ b/cli/ops/utils.rs
@@ -19,7 +19,7 @@ pub fn empty_buf() -> Buf {
// This is just type conversion. Implement From trait?
// See https://github.com/tokio-rs/tokio/blob/ffd73a64e7ec497622b7f939e38017afe7124dc4/tokio-fs/src/lib.rs#L76-L85
-fn convert_blocking<F>(f: F) -> Poll<Buf, ErrBox>
+pub fn convert_blocking<F>(f: F) -> Poll<Buf, ErrBox>
where
F: FnOnce() -> Result<Buf, ErrBox>,
{