summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2020-02-18 10:08:18 -0500
committerGitHub <noreply@github.com>2020-02-18 10:08:18 -0500
commit302debebb3a3b765b3d13f3244eb4625d7d610c2 (patch)
treed54b4d01f391f7396e8f1c92dc2e05c82acc2a8c
parent5a3292047c42b8a65d164f127fc57e57046fadf7 (diff)
refactor: cleanup cli/lib.rs (#4006)
* rename methods on Worker related to module loading * reorganize cli/lib.rs * remove cli/progress.rs and cli/shell.rs
-rw-r--r--cli/colors.rs8
-rw-r--r--cli/compilers/ts.rs13
-rw-r--r--cli/file_fetcher.rs21
-rw-r--r--cli/global_state.rs17
-rw-r--r--cli/lib.rs367
-rw-r--r--cli/ops/worker_host.rs4
-rw-r--r--cli/progress.rs168
-rw-r--r--cli/shell.rs285
-rw-r--r--cli/worker.rs56
-rw-r--r--core/es_isolate.rs9
-rw-r--r--core/modules.rs21
11 files changed, 229 insertions, 740 deletions
diff --git a/cli/colors.rs b/cli/colors.rs
index f792e2b33..0bf048943 100644
--- a/cli/colors.rs
+++ b/cli/colors.rs
@@ -78,6 +78,14 @@ pub fn red(s: String) -> impl fmt::Display {
style.paint(s)
}
+pub fn green(s: String) -> impl fmt::Display {
+ let mut style = Style::new();
+ if use_color() {
+ style = style.fg(Fixed(10)).bold();
+ }
+ style.paint(s)
+}
+
pub fn bold(s: String) -> impl fmt::Display {
let mut style = Style::new();
if use_color() {
diff --git a/cli/compilers/ts.rs b/cli/compilers/ts.rs
index a6ed8237d..9bfd93eeb 100644
--- a/cli/compilers/ts.rs
+++ b/cli/compilers/ts.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use super::compiler_worker::CompilerWorker;
+use crate::colors;
use crate::compilers::CompilationResultFuture;
use crate::compilers::CompiledModule;
use crate::diagnostics::Diagnostic;
@@ -372,18 +373,18 @@ impl TsCompiler {
let ts_compiler = self.clone();
- let compiling_job = global_state
- .progress
- .add("Compile", &module_url.to_string());
+ eprintln!(
+ "{} {}",
+ colors::green("Compile".to_string()),
+ module_url.to_string()
+ );
let msg = execute_in_thread(global_state.clone(), req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
return Err(ErrBox::from(diagnostics));
}
- let compiled_module = ts_compiler.get_compiled_module(&source_file_.url)?;
- drop(compiling_job);
- Ok(compiled_module)
+ ts_compiler.get_compiled_module(&source_file_.url)
}
/// Get associated `CompiledFileMetadata` for given module if it exists.
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs
index e69756b20..75774ed5b 100644
--- a/cli/file_fetcher.rs
+++ b/cli/file_fetcher.rs
@@ -1,4 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+use crate::colors;
use crate::deno_error::DenoError;
use crate::deno_error::ErrorKind;
use crate::deno_error::GetErrorKind;
@@ -8,7 +9,6 @@ use crate::http_util::create_http_client;
use crate::http_util::FetchOnceResult;
use crate::http_util::ResultPayload;
use crate::msg;
-use crate::progress::Progress;
use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use futures::future::Either;
@@ -95,7 +95,6 @@ const SUPPORTED_URL_SCHEMES: [&str; 3] = ["http", "https", "file"];
#[derive(Clone)]
pub struct SourceFileFetcher {
deps_cache: DiskCache,
- progress: Progress,
source_file_cache: SourceFileCache,
cache_blacklist: Vec<String>,
use_disk_cache: bool,
@@ -107,7 +106,6 @@ pub struct SourceFileFetcher {
impl SourceFileFetcher {
pub fn new(
deps_cache: DiskCache,
- progress: Progress,
use_disk_cache: bool,
cache_blacklist: Vec<String>,
no_remote: bool,
@@ -116,7 +114,6 @@ impl SourceFileFetcher {
) -> Result<Self, ErrBox> {
let file_fetcher = Self {
deps_cache,
- progress,
source_file_cache: SourceFileCache::default(),
cache_blacklist,
use_disk_cache,
@@ -441,7 +438,11 @@ impl SourceFileFetcher {
.boxed();
}
- let download_job = self.progress.add("Download", &module_url.to_string());
+ eprintln!(
+ "{} {}",
+ colors::green("Download".to_string()),
+ module_url.to_string()
+ );
let dir = self.clone();
let module_url = module_url.clone();
let headers = self.get_source_code_headers(&module_url);
@@ -455,9 +456,6 @@ impl SourceFileFetcher {
let source_file =
dir.fetch_cached_remote_source(&module_url)?.unwrap();
- // Explicit drop to keep reference alive until future completes.
- drop(download_job);
-
Ok(source_file)
}
FetchOnceResult::Redirect(new_module_url) => {
@@ -475,9 +473,6 @@ impl SourceFileFetcher {
));
}
- // Explicit drop to keep reference alive until future completes.
- drop(download_job);
-
// Recurse
dir
.fetch_remote_source_async(
@@ -542,9 +537,6 @@ impl SourceFileFetcher {
types_url,
};
- // Explicit drop to keep reference alive until future completes.
- drop(download_job);
-
Ok(source_file)
}
}
@@ -858,7 +850,6 @@ mod tests {
fn setup_file_fetcher(dir_path: &Path) -> SourceFileFetcher {
SourceFileFetcher::new(
DiskCache::new(&dir_path.to_path_buf().join("deps")),
- Progress::new(),
true,
vec![],
false,
diff --git a/cli/global_state.rs b/cli/global_state.rs
index a11900218..1d7a3a40f 100644
--- a/cli/global_state.rs
+++ b/cli/global_state.rs
@@ -12,8 +12,6 @@ use crate::flags;
use crate::lockfile::Lockfile;
use crate::msg;
use crate::permissions::DenoPermissions;
-use crate::progress::Progress;
-use crate::shell::Shell;
use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use std;
@@ -39,7 +37,6 @@ pub struct GlobalStateInner {
/// Permissions parsed from `flags`.
pub permissions: DenoPermissions,
pub dir: deno_dir::DenoDir,
- pub progress: Progress,
pub file_fetcher: SourceFileFetcher,
pub js_compiler: JsCompiler,
pub json_compiler: JsonCompiler,
@@ -62,21 +59,8 @@ impl GlobalState {
let custom_root = env::var("DENO_DIR").map(String::into).ok();
let dir = deno_dir::DenoDir::new(custom_root)?;
- // TODO(ry) Shell is a useless abstraction and should be removed at
- // some point.
- let shell = Arc::new(Mutex::new(Shell::new()));
-
- let progress = Progress::new();
- progress.set_callback(move |_done, _completed, _total, status, msg| {
- if !status.is_empty() {
- let mut s = shell.lock().unwrap();
- s.status(status, msg).expect("shell problem");
- }
- });
-
let file_fetcher = SourceFileFetcher::new(
dir.deps_cache.clone(),
- progress.clone(),
!flags.reload,
flags.cache_blacklist.clone(),
flags.no_remote,
@@ -102,7 +86,6 @@ impl GlobalState {
dir,
permissions: DenoPermissions::from_flags(&flags),
flags,
- progress,
file_fetcher,
ts_compiler,
js_compiler: JsCompiler {},
diff --git a/cli/lib.rs b/cli/lib.rs
index 81fd8810e..7737d1741 100644
--- a/cli/lib.rs
+++ b/cli/lib.rs
@@ -42,10 +42,8 @@ mod metrics;
pub mod msg;
pub mod ops;
pub mod permissions;
-mod progress;
mod repl;
pub mod resolve_addr;
-mod shell;
pub mod signal;
pub mod source_maps;
mod startup_data;
@@ -58,8 +56,6 @@ mod web_worker;
pub mod worker;
use crate::compilers::TargetLib;
-use crate::deno_error::js_check;
-use crate::deno_error::{print_err_and_exit, print_msg_and_exit};
use crate::fs as deno_fs;
use crate::global_state::GlobalState;
use crate::ops::io::get_stdio;
@@ -70,12 +66,15 @@ use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use flags::DenoFlags;
use flags::DenoSubcommand;
+use futures::future::FutureExt;
use log::Level;
use log::Metadata;
use log::Record;
use std::env;
use std::fs as std_fs;
+use std::io::Write;
use std::path::PathBuf;
+use url::Url;
static LOGGER: Logger = Logger;
@@ -101,42 +100,27 @@ impl log::Log for Logger {
fn flush(&self) {}
}
-fn create_global_state(flags: DenoFlags) -> GlobalState {
- GlobalState::new(flags)
- .map_err(deno_error::print_err_and_exit)
- .unwrap()
-}
-
fn create_main_worker(
global_state: GlobalState,
main_module: ModuleSpecifier,
-) -> MainWorker {
- let state = State::new(global_state, None, main_module)
- .map_err(deno_error::print_err_and_exit)
- .unwrap();
+) -> Result<MainWorker, ErrBox> {
+ let state = State::new(global_state, None, main_module)?;
- let state_ = state.clone();
{
- let mut state = state_.borrow_mut();
+ let mut s = state.borrow_mut();
let (stdin, stdout, stderr) = get_stdio();
- state.resource_table.add("stdin", Box::new(stdin));
- state.resource_table.add("stdout", Box::new(stdout));
- state.resource_table.add("stderr", Box::new(stderr));
+ s.resource_table.add("stdin", Box::new(stdin));
+ s.resource_table.add("stdout", Box::new(stdout));
+ s.resource_table.add("stderr", Box::new(stderr));
}
- MainWorker::new("main".to_string(), startup_data::deno_isolate_init(), state)
-}
-
-fn types_command() {
- let types = format!(
- "{}\n{}\n{}",
- crate::js::DENO_NS_LIB,
- crate::js::SHARED_GLOBALS_LIB,
- crate::js::WINDOW_LIB
+ let mut worker = MainWorker::new(
+ "main".to_string(),
+ startup_data::deno_isolate_init(),
+ state,
);
- use std::io::Write;
- let _r = std::io::stdout().write_all(types.as_bytes());
- // TODO(ry) Only ignore SIGPIPE. Currently ignoring all errors.
+ worker.execute("bootstrapMainRuntime()")?;
+ Ok(worker)
}
fn print_cache_info(state: &GlobalState) {
@@ -157,21 +141,19 @@ fn print_cache_info(state: &GlobalState) {
);
}
+// TODO(bartlomieju): this function de facto repeats
+// whole compilation stack. Can this be done better somehow?
async fn print_file_info(
worker: &MainWorker,
module_specifier: ModuleSpecifier,
-) {
+) -> Result<(), ErrBox> {
let global_state = worker.state.borrow().global_state.clone();
- let maybe_source_file = global_state
+ let out = global_state
.file_fetcher
.fetch_source_file_async(&module_specifier, None)
- .await;
- if let Err(err) = maybe_source_file {
- println!("{}", err);
- return;
- }
- let out = maybe_source_file.unwrap();
+ .await?;
+
println!(
"{} {}",
colors::bold("local:".to_string()),
@@ -185,15 +167,11 @@ async fn print_file_info(
);
let module_specifier_ = module_specifier.clone();
- let maybe_compiled = global_state
+ global_state
.clone()
.fetch_compiled_module(module_specifier_, None, TargetLib::Main)
- .await;
- if let Err(e) = maybe_compiled {
- debug!("compiler error exiting!");
- eprintln!("\n{}", e.to_string());
- std::process::exit(1);
- }
+ .await?;
+
if out.media_type == msg::MediaType::TypeScript
|| (out.media_type == msg::MediaType::JavaScript
&& global_state.ts_compiler.compile_js)
@@ -235,29 +213,25 @@ async fn print_file_info(
colors::bold("deps:".to_string()),
);
}
+
+ Ok(())
}
-async fn info_command(flags: DenoFlags, file: Option<String>) {
- let global_state = create_global_state(flags);
+async fn info_command(
+ flags: DenoFlags,
+ file: Option<String>,
+) -> Result<(), ErrBox> {
+ let global_state = GlobalState::new(flags)?;
// If it was just "deno info" print location of caches and exit
if file.is_none() {
- return print_cache_info(&global_state);
+ print_cache_info(&global_state);
+ return Ok(());
}
- // Setup runtime.
- let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())
- .expect("Bad specifier");
- let mut worker = create_main_worker(global_state, main_module.clone());
- // TODO(bartlomieju): not needed?
- js_check(worker.execute("bootstrapMainRuntime()"));
-
- let main_result = worker.execute_mod_async(&main_module, None, true).await;
- if let Err(e) = main_result {
- print_err_and_exit(e);
- }
- print_file_info(&worker, main_module.clone()).await;
- let result = (&mut *worker).await;
- js_check(result);
+ let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
+ let mut worker = create_main_worker(global_state, main_module.clone())?;
+ worker.preload_module(&main_module).await?;
+ print_file_info(&worker, main_module.clone()).await
}
async fn install_command(
@@ -267,199 +241,149 @@ async fn install_command(
module_url: String,
args: Vec<String>,
force: bool,
-) {
- // Firstly fetch and compile module, this
- // ensures the module exists.
+) -> Result<(), ErrBox> {
+ // Firstly fetch and compile module, this step ensures that module exists.
let mut fetch_flags = flags.clone();
fetch_flags.reload = true;
- fetch_command(fetch_flags, vec![module_url.to_string()]).await;
-
- let install_result =
- installer::install(flags, dir, &exe_name, &module_url, args, force);
- if let Err(e) = install_result {
- print_msg_and_exit(&e.to_string());
- }
+ let global_state = GlobalState::new(fetch_flags)?;
+ let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?;
+ let mut worker = create_main_worker(global_state, main_module.clone())?;
+ worker.preload_module(&main_module).await?;
+ installer::install(flags, dir, &exe_name, &module_url, args, force)
+ .map_err(ErrBox::from)
}
-async fn fetch_command(flags: DenoFlags, files: Vec<String>) {
+async fn fetch_command(
+ flags: DenoFlags,
+ files: Vec<String>,
+) -> Result<(), ErrBox> {
let main_module =
ModuleSpecifier::resolve_url_or_path("./__$deno$fetch.ts").unwrap();
- let global_state = create_global_state(flags);
+ let global_state = GlobalState::new(flags)?;
let mut worker =
- create_main_worker(global_state.clone(), main_module.clone());
-
- // TODO(bartlomieju): not needed?
- js_check(worker.execute("bootstrapMainRuntime()"));
+ create_main_worker(global_state.clone(), main_module.clone())?;
for file in files {
- let specifier = ModuleSpecifier::resolve_url_or_path(&file).unwrap();
- let result = worker.execute_mod_async(&specifier, None, true).await;
- js_check(result);
+ let specifier = ModuleSpecifier::resolve_url_or_path(&file)?;
+ worker.preload_module(&specifier).await.map(|_| ())?;
}
if global_state.flags.lock_write {
if let Some(ref lockfile) = global_state.lockfile {
let g = lockfile.lock().unwrap();
- if let Err(e) = g.write() {
- print_err_and_exit(ErrBox::from(e));
- }
+ g.write()?;
} else {
eprintln!("--lock flag must be specified when using --lock-write");
std::process::exit(11);
}
}
+
+ Ok(())
}
-async fn eval_command(flags: DenoFlags, code: String) {
+async fn eval_command(flags: DenoFlags, code: String) -> Result<(), ErrBox> {
// Force TypeScript compile.
let main_module =
ModuleSpecifier::resolve_url_or_path("./__$deno$eval.ts").unwrap();
- let global_state = create_global_state(flags);
- let mut worker = create_main_worker(global_state, main_module.clone());
-
- js_check(worker.execute("bootstrapMainRuntime()"));
+ let global_state = GlobalState::new(flags)?;
+ let mut worker = create_main_worker(global_state, main_module.clone())?;
debug!("main_module {}", &main_module);
-
- let exec_result = worker
- .execute_mod_async(&main_module, Some(code), false)
- .await;
- if let Err(e) = exec_result {
- print_err_and_exit(e);
- }
- js_check(worker.execute("window.dispatchEvent(new Event('load'))"));
- let result = (&mut *worker).await;
- js_check(result);
- js_check(worker.execute("window.dispatchEvent(new Event('unload'))"));
+ worker.execute_module_from_code(&main_module, code).await?;
+ worker.execute("window.dispatchEvent(new Event('load'))")?;
+ (&mut *worker).await?;
+ worker.execute("window.dispatchEvent(new Event('unload'))")?;
+ Ok(())
}
async fn bundle_command(
flags: DenoFlags,
source_file: String,
out_file: Option<PathBuf>,
-) {
+) -> Result<(), ErrBox> {
+ let module_name = ModuleSpecifier::resolve_url_or_path(&source_file)?;
+ let global_state = GlobalState::new(flags)?;
debug!(">>>>> bundle_async START");
- let source_file_specifier =
- ModuleSpecifier::resolve_url_or_path(&source_file).expect("Bad specifier");
- let global_state = create_global_state(flags);
- let mut worker =
- create_main_worker(global_state.clone(), source_file_specifier.clone());
-
- // NOTE: we need to poll `worker` otherwise TS compiler worker won't run properly
- let result = (&mut *worker).await;
- js_check(result);
let bundle_result = global_state
.ts_compiler
- .bundle_async(
- global_state.clone(),
- source_file_specifier.to_string(),
- out_file,
- )
+ .bundle_async(global_state.clone(), module_name.to_string(), out_file)
.await;
- if let Err(err) = bundle_result {
- debug!("diagnostics returned, exiting!");
- eprintln!("");
- print_err_and_exit(err);
- }
debug!(">>>>> bundle_async END");
+ bundle_result
}
-async fn run_repl(flags: DenoFlags) {
+async fn run_repl(flags: DenoFlags) -> Result<(), ErrBox> {
let main_module =
ModuleSpecifier::resolve_url_or_path("./__$deno$repl.ts").unwrap();
- let global_state = create_global_state(flags);
- let mut worker = create_main_worker(global_state, main_module);
- js_check(worker.execute("bootstrapMainRuntime()"));
+ let global_state = GlobalState::new(flags)?;
+ let mut worker = create_main_worker(global_state, main_module)?;
loop {
- let result = (&mut *worker).await;
- if let Err(err) = result {
- eprintln!("{}", err.to_string());
- }
+ (&mut *worker).await?;
}
}
-async fn run_command(flags: DenoFlags, script: String) {
- let global_state = create_global_state(flags.clone());
- let result = run_script(global_state.clone(), script).await;
- if let Err(err) = result {
- print_err_and_exit(err);
- }
+async fn run_command(flags: DenoFlags, script: String) -> Result<(), ErrBox> {
+ let global_state = GlobalState::new(flags.clone())?;
+ let main_module = ModuleSpecifier::resolve_url_or_path(&script).unwrap();
+ let mut worker =
+ create_main_worker(global_state.clone(), main_module.clone())?;
+ debug!("main_module {}", main_module);
+ worker.execute_module(&main_module).await?;
+ worker.execute("window.dispatchEvent(new Event('load'))")?;
+ (&mut *worker).await?;
+ worker.execute("window.dispatchEvent(new Event('unload'))")?;
if global_state.flags.lock_write {
if let Some(ref lockfile) = global_state.lockfile {
let g = lockfile.lock().unwrap();
- if let Err(e) = g.write() {
- print_err_and_exit(ErrBox::from(e));
- }
+ g.write()?;
} else {
eprintln!("--lock flag must be specified when using --lock-write");
std::process::exit(11);
}
}
-}
-
-async fn run_script(
- global_state: GlobalState,
- script: String,
-) -> Result<(), ErrBox> {
- let main_module = ModuleSpecifier::resolve_url_or_path(&script).unwrap();
- let mut worker =
- create_main_worker(global_state.clone(), main_module.clone());
- // Setup runtime.
- worker.execute("bootstrapMainRuntime()")?;
- debug!("main_module {}", main_module);
- worker.execute_mod_async(&main_module, None, false).await?;
- worker.execute("window.dispatchEvent(new Event('load'))")?;
- (&mut *worker).await?;
- worker.execute("window.dispatchEvent(new Event('unload'))")?;
Ok(())
}
-async fn fmt_command(files: Vec<String>, check: bool) {
- if let Err(err) = fmt::format_files(files, check) {
- print_err_and_exit(err);
- }
-}
-
async fn test_command(
flags: DenoFlags,
include: Option<Vec<String>>,
fail_fast: bool,
_quiet: bool,
allow_none: bool,
-) {
- let global_state = create_global_state(flags.clone());
+) -> Result<(), ErrBox> {
+ let global_state = GlobalState::new(flags.clone())?;
let cwd = std::env::current_dir().expect("No current directory");
let include = include.unwrap_or_else(|| vec![".".to_string()]);
- let res = test_runner::prepare_test_modules_urls(include, &cwd);
+ let test_modules = test_runner::prepare_test_modules_urls(include, &cwd)?;
- let test_modules = match res {
- Ok(modules) => modules,
- Err(e) => return print_err_and_exit(e),
- };
if test_modules.is_empty() {
println!("No matching test modules found");
if !allow_none {
std::process::exit(1);
}
- return;
+ return Ok(());
}
let test_file = test_runner::render_test_file(test_modules, fail_fast);
let test_file_path = cwd.join(".deno.test.ts");
+ let test_file_url =
+ Url::from_file_path(&test_file_path).expect("Should be valid file url");
+ let main_module =
+ ModuleSpecifier::resolve_url(&test_file_url.to_string()).unwrap();
+ // First create worker with specified test file and only then write
+ // file to disk. Then test file will be executed and removed
+ // immediately after. That way even if compilation/tests fail test
+ // file can be cleaned up.
+ let mut worker =
+ create_main_worker(global_state.clone(), main_module.clone())?;
deno_fs::write_file(&test_file_path, test_file.as_bytes(), 0o666)
.expect("Can't write test file");
-
- let mut flags = flags.clone();
- flags
- .argv
- .push(test_file_path.to_string_lossy().to_string());
-
- let result =
- run_script(global_state, test_file_path.to_string_lossy().to_string())
- .await;
+ let execute_result = worker.execute_module(&main_module).await;
+ // Remove temporary test file
std_fs::remove_file(&test_file_path).expect("Failed to remove temp file");
- if let Err(err) = result {
- print_err_and_exit(err);
- }
+ execute_result?;
+ worker.execute("window.dispatchEvent(new Event('load'))")?;
+ (&mut *worker).await?;
+ worker.execute("window.dispatchEvent(new Event('unload'))")
}
pub fn main() {
@@ -482,37 +406,58 @@ pub fn main() {
};
log::set_max_level(log_level.to_level_filter());
- let fut = async move {
- match flags.clone().subcommand {
- DenoSubcommand::Bundle {
- source_file,
- out_file,
- } => bundle_command(flags, source_file, out_file).await,
- DenoSubcommand::Completions { buf } => {
- print!("{}", std::str::from_utf8(&buf).unwrap());
- }
- DenoSubcommand::Eval { code } => eval_command(flags, code).await,
- DenoSubcommand::Fetch { files } => fetch_command(flags, files).await,
- DenoSubcommand::Fmt { check, files } => fmt_command(files, check).await,
- DenoSubcommand::Info { file } => info_command(flags, file).await,
- DenoSubcommand::Install {
- dir,
- exe_name,
- module_url,
- args,
- force,
- } => install_command(flags, dir, exe_name, module_url, args, force).await,
- DenoSubcommand::Repl => run_repl(flags).await,
- DenoSubcommand::Run { script } => run_command(flags, script).await,
- DenoSubcommand::Test {
- quiet,
- fail_fast,
- include,
- allow_none,
- } => test_command(flags, include, fail_fast, quiet, allow_none).await,
- DenoSubcommand::Types => types_command(),
- _ => panic!("bad subcommand"),
+ let fut = match flags.clone().subcommand {
+ DenoSubcommand::Bundle {
+ source_file,
+ out_file,
+ } => bundle_command(flags, source_file, out_file).boxed_local(),
+ DenoSubcommand::Eval { code } => eval_command(flags, code).boxed_local(),
+ DenoSubcommand::Fetch { files } => {
+ fetch_command(flags, files).boxed_local()
+ }
+ DenoSubcommand::Fmt { check, files } => {
+ async move { fmt::format_files(files, check) }.boxed_local()
+ }
+ DenoSubcommand::Info { file } => info_command(flags, file).boxed_local(),
+ DenoSubcommand::Install {
+ dir,
+ exe_name,
+ module_url,
+ args,
+ force,
+ } => install_command(flags, dir, exe_name, module_url, args, force)
+ .boxed_local(),
+ DenoSubcommand::Repl => run_repl(flags).boxed_local(),
+ DenoSubcommand::Run { script } => run_command(flags, script).boxed_local(),
+ DenoSubcommand::Test {
+ quiet,
+ fail_fast,
+ include,
+ allow_none,
+ } => {
+ test_command(flags, include, fail_fast, quiet, allow_none).boxed_local()
+ }
+ DenoSubcommand::Completions { buf } => {
+ print!("{}", std::str::from_utf8(&buf).unwrap());
+ return;
}
+ DenoSubcommand::Types => {
+ let types = format!(
+ "{}\n{}\n{}",
+ crate::js::DENO_NS_LIB,
+ crate::js::SHARED_GLOBALS_LIB,
+ crate::js::WINDOW_LIB
+ );
+ // TODO(ry) Only ignore SIGPIPE. Currently ignoring all errors.
+ let _r = std::io::stdout().write_all(types.as_bytes());
+ return;
+ }
+ _ => unreachable!(),
};
- tokio_util::run_basic(fut);
+
+ let result = tokio_util::run_basic(fut);
+ if let Err(err) = result {
+ eprintln!("{}", err.to_string());
+ std::process::exit(1);
+ }
}
diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs
index 4f6f996ee..81e8f76da 100644
--- a/cli/ops/worker_host.rs
+++ b/cli/ops/worker_host.rs
@@ -172,9 +172,7 @@ fn run_worker_thread(
} else {
// TODO(bartlomieju): add "type": "classic", ie. ability to load
// script instead of module
- let load_future = worker
- .execute_mod_async(&specifier, None, false)
- .boxed_local();
+ let load_future = worker.execute_module(&specifier).boxed_local();
rt.block_on(load_future)
};
diff --git a/cli/progress.rs b/cli/progress.rs
deleted file mode 100644
index 3eb0d9136..000000000
--- a/cli/progress.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-use std::sync::Arc;
-use std::sync::Mutex;
-
-#[derive(Clone, Default)]
-pub struct Progress(Arc<Mutex<Inner>>);
-
-impl Progress {
- pub fn new() -> Self {
- Progress::default()
- }
-
- pub fn set_callback<F>(&self, f: F)
- where
- F: Fn(bool, usize, usize, &str, &str) + Send + Sync + 'static,
- {
- let mut s = self.0.lock().unwrap();
- assert!(s.callback.is_none());
- s.callback = Some(Arc::new(f));
- }
-
- /// Returns job counts: (complete, total)
- pub fn progress(&self) -> (usize, usize) {
- let s = self.0.lock().unwrap();
- s.progress()
- }
-
- pub fn history(&self) -> Vec<String> {
- let s = self.0.lock().unwrap();
- s.job_names.clone()
- }
-
- pub fn add(&self, status: &str, name: &str) -> Job {
- let mut s = self.0.lock().unwrap();
- let id = s.job_names.len();
- s.maybe_call_callback(
- false,
- s.complete,
- s.job_names.len() + 1,
- status,
- name,
- );
- s.job_names.push(name.to_string());
- Job {
- id,
- inner: self.0.clone(),
- }
- }
-
- pub fn done(&self) {
- let s = self.0.lock().unwrap();
- s.maybe_call_callback(true, s.complete, s.job_names.len(), "", "");
- }
-}
-
-type Callback = dyn Fn(bool, usize, usize, &str, &str) + Send + Sync;
-
-#[derive(Default)]
-struct Inner {
- job_names: Vec<String>,
- complete: usize,
- callback: Option<Arc<Callback>>,
-}
-
-impl Inner {
- pub fn maybe_call_callback(
- &self,
- done: bool,
- complete: usize,
- total: usize,
- status: &str,
- msg: &str,
- ) {
- if let Some(ref cb) = self.callback {
- cb(done, complete, total, status, msg);
- }
- }
-
- /// Returns job counts: (complete, total)
- pub fn progress(&self) -> (usize, usize) {
- let total = self.job_names.len();
- (self.complete, total)
- }
-}
-
-pub struct Job {
- inner: Arc<Mutex<Inner>>,
- id: usize,
-}
-
-impl Drop for Job {
- fn drop(&mut self) {
- let mut s = self.inner.lock().unwrap();
- s.complete += 1;
- let name = &s.job_names[self.id];
- let (complete, total) = s.progress();
- s.maybe_call_callback(false, complete, total, "", name);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn progress() {
- let p = Progress::new();
- assert_eq!(p.progress(), (0, 0));
- {
- let _j1 = p.add("status", "hello");
- assert_eq!(p.progress(), (0, 1));
- }
- assert_eq!(p.progress(), (1, 1));
- {
- let _j2 = p.add("status", "hello");
- assert_eq!(p.progress(), (1, 2));
- }
- assert_eq!(p.progress(), (2, 2));
- }
-
- #[test]
- fn history() {
- let p = Progress::new();
- let _a = p.add("status", "a");
- let _b = p.add("status", "b");
- assert_eq!(p.history(), vec!["a", "b"]);
- }
-
- #[test]
- fn callback() {
- let callback_history: Arc<Mutex<Vec<(usize, usize, String)>>> =
- Arc::new(Mutex::new(Vec::new()));
- {
- let p = Progress::new();
- let callback_history_ = callback_history.clone();
-
- p.set_callback(move |_done, complete, total, _status, msg| {
- // println!("callback: {}, {}, {}", complete, total, msg);
- let mut h = callback_history_.lock().unwrap();
- h.push((complete, total, String::from(msg)));
- });
- {
- let _a = p.add("status", "a");
- let _b = p.add("status", "b");
- }
- let _c = p.add("status", "c");
- }
-
- let h = callback_history.lock().unwrap();
- assert_eq!(
- h.to_vec(),
- vec![
- (0, 1, "a".to_string()),
- (0, 2, "b".to_string()),
- (1, 2, "b".to_string()),
- (2, 2, "a".to_string()),
- (2, 3, "c".to_string()),
- (3, 3, "c".to_string()),
- ]
- );
- }
-
- #[test]
- fn thread_safe() {
- fn f<S: Send + Sync>(_: S) {}
- f(Progress::new());
- }
-}
diff --git a/cli/shell.rs b/cli/shell.rs
deleted file mode 100644
index 8e52f51fd..000000000
--- a/cli/shell.rs
+++ /dev/null
@@ -1,285 +0,0 @@
-// This file was forked from Cargo on 2019.05.29:
-// https://github.com/rust-lang/cargo/blob/edd874/src/cargo/core/shell.rs
-// Cargo is MIT licenced:
-// https://github.com/rust-lang/cargo/blob/edd874/LICENSE-MIT
-
-use std::fmt;
-use std::io::prelude::*;
-
-use atty;
-use deno_core::ErrBox;
-use termcolor::Color::Green;
-use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};
-
-/// The requested verbosity of output.
-#[derive(Debug, Clone, Copy, PartialEq)]
-#[allow(dead_code)]
-pub enum Verbosity {
- Verbose,
- Normal,
- Quiet,
-}
-
-/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
-/// color.
-pub struct Shell {
- /// the `Write`able object, either with or without color support (represented by different enum
- /// variants)
- err: ShellOut,
- /// How verbose messages should be
- verbosity: Verbosity,
- /// Flag that indicates the current line needs to be cleared before
- /// printing. Used when a progress bar is currently displayed.
- needs_clear: bool,
-}
-
-impl fmt::Debug for Shell {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.err {
- /*
- ShellOut::Write(_) => f
- .debug_struct("Shell")
- .field("verbosity", &self.verbosity)
- .finish(),
- */
- ShellOut::Stream { color_choice, .. } => f
- .debug_struct("Shell")
- .field("verbosity", &self.verbosity)
- .field("color_choice", &color_choice)
- .finish(),
- }
- }
-}
-
-/// A `Write`able object, either with or without color support
-enum ShellOut {
- /// A plain write object without color support
- // TODO(ry) Disabling this type of output because it makes Shell
- // not thread safe and thus not includable in State.
- // But I think we will want this in the future.
- //Write(Box<dyn Write>),
- /// Color-enabled stdio, with information on whether color should be used
- Stream {
- stream: StandardStream,
- tty: bool,
- color_choice: ColorChoice,
- },
-}
-
-/// Whether messages should use color output
-#[derive(Debug, PartialEq, Clone, Copy)]
-#[allow(dead_code)]
-pub enum ColorChoice {
- /// Force color output
- Always,
- /// Force disable color output
- Never,
- /// Intelligently guess whether to use color output
- CargoAuto,
-}
-
-impl Shell {
- /// Creates a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
- /// output.
- pub fn new() -> Shell {
- Shell {
- err: ShellOut::Stream {
- stream: StandardStream::stderr(
- ColorChoice::CargoAuto.to_termcolor_color_choice(),
- ),
- color_choice: ColorChoice::CargoAuto,
- tty: atty::is(atty::Stream::Stderr),
- },
- verbosity: Verbosity::Verbose,
- needs_clear: false,
- }
- }
-
- /// Prints a message, where the status will have `color` color, and can be justified. The
- /// messages follows without color.
- fn print(
- &mut self,
- status: &dyn fmt::Display,
- message: Option<&dyn fmt::Display>,
- color: Color,
- justified: bool,
- ) -> Result<(), ErrBox> {
- match self.verbosity {
- Verbosity::Quiet => Ok(()),
- _ => {
- if self.needs_clear {
- self.err_erase_line();
- }
- self.err.print(status, message, color, justified)
- }
- }
- }
-
- /// Erase from cursor to end of line.
- pub fn err_erase_line(&mut self) {
- if let ShellOut::Stream { tty: true, .. } = self.err {
- imp::err_erase_line(self);
- self.needs_clear = false;
- }
- }
-
- /// Shortcut to right-align and color green a status message.
- pub fn status<T, U>(&mut self, status: T, message: U) -> Result<(), ErrBox>
- where
- T: fmt::Display,
- U: fmt::Display,
- {
- self.print(&status, Some(&message), Green, false)
- }
-}
-
-impl Default for Shell {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl ShellOut {
- /// Prints out a message with a status. The status comes first, and is bold plus the given
- /// color. The status can be justified, in which case the max width that will right align is
- /// 12 chars.
- fn print(
- &mut self,
- status: &dyn fmt::Display,
- message: Option<&dyn fmt::Display>,
- color: Color,
- justified: bool,
- ) -> Result<(), ErrBox> {
- match *self {
- ShellOut::Stream { ref mut stream, .. } => {
- stream.reset()?;
- stream
- .set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)))?;
- if justified {
- write!(stream, "{:>12}", status)?;
- } else {
- write!(stream, "{}", status)?;
- }
- stream.reset()?;
- match message {
- Some(message) => writeln!(stream, " {}", message)?,
- None => write!(stream, " ")?,
- }
- }
- }
- Ok(())
- }
-
- /// Gets this object as a `io::Write`.
- fn as_write(&mut self) -> &mut dyn Write {
- match *self {
- ShellOut::Stream { ref mut stream, .. } => stream,
- // ShellOut::Write(ref mut w) => w,
- }
- }
-}
-
-impl ColorChoice {
- /// Converts our color choice to termcolor's version.
- fn to_termcolor_color_choice(self) -> termcolor::ColorChoice {
- match self {
- ColorChoice::Always => termcolor::ColorChoice::Always,
- ColorChoice::Never => termcolor::ColorChoice::Never,
- ColorChoice::CargoAuto => {
- if atty::is(atty::Stream::Stderr) {
- termcolor::ColorChoice::Auto
- } else {
- termcolor::ColorChoice::Never
- }
- }
- }
- }
-}
-
-#[cfg(any(target_os = "linux", target_os = "macos"))]
-mod imp {
- use super::Shell;
-
- pub fn err_erase_line(shell: &mut Shell) {
- // This is the "EL - Erase in Line" sequence. It clears from the cursor
- // to the end of line.
- // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
- let _ = shell.err.as_write().write_all(b"\x1B[K");
- }
-}
-
-#[cfg(all(unix, not(any(target_os = "linux", target_os = "macos"))))]
-mod imp {
- pub(super) use super::default_err_erase_line as err_erase_line;
-
- pub fn stderr_width() -> Option<usize> {
- None
- }
-}
-
-#[cfg(windows)]
-mod imp {
- use std::{cmp, mem, ptr};
- use winapi::um::fileapi::*;
- use winapi::um::handleapi::*;
- use winapi::um::processenv::*;
- use winapi::um::winbase::*;
- use winapi::um::wincon::*;
- use winapi::um::winnt::*;
-
- pub(super) use super::default_err_erase_line as err_erase_line;
-
- pub fn stderr_width() -> Option<usize> {
- unsafe {
- let stdout = GetStdHandle(STD_ERROR_HANDLE);
- let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
- if GetConsoleScreenBufferInfo(stdout, &mut csbi) != 0 {
- return Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize);
- }
-
- // On mintty/msys/cygwin based terminals, the above fails with
- // INVALID_HANDLE_VALUE. Use an alternate method which works
- // in that case as well.
- let h = CreateFileA(
- "CONOUT$\0".as_ptr() as *const CHAR,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- ptr::null_mut(),
- OPEN_EXISTING,
- 0,
- ptr::null_mut(),
- );
- if h == INVALID_HANDLE_VALUE {
- return None;
- }
-
- let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
- let rc = GetConsoleScreenBufferInfo(h, &mut csbi);
- CloseHandle(h);
- if rc != 0 {
- let width = (csbi.srWindow.Right - csbi.srWindow.Left) as usize;
- // Unfortunately cygwin/mintty does not set the size of the
- // backing console to match the actual window size. This
- // always reports a size of 80 or 120 (not sure what
- // determines that). Use a conservative max of 60 which should
- // work in most circumstances. ConEmu does some magic to
- // resize the console correctly, but there's no reasonable way
- // to detect which kind of terminal we are running in, or if
- // GetConsoleScreenBufferInfo returns accurate information.
- return Some(cmp::min(60, width));
- }
- None
- }
- }
-}
-
-#[cfg(any(
- all(unix, not(any(target_os = "linux", target_os = "macos"))),
- windows
-))]
-fn default_err_erase_line(shell: &mut Shell) {
- if let Some(max_width) = imp::stderr_width() {
- let blank = " ".repeat(max_width);
- drop(write!(shell.err.as_write(), "{}\r", blank));
- }
-}
diff --git a/cli/worker.rs b/cli/worker.rs
index fa04d5a8f..bfcc1afdc 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -5,6 +5,7 @@ use crate::state::State;
use deno_core;
use deno_core::Buf;
use deno_core::ErrBox;
+use deno_core::ModuleId;
use deno_core::ModuleSpecifier;
use deno_core::StartupData;
use futures::channel::mpsc;
@@ -137,20 +138,35 @@ impl Worker {
self.isolate.execute(js_filename, js_source)
}
- /// Executes the provided JavaScript module.
- pub async fn execute_mod_async(
+ /// Loads and instantiates specified JavaScript module.
+ pub async fn preload_module(
+ &mut self,
+ module_specifier: &ModuleSpecifier,
+ ) -> Result<ModuleId, ErrBox> {
+ self.isolate.load_module(module_specifier, None).await
+ }
+
+ /// Loads, instantiates and executes specified JavaScript module.
+ pub async fn execute_module(
&mut self,
module_specifier: &ModuleSpecifier,
- maybe_code: Option<String>,
- is_prefetch: bool,
) -> Result<(), ErrBox> {
- let specifier = module_specifier.to_string();
- let id = self.isolate.load_module(&specifier, maybe_code).await?;
- self.state.borrow().global_state.progress.done();
- if !is_prefetch {
- return self.isolate.mod_evaluate(id);
- }
- Ok(())
+ let id = self.preload_module(module_specifier).await?;
+ self.isolate.mod_evaluate(id)
+ }
+
+ /// Loads, instantiates and executes provided source code
+ /// as module.
+ pub async fn execute_module_from_code(
+ &mut self,
+ module_specifier: &ModuleSpecifier,
+ code: String,
+ ) -> Result<(), ErrBox> {
+ let id = self
+ .isolate
+ .load_module(module_specifier, Some(code))
+ .await?;
+ self.isolate.mod_evaluate(id)
}
/// Returns a way to communicate with the Worker from other threads.
@@ -256,9 +272,7 @@ mod tests {
tokio_util::run_basic(async move {
let mut worker =
MainWorker::new("TEST".to_string(), StartupData::None, state);
- let result = worker
- .execute_mod_async(&module_specifier, None, false)
- .await;
+ let result = worker.execute_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
@@ -287,9 +301,7 @@ mod tests {
tokio_util::run_basic(async move {
let mut worker =
MainWorker::new("TEST".to_string(), StartupData::None, state);
- let result = worker
- .execute_mod_async(&module_specifier, None, false)
- .await;
+ let result = worker.execute_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
@@ -329,9 +341,7 @@ mod tests {
state.clone(),
);
worker.execute("bootstrapMainRuntime()").unwrap();
- let result = worker
- .execute_mod_async(&module_specifier, None, false)
- .await;
+ let result = worker.execute_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
@@ -363,8 +373,7 @@ mod tests {
let mut worker = create_test_worker();
let module_specifier =
ModuleSpecifier::resolve_url_or_path("does-not-exist").unwrap();
- let result =
- block_on(worker.execute_mod_async(&module_specifier, None, false));
+ let result = block_on(worker.execute_module(&module_specifier));
assert!(result.is_err());
})
}
@@ -381,8 +390,7 @@ mod tests {
.join("cli/tests/002_hello.ts");
let module_specifier =
ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
- let result =
- block_on(worker.execute_mod_async(&module_specifier, None, false));
+ let result = block_on(worker.execute_module(&module_specifier));
assert!(result.is_ok());
})
}
diff --git a/core/es_isolate.rs b/core/es_isolate.rs
index 197c548d7..152805f3f 100644
--- a/core/es_isolate.rs
+++ b/core/es_isolate.rs
@@ -553,11 +553,14 @@ impl EsIsolate {
/// manually after load is finished.
pub async fn load_module(
&mut self,
- specifier: &str,
+ specifier: &ModuleSpecifier,
code: Option<String>,
) -> Result<ModuleId, ErrBox> {
- let mut load =
- RecursiveModuleLoad::main(specifier, code, self.loader.clone());
+ let mut load = RecursiveModuleLoad::main(
+ &specifier.to_string(),
+ code,
+ self.loader.clone(),
+ );
while let Some(info_result) = load.next().await {
let info = info_result?;
diff --git a/core/modules.rs b/core/modules.rs
index 29f6067cd..764aadb64 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -653,7 +653,8 @@ mod tests {
let loader = MockLoader::new();
let loads = loader.loads.clone();
let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false);
- let a_id_fut = isolate.load_module("/a.js", None);
+ let spec = ModuleSpecifier::resolve_url("file:///a.js").unwrap();
+ let a_id_fut = isolate.load_module(&spec, None);
let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load");
js_check(isolate.mod_evaluate(a_id));
@@ -714,7 +715,8 @@ mod tests {
let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false);
let fut = async move {
- let result = isolate.load_module("/circular1.js", None).await;
+ let spec = ModuleSpecifier::resolve_url("file:///circular1.js").unwrap();
+ let result = isolate.load_module(&spec, None).await;
assert!(result.is_ok());
let circular1_id = result.unwrap();
js_check(isolate.mod_evaluate(circular1_id));
@@ -784,7 +786,8 @@ mod tests {
let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false);
let fut = async move {
- let result = isolate.load_module("/redirect1.js", None).await;
+ let spec = ModuleSpecifier::resolve_url("file:///redirect1.js").unwrap();
+ let result = isolate.load_module(&spec, None).await;
println!(">> result {:?}", result);
assert!(result.is_ok());
let redirect1_id = result.unwrap();
@@ -844,8 +847,8 @@ mod tests {
let loads = loader.loads.clone();
let mut isolate =
EsIsolate::new(Rc::new(loader), StartupData::None, false);
- let mut recursive_load =
- isolate.load_module("/main.js", None).boxed_local();
+ let spec = ModuleSpecifier::resolve_url("file:///main.js").unwrap();
+ let mut recursive_load = isolate.load_module(&spec, None).boxed_local();
let result = recursive_load.poll_unpin(&mut cx);
assert!(result.is_pending());
@@ -890,8 +893,8 @@ mod tests {
let loader = MockLoader::new();
let mut isolate =
EsIsolate::new(Rc::new(loader), StartupData::None, false);
- let mut load_fut =
- isolate.load_module("/bad_import.js", None).boxed_local();
+ let spec = ModuleSpecifier::resolve_url("file:///bad_import.js").unwrap();
+ let mut load_fut = isolate.load_module(&spec, None).boxed_local();
let result = load_fut.poll_unpin(&mut cx);
if let Poll::Ready(Err(err)) = result {
assert_eq!(
@@ -921,8 +924,10 @@ mod tests {
// In default resolution code should be empty.
// Instead we explicitly pass in our own code.
// The behavior should be very similar to /a.js.
+ let spec =
+ ModuleSpecifier::resolve_url("file:///main_with_code.js").unwrap();
let main_id_fut = isolate
- .load_module("/main_with_code.js", Some(MAIN_WITH_CODE_SRC.to_owned()))
+ .load_module(&spec, Some(MAIN_WITH_CODE_SRC.to_owned()))
.boxed_local();
let main_id =
futures::executor::block_on(main_id_fut).expect("Failed to load");