Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor CLI entry point #2157

Merged
merged 14 commits into from
Apr 21, 2019
460 changes: 212 additions & 248 deletions cli/flags.rs

Large diffs are not rendered by default.

278 changes: 193 additions & 85 deletions cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ use crate::errors::RustOrJsError;
use crate::state::ThreadSafeState;
use crate::worker::root_specifier_to_url;
use crate::worker::Worker;
use deno::v8_set_flags;
use flags::DenoFlags;
use futures::lazy;
use futures::Future;
use log::{LevelFilter, Metadata, Record};
use std::env;
use std::path::Path;

static LOGGER: Logger = Logger;

Expand Down Expand Up @@ -123,103 +126,208 @@ pub fn print_file_info(worker: &Worker, url: &str) {
}
}

fn main() {
#[cfg(windows)]
ansi_term::enable_ansi_support().ok(); // For Windows 10
fn create_worker_and_state(
flags: DenoFlags,
argv: Vec<String>,
) -> (Worker, ThreadSafeState) {
let state = ThreadSafeState::new(flags, argv, ops::op_selector_std);
let worker = Worker::new(
"main".to_string(),
startup_data::deno_isolate_init(),
state.clone(),
);

log::set_logger(&LOGGER).unwrap();
let args = env::args().collect();
let (mut flags, mut rest_argv) =
flags::set_flags(args).unwrap_or_else(|err| {
eprintln!("{}", err);
std::process::exit(1)
});
(worker, state)
}

log::set_max_level(if flags.log_debug {
LevelFilter::Debug
} else {
LevelFilter::Warn
});
fn types_command() {
let p = Path::new(concat!(
env!("GN_OUT_DIR"),
"/gen/cli/lib/lib.deno_runtime.d.ts"
));
let content_bytes = std::fs::read(p).unwrap();
let content = std::str::from_utf8(&content_bytes[..]).unwrap();
println!("{}", content);
}

if flags.fmt {
rest_argv.insert(1, "https://deno.land/std/prettier/main.ts".to_string());
flags.allow_read = true;
flags.allow_write = true;
}
fn prefetch_or_info_command(
flags: DenoFlags,
argv: Vec<String>,
print_info: bool,
) {
let (mut worker, state) = create_worker_and_state(flags, argv);

let should_prefetch = flags.prefetch || flags.info;
let should_display_info = flags.info;
let main_module = state.main_module().unwrap();
let main_future = lazy(move || {
// Setup runtime.
js_check(worker.execute("denoMain()"));
debug!("main_module {}", main_module);

let state = ThreadSafeState::new(flags, rest_argv, ops::op_selector_std);
let mut worker = Worker::new(
"main".to_string(),
startup_data::deno_isolate_init(),
state.clone(),
let main_url = root_specifier_to_url(&main_module).unwrap();

worker
.execute_mod_async(&main_url, true)
.and_then(move |worker| {
if print_info {
print_file_info(&worker, &main_module);
}
worker.then(|result| {
js_check(result);
Ok(())
})
}).map_err(|(err, _worker)| print_err_and_exit(err))
});
tokio_util::run(main_future);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ry PTAL at it. It seem that execute_mod_async does not evaluate and run file if prefetch is set to true, so simple letting worker finish the job seems to work fine. I'm not sure though


fn eval_command(flags: DenoFlags, argv: Vec<String>) {
let (mut worker, state) = create_worker_and_state(flags, argv);
// Wrap provided script in async function so asynchronous methods
// work. This is required until top-level await is not supported.
let js_source = format!(
"async function _topLevelWrapper(){{
{}
}}
_topLevelWrapper();
",
&state.argv[1]
);

// TODO(ry) somehow combine the two branches below. They're very similar but
// it's difficult to get the types to workout.

if state.flags.eval {
let main_future = lazy(move || {
js_check(worker.execute("denoMain()"));
// Wrap provided script in async function so asynchronous methods
// work. This is required until top-level await is not supported.
let js_source = format!(
"async function _topLevelWrapper(){{
{}
}}
_topLevelWrapper();
",
&state.argv[1]
);
// ATM imports in `deno eval` are not allowed
// TODO Support ES modules once Worker supports evaluating anonymous modules.
js_check(worker.execute(&js_source));
worker.then(|result| {
let main_future = lazy(move || {
js_check(worker.execute("denoMain()"));
// ATM imports in `deno eval` are not allowed
// TODO Support ES modules once Worker supports evaluating anonymous modules.
js_check(worker.execute(&js_source));
worker.then(|result| {
js_check(result);
Ok(())
})
});
tokio_util::run(main_future);
}

fn run_repl(flags: DenoFlags, argv: Vec<String>) {
let (mut worker, _state) = create_worker_and_state(flags, argv);

// REPL situation.
let main_future = lazy(move || {
// Setup runtime.
js_check(worker.execute("denoMain()"));
worker
.then(|result| {
js_check(result);
Ok(())
}).map_err(|(err, _worker): (RustOrJsError, Worker)| {
print_err_and_exit(err)
})
});
tokio_util::run(main_future);
} else if let Some(main_module) = state.main_module() {
// Normal situation of executing a module.

let main_future = lazy(move || {
// Setup runtime.
js_check(worker.execute("denoMain()"));
debug!("main_module {}", main_module);

let main_url = root_specifier_to_url(&main_module).unwrap();

worker
.execute_mod_async(&main_url, should_prefetch)
.and_then(move |worker| {
if should_display_info {
// Display file info and exit. Do not run file
print_file_info(&worker, &main_module);
std::process::exit(0);
}
worker.then(|result| {
js_check(result);
Ok(())
})
}).map_err(|(err, _worker)| print_err_and_exit(err))
});
tokio_util::run(main_future);
} else {
// REPL situation.
let main_future = lazy(move || {
// Setup runtime.
js_check(worker.execute("denoMain()"));
worker
.then(|result| {
});
tokio_util::run(main_future);
}

fn run_script(flags: DenoFlags, argv: Vec<String>) {
let (mut worker, state) = create_worker_and_state(flags, argv);

let main_module = state.main_module().unwrap();
// Normal situation of executing a module.
let main_future = lazy(move || {
// Setup runtime.
js_check(worker.execute("denoMain()"));
debug!("main_module {}", main_module);

let main_url = root_specifier_to_url(&main_module).unwrap();

worker
.execute_mod_async(&main_url, false)
.and_then(move |worker| {
worker.then(|result| {
js_check(result);
Ok(())
}).map_err(|(err, _worker): (RustOrJsError, Worker)| {
print_err_and_exit(err)
})
});
tokio_util::run(main_future);
}).map_err(|(err, _worker)| print_err_and_exit(err))
});
tokio_util::run(main_future);
}

fn fmt_command(mut flags: DenoFlags, mut argv: Vec<String>) {
argv.insert(1, "https://deno.land/std/prettier/main.ts".to_string());
flags.allow_read = true;
flags.allow_write = true;
run_script(flags, argv);
}

fn main() {
#[cfg(windows)]
ansi_term::enable_ansi_support().ok(); // For Windows 10

log::set_logger(&LOGGER).unwrap();
let args: Vec<String> = env::args().collect();
let cli_app = flags::create_cli_app();
let matches = cli_app.get_matches_from(args);
let flags = flags::parse_flags(matches.clone());
let mut argv: Vec<String> = vec!["deno".to_string()];

if flags.v8_help {
// show v8 help and exit
v8_set_flags(vec!["--help".to_string()]);
}

match &flags.v8_flags {
Some(v8_flags) => {
v8_set_flags(v8_flags.clone());
}
_ => {}
};

log::set_max_level(if flags.log_debug {
LevelFilter::Debug
} else {
LevelFilter::Warn
});

match matches.subcommand() {
("types", Some(_)) => {
types_command();
}
("eval", Some(eval_match)) => {
let code: &str = eval_match.value_of("code").unwrap();
argv.extend(vec![code.to_string()]);
eval_command(flags, argv);
}
("info", Some(info_match)) => {
let file: &str = info_match.value_of("file").unwrap();
argv.extend(vec![file.to_string()]);
prefetch_or_info_command(flags, argv, true);
}
("prefetch", Some(prefetch_match)) => {
let file: &str = prefetch_match.value_of("file").unwrap();
argv.extend(vec![file.to_string()]);
prefetch_or_info_command(flags, argv, false);
}
("fmt", Some(fmt_match)) => {
let files: Vec<String> = fmt_match
.values_of("files")
.unwrap()
.map(String::from)
.collect();
argv.extend(files);
fmt_command(flags, argv);
}
(script, Some(script_match)) => {
argv.extend(vec![script.to_string()]);
// check if there are any extra arguments that should
// be passed to script
if script_match.is_present("") {
let script_args: Vec<String> = script_match
.values_of("")
.unwrap()
.map(String::from)
.collect();
argv.extend(script_args);
}
run_script(flags, argv);
}
_ => {
run_repl(flags, argv);
}
}
}
1 change: 0 additions & 1 deletion cli/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ fn op_start(
argv: Some(argv_off),
main_module,
debug_flag: state.flags.log_debug,
types_flag: state.flags.types,
version_flag: state.flags.version,
v8_version: Some(v8_version_off),
deno_version: Some(deno_version_off),
Expand Down
8 changes: 5 additions & 3 deletions cli/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,11 @@ impl ThreadSafeState {
#[cfg(test)]
pub fn mock() -> ThreadSafeState {
let argv = vec![String::from("./deno"), String::from("hello.js")];
// For debugging: argv.push_back(String::from("-D"));
let (flags, rest_argv) = flags::set_flags(argv).unwrap();
ThreadSafeState::new(flags, rest_argv, ops::op_selector_std)
ThreadSafeState::new(
flags::DenoFlags::default(),
argv,
ops::op_selector_std,
)
}

pub fn metrics_op_dispatched(
Expand Down
10 changes: 4 additions & 6 deletions cli/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,8 @@ mod tests {
let js_url = Url::from_file_path(filename).unwrap();

let argv = vec![String::from("./deno"), js_url.to_string()];
let (flags, rest_argv) = flags::set_flags(argv).unwrap();

let state = ThreadSafeState::new(flags, rest_argv, op_selector_std);
let state =
ThreadSafeState::new(flags::DenoFlags::default(), argv, op_selector_std);
let state_ = state.clone();
tokio_util::run(lazy(move || {
let worker = Worker::new("TEST".to_string(), StartupData::None, state);
Expand All @@ -294,9 +293,8 @@ mod tests {
let js_url = Url::from_file_path(filename).unwrap();

let argv = vec![String::from("./deno"), js_url.to_string()];
let (flags, rest_argv) = flags::set_flags(argv).unwrap();

let state = ThreadSafeState::new(flags, rest_argv, op_selector_std);
let state =
ThreadSafeState::new(flags::DenoFlags::default(), argv, op_selector_std);
let state_ = state.clone();
tokio_util::run(lazy(move || {
let worker = Worker::new("TEST".to_string(), StartupData::None, state);
Expand Down
1 change: 1 addition & 0 deletions core/examples/http_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ fn main() {
});

let args: Vec<String> = env::args().collect();
// NOTE: `--help` arg will display V8 help and exit
let args = deno::v8_set_flags(args);

log::set_logger(&LOGGER).unwrap();
Expand Down
Loading