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

Large diffs are not rendered by default.

@@ -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;

@@ -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);
}

This comment has been minimized.

Copy link
@bartlomieju

bartlomieju Apr 20, 2019

Author Contributor

@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);
}
}
}
@@ -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),
@@ -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(
@@ -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);
@@ -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);
@@ -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();
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.