summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-12-09 09:40:48 -0500
committerGitHub <noreply@github.com>2022-12-09 09:40:48 -0500
commit6541a0a9fd818424688003c617e4a84c3cf7d34d (patch)
tree0a2281e9f119bb992fe34908665a79f5eaddaa77
parent9daf6e197a642a88d79614fb53888b5bb954463a (diff)
refactor: cleanup main.rs (#16996)
1. Extracts out some code from main.rs 2. Inlines all the `x_command` functions in main.rs
-rw-r--r--cli/graph_util.rs112
-rw-r--r--cli/main.rs833
-rw-r--r--cli/proc_state.rs25
-rw-r--r--cli/tools/bundle.rs158
-rw-r--r--cli/tools/coverage/mod.rs5
-rw-r--r--cli/tools/installer.rs37
-rw-r--r--cli/tools/mod.rs2
-rw-r--r--cli/tools/repl/mod.rs22
-rw-r--r--cli/tools/run.rs169
-rw-r--r--cli/tools/standalone.rs61
10 files changed, 664 insertions, 760 deletions
diff --git a/cli/graph_util.rs b/cli/graph_util.rs
index 7cef4b6f1..253d556e0 100644
--- a/cli/graph_util.rs
+++ b/cli/graph_util.rs
@@ -1,15 +1,24 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::args::Lockfile;
+use crate::args::TsConfigType;
use crate::args::TsTypeLib;
+use crate::args::TypeCheckMode;
+use crate::cache;
+use crate::cache::TypeCheckCache;
use crate::colors;
use crate::errors::get_error_class_name;
use crate::npm::resolve_npm_package_reqs;
use crate::npm::NpmPackageReference;
use crate::npm::NpmPackageReq;
+use crate::proc_state::ProcState;
+use crate::resolver::CliResolver;
+use crate::tools::check;
+use deno_core::anyhow::bail;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
+use deno_core::parking_lot::RwLock;
use deno_core::ModuleSpecifier;
use deno_graph::Dependency;
use deno_graph::GraphImport;
@@ -19,6 +28,7 @@ use deno_graph::ModuleGraphError;
use deno_graph::ModuleKind;
use deno_graph::Range;
use deno_graph::Resolved;
+use deno_runtime::permissions::Permissions;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::HashSet;
@@ -496,3 +506,105 @@ pub fn graph_lock_or_exit(graph: &ModuleGraph, lockfile: &mut Lockfile) {
}
}
}
+
+pub async fn create_graph_and_maybe_check(
+ root: ModuleSpecifier,
+ ps: &ProcState,
+) -> Result<Arc<deno_graph::ModuleGraph>, AnyError> {
+ let mut cache = cache::FetchCacher::new(
+ ps.emit_cache.clone(),
+ ps.file_fetcher.clone(),
+ Permissions::allow_all(),
+ Permissions::allow_all(),
+ );
+ let maybe_imports = ps.options.to_maybe_imports()?;
+ let maybe_cli_resolver = CliResolver::maybe_new(
+ ps.options.to_maybe_jsx_import_source_config(),
+ ps.maybe_import_map.clone(),
+ );
+ let maybe_graph_resolver =
+ maybe_cli_resolver.as_ref().map(|r| r.as_graph_resolver());
+ let analyzer = ps.parsed_source_cache.as_analyzer();
+ let graph = Arc::new(
+ deno_graph::create_graph(
+ vec![(root, deno_graph::ModuleKind::Esm)],
+ &mut cache,
+ deno_graph::GraphOptions {
+ is_dynamic: false,
+ imports: maybe_imports,
+ resolver: maybe_graph_resolver,
+ module_analyzer: Some(&*analyzer),
+ reporter: None,
+ },
+ )
+ .await,
+ );
+
+ let check_js = ps.options.check_js();
+ let mut graph_data = GraphData::default();
+ graph_data.add_graph(&graph, false);
+ graph_data
+ .check(
+ &graph.roots,
+ ps.options.type_check_mode() != TypeCheckMode::None,
+ check_js,
+ )
+ .unwrap()?;
+ ps.npm_resolver
+ .add_package_reqs(graph_data.npm_package_reqs().clone())
+ .await?;
+ if let Some(lockfile) = &ps.lockfile {
+ graph_lock_or_exit(&graph, &mut lockfile.lock());
+ }
+
+ if ps.options.type_check_mode() != TypeCheckMode::None {
+ let ts_config_result =
+ ps.options.resolve_ts_config_for_emit(TsConfigType::Check {
+ lib: ps.options.ts_type_lib_window(),
+ })?;
+ if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
+ eprintln!("{}", ignored_options);
+ }
+ let maybe_config_specifier = ps.options.maybe_config_file_specifier();
+ let cache = TypeCheckCache::new(&ps.dir.type_checking_cache_db_file_path());
+ let check_result = check::check(
+ &graph.roots,
+ Arc::new(RwLock::new(graph_data)),
+ &cache,
+ ps.npm_resolver.clone(),
+ check::CheckOptions {
+ type_check_mode: ps.options.type_check_mode(),
+ debug: ps.options.log_level() == Some(log::Level::Debug),
+ maybe_config_specifier,
+ ts_config: ts_config_result.ts_config,
+ log_checks: true,
+ reload: ps.options.reload_flag(),
+ },
+ )?;
+ log::debug!("{}", check_result.stats);
+ if !check_result.diagnostics.is_empty() {
+ return Err(check_result.diagnostics.into());
+ }
+ }
+
+ Ok(graph)
+}
+
+pub fn error_for_any_npm_specifier(
+ graph: &deno_graph::ModuleGraph,
+) -> Result<(), AnyError> {
+ let first_npm_specifier = graph
+ .specifiers()
+ .filter_map(|(_, r)| match r {
+ Ok((specifier, kind, _)) if kind == deno_graph::ModuleKind::External => {
+ Some(specifier.clone())
+ }
+ _ => None,
+ })
+ .next();
+ if let Some(npm_specifier) = first_npm_specifier {
+ bail!("npm specifiers have not yet been implemented for this sub command (https://github.com/denoland/deno/issues/15960). Found: {}", npm_specifier)
+ } else {
+ Ok(())
+ }
+}
diff --git a/cli/main.rs b/cli/main.rs
index 05dc768f7..a47c9a01a 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -26,731 +26,23 @@ mod version;
mod worker;
use crate::args::flags_from_vec;
-use crate::args::BenchFlags;
-use crate::args::BundleFlags;
-use crate::args::CacheFlags;
-use crate::args::CheckFlags;
-use crate::args::CompileFlags;
-use crate::args::CompletionsFlags;
-use crate::args::CoverageFlags;
use crate::args::DenoSubcommand;
-use crate::args::DocFlags;
-use crate::args::EvalFlags;
use crate::args::Flags;
-use crate::args::FmtFlags;
-use crate::args::InfoFlags;
-use crate::args::InitFlags;
-use crate::args::InstallFlags;
-use crate::args::LintFlags;
-use crate::args::ReplFlags;
-use crate::args::RunFlags;
-use crate::args::TaskFlags;
-use crate::args::TestFlags;
-use crate::args::TsConfigType;
-use crate::args::TypeCheckMode;
-use crate::args::UninstallFlags;
-use crate::args::UpgradeFlags;
-use crate::args::VendorFlags;
-use crate::cache::TypeCheckCache;
-use crate::file_fetcher::File;
-use crate::graph_util::graph_lock_or_exit;
use crate::proc_state::ProcState;
use crate::resolver::CliResolver;
-use crate::tools::check;
use crate::util::display;
-use crate::util::file_watcher::ResolutionResult;
use args::CliOptions;
-use deno_ast::MediaType;
-use deno_core::anyhow::bail;
-use deno_core::error::generic_error;
+use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::error::JsError;
-use deno_core::futures::future::FutureExt;
-use deno_core::futures::Future;
-use deno_core::parking_lot::RwLock;
-use deno_core::resolve_url_or_path;
use deno_core::v8_set_flags;
-use deno_core::ModuleSpecifier;
use deno_runtime::colors;
use deno_runtime::fmt_errors::format_js_error;
-use deno_runtime::permissions::Permissions;
use deno_runtime::tokio_util::run_local;
-use graph_util::GraphData;
-use log::debug;
-use log::info;
-use npm::NpmPackageReference;
use std::env;
-use std::io::Read;
use std::iter::once;
use std::path::PathBuf;
-use std::pin::Pin;
-use std::sync::Arc;
-use worker::create_main_worker;
-
-async fn compile_command(
- flags: Flags,
- compile_flags: CompileFlags,
-) -> Result<i32, AnyError> {
- let ps = ProcState::build(flags.clone()).await?;
- let module_specifier = resolve_url_or_path(&compile_flags.source_file)?;
- let deno_dir = &ps.dir;
-
- let output_path =
- tools::standalone::resolve_compile_executable_output_path(&compile_flags)?;
-
- let graph = Arc::try_unwrap(
- create_graph_and_maybe_check(module_specifier.clone(), &ps).await?,
- )
- .unwrap();
-
- // at the moment, we don't support npm specifiers in deno_compile, so show an error
- error_for_any_npm_specifier(&graph)?;
-
- graph.valid()?;
-
- let parser = ps.parsed_source_cache.as_capturing_parser();
- let eszip = eszip::EszipV2::from_graph(graph, &parser, Default::default())?;
-
- info!(
- "{} {}",
- colors::green("Compile"),
- module_specifier.to_string()
- );
-
- // Select base binary based on target
- let original_binary =
- tools::standalone::get_base_binary(deno_dir, compile_flags.target.clone())
- .await?;
-
- let final_bin = tools::standalone::create_standalone_binary(
- original_binary,
- eszip,
- module_specifier.clone(),
- &compile_flags,
- ps,
- )
- .await?;
-
- info!("{} {}", colors::green("Emit"), output_path.display());
-
- tools::standalone::write_standalone_binary(output_path, final_bin).await?;
-
- Ok(0)
-}
-
-async fn init_command(
- _flags: Flags,
- init_flags: InitFlags,
-) -> Result<i32, AnyError> {
- tools::init::init_project(init_flags).await?;
- Ok(0)
-}
-
-async fn info_command(
- flags: Flags,
- info_flags: InfoFlags,
-) -> Result<i32, AnyError> {
- tools::info::info(flags, info_flags).await?;
- Ok(0)
-}
-
-async fn install_command(
- flags: Flags,
- install_flags: InstallFlags,
-) -> Result<i32, AnyError> {
- let ps = ProcState::build(flags.clone()).await?;
- // ensure the module is cached
- load_and_type_check(&ps, &[install_flags.module_url.clone()]).await?;
- tools::installer::install(flags, install_flags)?;
- Ok(0)
-}
-
-async fn uninstall_command(
- uninstall_flags: UninstallFlags,
-) -> Result<i32, AnyError> {
- tools::installer::uninstall(uninstall_flags.name, uninstall_flags.root)?;
- Ok(0)
-}
-
-async fn lsp_command() -> Result<i32, AnyError> {
- lsp::start().await?;
- Ok(0)
-}
-
-async fn lint_command(
- flags: Flags,
- lint_flags: LintFlags,
-) -> Result<i32, AnyError> {
- if lint_flags.rules {
- tools::lint::print_rules_list(lint_flags.json);
- return Ok(0);
- }
-
- tools::lint::lint(flags, lint_flags).await?;
- Ok(0)
-}
-
-async fn cache_command(
- flags: Flags,
- cache_flags: CacheFlags,
-) -> Result<i32, AnyError> {
- let ps = ProcState::build(flags).await?;
- load_and_type_check(&ps, &cache_flags.files).await?;
- ps.cache_module_emits()?;
- Ok(0)
-}
-
-async fn check_command(
- flags: Flags,
- check_flags: CheckFlags,
-) -> Result<i32, AnyError> {
- let ps = ProcState::build(flags).await?;
- load_and_type_check(&ps, &check_flags.files).await?;
- Ok(0)
-}
-
-async fn load_and_type_check(
- ps: &ProcState,
- files: &[String],
-) -> Result<(), AnyError> {
- let lib = ps.options.ts_type_lib_window();
-
- let specifiers = files
- .iter()
- .map(|file| resolve_url_or_path(file))
- .collect::<Result<Vec<_>, _>>()?;
- ps.prepare_module_load(
- specifiers,
- false,
- lib,
- Permissions::allow_all(),
- Permissions::allow_all(),
- false,
- )
- .await?;
-
- Ok(())
-}
-
-async fn eval_command(
- flags: Flags,
- eval_flags: EvalFlags,
-) -> Result<i32, AnyError> {
- // deno_graph works off of extensions for local files to determine the media
- // type, and so our "fake" specifier needs to have the proper extension.
- let main_module =
- resolve_url_or_path(&format!("./$deno$eval.{}", eval_flags.ext))?;
- let ps = ProcState::build(flags).await?;
- let permissions =
- Permissions::from_options(&ps.options.permissions_options())?;
- let mut worker =
- create_main_worker(&ps, main_module.clone(), permissions).await?;
- // Create a dummy source file.
- let source_code = if eval_flags.print {
- format!("console.log({})", eval_flags.code)
- } else {
- eval_flags.code
- }
- .into_bytes();
-
- let file = File {
- local: main_module.clone().to_file_path().unwrap(),
- maybe_types: None,
- media_type: MediaType::Unknown,
- source: String::from_utf8(source_code)?.into(),
- specifier: main_module.clone(),
- maybe_headers: None,
- };
-
- // Save our fake file into file fetcher cache
- // to allow module access by TS compiler.
- ps.file_fetcher.insert_cached(file);
- let exit_code = worker.run().await?;
- Ok(exit_code)
-}
-
-async fn create_graph_and_maybe_check(
- root: ModuleSpecifier,
- ps: &ProcState,
-) -> Result<Arc<deno_graph::ModuleGraph>, AnyError> {
- let mut cache = cache::FetchCacher::new(
- ps.emit_cache.clone(),
- ps.file_fetcher.clone(),
- Permissions::allow_all(),
- Permissions::allow_all(),
- );
- let maybe_imports = ps.options.to_maybe_imports()?;
- let maybe_cli_resolver = CliResolver::maybe_new(
- ps.options.to_maybe_jsx_import_source_config(),
- ps.maybe_import_map.clone(),
- );
- let maybe_graph_resolver =
- maybe_cli_resolver.as_ref().map(|r| r.as_graph_resolver());
- let analyzer = ps.parsed_source_cache.as_analyzer();
- let graph = Arc::new(
- deno_graph::create_graph(
- vec![(root, deno_graph::ModuleKind::Esm)],
- &mut cache,
- deno_graph::GraphOptions {
- is_dynamic: false,
- imports: maybe_imports,
- resolver: maybe_graph_resolver,
- module_analyzer: Some(&*analyzer),
- reporter: None,
- },
- )
- .await,
- );
-
- let check_js = ps.options.check_js();
- let mut graph_data = GraphData::default();
- graph_data.add_graph(&graph, false);
- graph_data
- .check(
- &graph.roots,
- ps.options.type_check_mode() != TypeCheckMode::None,
- check_js,
- )
- .unwrap()?;
- ps.npm_resolver
- .add_package_reqs(graph_data.npm_package_reqs().clone())
- .await?;
- if let Some(lockfile) = &ps.lockfile {
- graph_lock_or_exit(&graph, &mut lockfile.lock());
- }
-
- if ps.options.type_check_mode() != TypeCheckMode::None {
- let ts_config_result =
- ps.options.resolve_ts_config_for_emit(TsConfigType::Check {
- lib: ps.options.ts_type_lib_window(),
- })?;
- if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
- eprintln!("{}", ignored_options);
- }
- let maybe_config_specifier = ps.options.maybe_config_file_specifier();
- let cache = TypeCheckCache::new(&ps.dir.type_checking_cache_db_file_path());
- let check_result = check::check(
- &graph.roots,
- Arc::new(RwLock::new(graph_data)),
- &cache,
- ps.npm_resolver.clone(),
- check::CheckOptions {
- type_check_mode: ps.options.type_check_mode(),
- debug: ps.options.log_level() == Some(log::Level::Debug),
- maybe_config_specifier,
- ts_config: ts_config_result.ts_config,
- log_checks: true,
- reload: ps.options.reload_flag(),
- },
- )?;
- debug!("{}", check_result.stats);
- if !check_result.diagnostics.is_empty() {
- return Err(check_result.diagnostics.into());
- }
- }
-
- Ok(graph)
-}
-
-fn bundle_module_graph(
- graph: &deno_graph::ModuleGraph,
- ps: &ProcState,
-) -> Result<deno_emit::BundleEmit, AnyError> {
- info!("{} {}", colors::green("Bundle"), graph.roots[0].0);
-
- let ts_config_result = ps
- .options
- .resolve_ts_config_for_emit(TsConfigType::Bundle)?;
- if ps.options.type_check_mode() == TypeCheckMode::None {
- if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
- eprintln!("{}", ignored_options);
- }
- }
-
- deno_emit::bundle_graph(
- graph,
- deno_emit::BundleOptions {
- bundle_type: deno_emit::BundleType::Module,
- emit_options: ts_config_result.ts_config.into(),
- emit_ignore_directives: true,
- },
- )
-}
-
-async fn bundle_command(
- flags: Flags,
- bundle_flags: BundleFlags,
-) -> Result<i32, AnyError> {
- let cli_options = Arc::new(CliOptions::from_flags(flags)?);
- let resolver = |_| {
- let cli_options = cli_options.clone();
- let source_file1 = bundle_flags.source_file.clone();
- let source_file2 = bundle_flags.source_file.clone();
- async move {
- let module_specifier = resolve_url_or_path(&source_file1)?;
-
- debug!(">>>>> bundle START");
- let ps = ProcState::from_options(cli_options).await?;
- let graph = create_graph_and_maybe_check(module_specifier, &ps).await?;
-
- let mut paths_to_watch: Vec<PathBuf> = graph
- .specifiers()
- .filter_map(|(_, r)| {
- r.as_ref().ok().and_then(|(s, _, _)| s.to_file_path().ok())
- })
- .collect();
-
- if let Ok(Some(import_map_path)) = ps
- .options
- .resolve_import_map_specifier()
- .map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
- {
- paths_to_watch.push(import_map_path);
- }
-
- Ok((paths_to_watch, graph, ps))
- }
- .map(move |result| match result {
- Ok((paths_to_watch, graph, ps)) => ResolutionResult::Restart {
- paths_to_watch,
- result: Ok((ps, graph)),
- },
- Err(e) => ResolutionResult::Restart {
- paths_to_watch: vec![PathBuf::from(source_file2)],
- result: Err(e),
- },
- })
- };
-
- let operation = |(ps, graph): (ProcState, Arc<deno_graph::ModuleGraph>)| {
- let out_file = bundle_flags.out_file.clone();
- async move {
- // at the moment, we don't support npm specifiers in deno bundle, so show an error
- error_for_any_npm_specifier(&graph)?;
-
- let bundle_output = bundle_module_graph(graph.as_ref(), &ps)?;
- debug!(">>>>> bundle END");
-
- if let Some(out_file) = out_file.as_ref() {
- let output_bytes = bundle_output.code.as_bytes();
- let output_len = output_bytes.len();
- util::fs::write_file(out_file, output_bytes, 0o644)?;
- info!(
- "{} {:?} ({})",
- colors::green("Emit"),
- out_file,
- colors::gray(display::human_size(output_len as f64))
- );
- if let Some(bundle_map) = bundle_output.maybe_map {
- let map_bytes = bundle_map.as_bytes();
- let map_len = map_bytes.len();
- let ext = if let Some(curr_ext) = out_file.extension() {
- format!("{}.map", curr_ext.to_string_lossy())
- } else {
- "map".to_string()
- };
- let map_out_file = out_file.with_extension(ext);
- util::fs::write_file(&map_out_file, map_bytes, 0o644)?;
- info!(
- "{} {:?} ({})",
- colors::green("Emit"),
- map_out_file,
- colors::gray(display::human_size(map_len as f64))
- );
- }
- } else {
- println!("{}", bundle_output.code);
- }
-
- Ok(())
- }
- };
-
- if cli_options.watch_paths().is_some() {
- util::file_watcher::watch_func(
- resolver,
- operation,
- util::file_watcher::PrintConfig {
- job_name: "Bundle".to_string(),
- clear_screen: !cli_options.no_clear_screen(),
- },
- )
- .await?;
- } else {
- let module_graph =
- if let ResolutionResult::Restart { result, .. } = resolver(None).await {
- result?
- } else {
- unreachable!();
- };
- operation(module_graph).await?;
- }
-
- Ok(0)
-}
-
-fn error_for_any_npm_specifier(
- graph: &deno_graph::ModuleGraph,
-) -> Result<(), AnyError> {
- let first_npm_specifier = graph
- .specifiers()
- .filter_map(|(_, r)| match r {
- Ok((specifier, kind, _)) if kind == deno_graph::ModuleKind::External => {
- Some(specifier.clone())
- }
- _ => None,
- })
- .next();
- if let Some(npm_specifier) = first_npm_specifier {
- bail!("npm specifiers have not yet been implemented for this sub command (https://github.com/denoland/deno/issues/15960). Found: {}", npm_specifier)
- } else {
- Ok(())
- }
-}
-
-async fn doc_command(
- flags: Flags,
- doc_flags: DocFlags,
-) -> Result<i32, AnyError> {
- tools::doc::print_docs(flags, doc_flags).await?;
- Ok(0)
-}
-
-async fn format_command(
- flags: Flags,
- fmt_flags: FmtFlags,
-) -> Result<i32, AnyError> {
- let config = CliOptions::from_flags(flags)?;
-
- if fmt_flags.files.len() == 1 && fmt_flags.files[0].to_string_lossy() == "-" {
- let maybe_fmt_config = config.to_fmt_config()?;
- tools::fmt::format_stdin(
- fmt_flags,
- maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
- )?;
- return Ok(0);
- }
-
- tools::fmt::format(&config, fmt_flags).await?;
- Ok(0)
-}
-
-async fn repl_command(
- flags: Flags,
- repl_flags: ReplFlags,
-) -> Result<i32, AnyError> {
- let main_module = resolve_url_or_path("./$deno$repl.ts").unwrap();
- let ps = ProcState::build(flags).await?;
- let mut worker = create_main_worker(
- &ps,
- main_module.clone(),
- Permissions::from_options(&ps.options.permissions_options())?,
- )
- .await?;
- worker.setup_repl().await?;
- tools::repl::run(&ps, worker.into_main_worker(), repl_flags).await
-}
-
-async fn run_from_stdin(flags: Flags) -> Result<i32, AnyError> {
- let ps = ProcState::build(flags).await?;
- let main_module = resolve_url_or_path("./$deno$stdin.ts").unwrap();
- let mut worker = create_main_worker(
- &ps.clone(),
- main_module.clone(),
- Permissions::from_options(&ps.options.permissions_options())?,
- )
- .await?;
-
- let mut source = Vec::new();
- std::io::stdin().read_to_end(&mut source)?;
- // Create a dummy source file.
- let source_file = File {
- local: main_module.clone().to_file_path().unwrap(),
- maybe_types: None,
- media_type: MediaType::TypeScript,
- source: String::from_utf8(source)?.into(),
- specifier: main_module.clone(),
- maybe_headers: None,
- };
- // Save our fake file into file fetcher cache
- // to allow module access by TS compiler
- ps.file_fetcher.insert_cached(source_file);
-
- let exit_code = worker.run().await?;
- Ok(exit_code)
-}
-
-// TODO(bartlomieju): this function is not handling `exit_code` set by the runtime
-// code properly.
-async fn run_with_watch(flags: Flags, script: String) -> Result<i32, AnyError> {
- let flags = Arc::new(flags);
- let main_module = resolve_url_or_path(&script)?;
- let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
-
- let operation = |(sender, main_module): (
- tokio::sync::mpsc::UnboundedSender<Vec<PathBuf>>,
- ModuleSpecifier,
- )| {
- let flags = flags.clone();
- Ok(async move {
- let ps =
- ProcState::build_for_file_watcher((*flags).clone(), sender.clone())
- .await?;
- let permissions =
- Permissions::from_options(&ps.options.permissions_options())?;
- let worker =
- create_main_worker(&ps, main_module.clone(), permissions).await?;
- worker.run_for_watcher().await?;
-
- Ok(())
- })
- };
-
- util::file_watcher::watch_func2(
- receiver,
- operation,
- (sender, main_module),
- util::file_watcher::PrintConfig {
- job_name: "Process".to_string(),
- clear_screen: !flags.no_clear_screen,
- },
- )
- .await?;
-
- Ok(0)
-}
-
-async fn run_command(
- flags: Flags,
- run_flags: RunFlags,
-) -> Result<i32, AnyError> {
- // Read script content from stdin
- if run_flags.is_stdin() {
- return run_from_stdin(flags).await;
- }
-
- if !flags.has_permission() && flags.has_permission_in_argv() {
- log::warn!(
- "{}",
- crate::colors::yellow(
- r#"Permission flags have likely been incorrectly set after the script argument.
-To grant permissions, set them before the script argument. For example:
- deno run --allow-read=. main.js"#
- )
- );
- }
-
- if flags.watch.is_some() {
- return run_with_watch(flags, run_flags.script).await;
- }
-
- // TODO(bartlomieju): actually I think it will also fail if there's an import
- // map specified and bare specifier is used on the command line - this should
- // probably call `ProcState::resolve` instead
- let ps = ProcState::build(flags).await?;
-
- // Run a background task that checks for available upgrades. If an earlier
- // run of this background task found a new version of Deno.
- tools::upgrade::check_for_upgrades(ps.dir.upgrade_check_file_path());
-
- let main_module = if NpmPackageReference::from_str(&run_flags.script).is_ok()
- {
- ModuleSpecifier::parse(&run_flags.script)?
- } else {
- resolve_url_or_path(&run_flags.script)?
- };
- let permissions =
- Permissions::from_options(&ps.options.permissions_options())?;
- let mut worker =
- create_main_worker(&ps, main_module.clone(), permissions).await?;
-
- let exit_code = worker.run().await?;
- Ok(exit_code)
-}
-
-async fn task_command(
- flags: Flags,
- task_flags: TaskFlags,
-) -> Result<i32, AnyError> {
- tools::task::execute_script(flags, task_flags).await
-}
-
-async fn coverage_command(
- flags: Flags,
- coverage_flags: CoverageFlags,
-) -> Result<i32, AnyError> {
- if coverage_flags.files.is_empty() {
- return Err(generic_error("No matching coverage profiles found"));
- }
-
- tools::coverage::cover_files(flags, coverage_flags).await?;
- Ok(0)
-}
-
-async fn bench_command(
- flags: Flags,
- bench_flags: BenchFlags,
-) -> Result<i32, AnyError> {
- if flags.watch.is_some() {
- tools::bench::run_benchmarks_with_watch(flags, bench_flags).await?;
- } else {
- tools::bench::run_benchmarks(flags, bench_flags).await?;
- }
-
- Ok(0)
-}
-
-async fn test_command(
- flags: Flags,
- test_flags: TestFlags,
-) -> Result<i32, AnyError> {
- if let Some(ref coverage_dir) = flags.coverage_dir {
- std::fs::create_dir_all(coverage_dir)?;
- env::set_var(
- "DENO_UNSTABLE_COVERAGE_DIR",
- PathBuf::from(coverage_dir).canonicalize()?,
- );
- }
-
- if flags.watch.is_some() {
- tools::test::run_tests_with_watch(flags, test_flags).await?;
- } else {
- tools::test::run_tests(flags, test_flags).await?;
- }
-
- Ok(0)
-}
-
-async fn completions_command(
- _flags: Flags,
- completions_flags: CompletionsFlags,
-) -> Result<i32, AnyError> {
- display::write_to_stdout_ignore_sigpipe(&completions_flags.buf)?;
- Ok(0)
-}
-
-async fn types_command(flags: Flags) -> Result<i32, AnyError> {
- let types = tsc::get_types_declaration_file_text(flags.unstable);
- display::write_to_stdout_ignore_sigpipe(types.as_bytes())?;
- Ok(0)
-}
-
-async fn upgrade_command(
- _flags: Flags,
- upgrade_flags: UpgradeFlags,
-) -> Result<i32, AnyError> {
- tools::upgrade::upgrade(upgrade_flags).await?;
- Ok(0)
-}
-
-async fn vendor_command(
- flags: Flags,
- vendor_flags: VendorFlags,
-) -> Result<i32, AnyError> {
- tools::vendor::vendor(flags, vendor_flags).await?;
- Ok(0)
-}
fn init_v8_flags(v8_flags: &[String]) {
let v8_flags_includes_help = v8_flags
@@ -776,74 +68,139 @@ fn init_v8_flags(v8_flags: &[String]) {
}
}
-fn get_subcommand(
- flags: Flags,
-) -> Pin<Box<dyn Future<Output = Result<i32, AnyError>>>> {
+async fn run_subcommand(flags: Flags) -> Result<i32, AnyError> {
match flags.subcommand.clone() {
DenoSubcommand::Bench(bench_flags) => {
- bench_command(flags, bench_flags).boxed_local()
+ if flags.watch.is_some() {
+ tools::bench::run_benchmarks_with_watch(flags, bench_flags).await?;
+ } else {
+ tools::bench::run_benchmarks(flags, bench_flags).await?;
+ }
+ Ok(0)
}
DenoSubcommand::Bundle(bundle_flags) => {
- bundle_command(flags, bundle_flags).boxed_local()
+ tools::bundle::bundle(flags, bundle_flags).await?;
+ Ok(0)
}
DenoSubcommand::Doc(doc_flags) => {
- doc_command(flags, doc_flags).boxed_local()
+ tools::doc::print_docs(flags, doc_flags).await?;
+ Ok(0)
}
DenoSubcommand::Eval(eval_flags) => {
- eval_command(flags, eval_flags).boxed_local()
+ tools::run::eval_command(flags, eval_flags).await
}
DenoSubcommand::Cache(cache_flags) => {
- cache_command(flags, cache_flags).boxed_local()
+ let ps = ProcState::build(flags).await?;
+ ps.load_and_type_check_files(&cache_flags.files).await?;
+ ps.cache_module_emits()?;
+ Ok(0)
}
DenoSubcommand::Check(check_flags) => {
- check_command(flags, check_flags).boxed_local()
+ let ps = ProcState::build(flags).await?;
+ ps.load_and_type_check_files(&check_flags.files).await?;
+ Ok(0)
}
DenoSubcommand::Compile(compile_flags) => {
- compile_command(flags, compile_flags).boxed_local()
+ tools::standalone::compile(flags, compile_flags).await?;
+ Ok(0)
}
DenoSubcommand::Coverage(coverage_flags) => {
- coverage_command(flags, coverage_flags).boxed_local()
+ tools::coverage::cover_files(flags, coverage_flags).await?;
+ Ok(0)
}
DenoSubcommand::Fmt(fmt_flags) => {
- format_command(flags, fmt_flags).boxed_local()
+ let config = CliOptions::from_flags(flags)?;
+
+ if fmt_flags.files.len() == 1
+ && fmt_flags.files[0].to_string_lossy() == "-"
+ {
+ let maybe_fmt_config = config.to_fmt_config()?;
+ tools::fmt::format_stdin(
+ fmt_flags,
+ maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
+ )?;
+ } else {
+ tools::fmt::format(&config, fmt_flags).await?;
+ }
+ Ok(0)
}
DenoSubcommand::Init(init_flags) => {
- init_command(flags, init_flags).boxed_local()
+ tools::init::init_project(init_flags).await?;
+ Ok(0)
}
DenoSubcommand::Info(info_flags) => {
- info_command(flags, info_flags).boxed_local()
+ tools::info::info(flags, info_flags).await?;
+ Ok(0)
}
DenoSubcommand::Install(install_flags) => {
- install_command(flags, install_flags).boxed_local()
+ tools::installer::install_command(flags, install_flags).await?;
+ Ok(0)
}
DenoSubcommand::Uninstall(uninstall_flags) => {
- uninstall_command(uninstall_flags).boxed_local()
+ tools::installer::uninstall(uninstall_flags.name, uninstall_flags.root)?;
+ Ok(0)
+ }
+ DenoSubcommand::Lsp => {
+ lsp::start().await?;
+ Ok(0)
}
- DenoSubcommand::Lsp => lsp_command().boxed_local(),
DenoSubcommand::Lint(lint_flags) => {
- lint_command(flags, lint_flags).boxed_local()
+ if lint_flags.rules {
+ tools::lint::print_rules_list(lint_flags.json);
+ } else {
+ tools::lint::lint(flags, lint_flags).await?;
+ }
+ Ok(0)
}
DenoSubcommand::Repl(repl_flags) => {
- repl_command(flags, repl_flags).boxed_local()
+ tools::repl::run(flags, repl_flags).await
}
DenoSubcommand::Run(run_flags) => {
- run_command(flags, run_flags).boxed_local()
+ if run_flags.is_stdin() {
+ tools::run::run_from_stdin(flags).await
+ } else {
+ tools::run::run_script(flags, run_flags).await
+ }
}
DenoSubcommand::Task(task_flags) => {
- task_command(flags, task_flags).boxed_local()
+ tools::task::execute_script(flags, task_flags).await
}
DenoSubcommand::Test(test_flags) => {
- test_command(flags, test_flags).boxed_local()
+ if let Some(ref coverage_dir) = flags.coverage_dir {
+ std::fs::create_dir_all(coverage_dir)
+ .with_context(|| format!("Failed creating: {}", coverage_dir))?;
+ // this is set in order to ensure spawned processes use the same
+ // coverage directory
+ env::set_var(
+ "DENO_UNSTABLE_COVERAGE_DIR",
+ PathBuf::from(coverage_dir).canonicalize()?,
+ );
+ }
+
+ if flags.watch.is_some() {
+ tools::test::run_tests_with_watch(flags, test_flags).await?;
+ } else {
+ tools::test::run_tests(flags, test_flags).await?;
+ }
+
+ Ok(0)
}
DenoSubcommand::Completions(completions_flags) => {
- completions_command(flags, completions_flags).boxed_local()
+ display::write_to_stdout_ignore_sigpipe(&completions_flags.buf)?;
+ Ok(0)
+ }
+ DenoSubcommand::Types => {
+ let types = tsc::get_types_declaration_file_text(flags.unstable);
+ display::write_to_stdout_ignore_sigpipe(types.as_bytes())?;
+ Ok(0)
}
- DenoSubcommand::Types => types_command(flags).boxed_local(),
DenoSubcommand::Upgrade(upgrade_flags) => {
- upgrade_command(flags, upgrade_flags).boxed_local()
+ tools::upgrade::upgrade(upgrade_flags).await?;
+ Ok(0)
}
DenoSubcommand::Vendor(vendor_flags) => {
- vendor_command(flags, vendor_flags).boxed_local()
+ tools::vendor::vendor(flags, vendor_flags).await?;
+ Ok(0)
}
}
}
@@ -906,7 +263,7 @@ pub fn main() {
let args: Vec<String> = env::args().collect();
- let exit_code = async move {
+ let future = async move {
let standalone_res =
match standalone::extract_standalone(args.clone()).await {
Ok(Some((metadata, eszip))) => standalone::run(eszip, metadata).await,
@@ -933,10 +290,10 @@ pub fn main() {
util::logger::init(flags.log_level);
- get_subcommand(flags).await
+ run_subcommand(flags).await
};
- let exit_code = unwrap_or_exit(run_local(exit_code));
+ let exit_code = unwrap_or_exit(run_local(future));
std::process::exit(exit_code);
}
diff --git a/cli/proc_state.rs b/cli/proc_state.rs
index 07f8a0860..5be3ae62e 100644
--- a/cli/proc_state.rs
+++ b/cli/proc_state.rs
@@ -41,6 +41,7 @@ use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::parking_lot::Mutex;
use deno_core::parking_lot::RwLock;
+use deno_core::resolve_url_or_path;
use deno_core::url::Url;
use deno_core::CompiledWasmModuleStore;
use deno_core::ModuleSpecifier;
@@ -469,6 +470,30 @@ impl ProcState {
Ok(())
}
+ /// Helper around prepare_module_load that loads and type checks
+ /// the provided files.
+ pub async fn load_and_type_check_files(
+ &self,
+ files: &[String],
+ ) -> Result<(), AnyError> {
+ let lib = self.options.ts_type_lib_window();
+
+ let specifiers = files
+ .iter()
+ .map(|file| resolve_url_or_path(file))
+ .collect::<Result<Vec<_>, _>>()?;
+ self
+ .prepare_module_load(
+ specifiers,
+ false,
+ lib,
+ Permissions::allow_all(),
+ Permissions::allow_all(),
+ false,
+ )
+ .await
+ }
+
/// Add the builtin node modules to the graph data.
pub async fn prepare_node_std_graph(&self) -> Result<(), AnyError> {
if self.node_std_graph_prepared.load(Ordering::Relaxed) {
diff --git a/cli/tools/bundle.rs b/cli/tools/bundle.rs
new file mode 100644
index 000000000..606bab46f
--- /dev/null
+++ b/cli/tools/bundle.rs
@@ -0,0 +1,158 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use std::path::PathBuf;
+use std::sync::Arc;
+
+use deno_core::error::AnyError;
+use deno_core::futures::FutureExt;
+use deno_core::resolve_url_or_path;
+use deno_runtime::colors;
+
+use crate::args::BundleFlags;
+use crate::args::CliOptions;
+use crate::args::Flags;
+use crate::args::TsConfigType;
+use crate::args::TypeCheckMode;
+use crate::graph_util::create_graph_and_maybe_check;
+use crate::graph_util::error_for_any_npm_specifier;
+use crate::proc_state::ProcState;
+use crate::util;
+use crate::util::display;
+use crate::util::file_watcher::ResolutionResult;
+
+pub async fn bundle(
+ flags: Flags,
+ bundle_flags: BundleFlags,
+) -> Result<(), AnyError> {
+ let cli_options = Arc::new(CliOptions::from_flags(flags)?);
+ let resolver = |_| {
+ let cli_options = cli_options.clone();
+ let source_file1 = bundle_flags.source_file.clone();
+ let source_file2 = bundle_flags.source_file.clone();
+ async move {
+ let module_specifier = resolve_url_or_path(&source_file1)?;
+
+ log::debug!(">>>>> bundle START");
+ let ps = ProcState::from_options(cli_options).await?;
+ let graph = create_graph_and_maybe_check(module_specifier, &ps).await?;
+
+ let mut paths_to_watch: Vec<PathBuf> = graph
+ .specifiers()
+ .filter_map(|(_, r)| {
+ r.as_ref().ok().and_then(|(s, _, _)| s.to_file_path().ok())
+ })
+ .collect();
+
+ if let Ok(Some(import_map_path)) = ps
+ .options
+ .resolve_import_map_specifier()
+ .map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
+ {
+ paths_to_watch.push(import_map_path);
+ }
+
+ Ok((paths_to_watch, graph, ps))
+ }
+ .map(move |result| match result {
+ Ok((paths_to_watch, graph, ps)) => ResolutionResult::Restart {
+ paths_to_watch,
+ result: Ok((ps, graph)),
+ },
+ Err(e) => ResolutionResult::Restart {
+ paths_to_watch: vec![PathBuf::from(source_file2)],
+ result: Err(e),
+ },
+ })
+ };
+
+ let operation = |(ps, graph): (ProcState, Arc<deno_graph::ModuleGraph>)| {
+ let out_file = bundle_flags.out_file.clone();
+ async move {
+ // at the moment, we don't support npm specifiers in deno bundle, so show an error
+ error_for_any_npm_specifier(&graph)?;
+
+ let bundle_output = bundle_module_graph(graph.as_ref(), &ps)?;
+ log::debug!(">>>>> bundle END");
+
+ if let Some(out_file) = out_file.as_ref() {
+ let output_bytes = bundle_output.code.as_bytes();
+ let output_len = output_bytes.len();
+ util::fs::write_file(out_file, output_bytes, 0o644)?;
+ log::info!(
+ "{} {:?} ({})",
+ colors::green("Emit"),
+ out_file,
+ colors::gray(display::human_size(output_len as f64))
+ );
+ if let Some(bundle_map) = bundle_output.maybe_map {
+ let map_bytes = bundle_map.as_bytes();
+ let map_len = map_bytes.len();
+ let ext = if let Some(curr_ext) = out_file.extension() {
+ format!("{}.map", curr_ext.to_string_lossy())
+ } else {
+ "map".to_string()
+ };
+ let map_out_file = out_file.with_extension(ext);
+ util::fs::write_file(&map_out_file, map_bytes, 0o644)?;
+ log::info!(
+ "{} {:?} ({})",
+ colors::green("Emit"),
+ map_out_file,
+ colors::gray(display::human_size(map_len as f64))
+ );
+ }
+ } else {
+ println!("{}", bundle_output.code);
+ }
+
+ Ok(())
+ }
+ };
+
+ if cli_options.watch_paths().is_some() {
+ util::file_watcher::watch_func(
+ resolver,
+ operation,
+ util::file_watcher::PrintConfig {
+ job_name: "Bundle".to_string(),
+ clear_screen: !cli_options.no_clear_screen(),
+ },
+ )
+ .await?;
+ } else {
+ let module_graph =
+ if let ResolutionResult::Restart { result, .. } = resolver(None).await {
+ result?
+ } else {
+ unreachable!();
+ };
+ operation(module_graph).await?;
+ }
+
+ Ok(())
+}
+
+fn bundle_module_graph(
+ graph: &deno_graph::ModuleGraph,
+ ps: &ProcState,
+) -> Result<deno_emit::BundleEmit, AnyError> {
+ log::info!("{} {}", colors::green("Bundle"), graph.roots[0].0);
+
+ let ts_config_result = ps
+ .options
+ .resolve_ts_config_for_emit(TsConfigType::Bundle)?;
+ if ps.options.type_check_mode() == TypeCheckMode::None {
+ if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
+ eprintln!("{}", ignored_options);
+ }
+ }
+
+ deno_emit::bundle_graph(
+ graph,
+ deno_emit::BundleOptions {
+ bundle_type: deno_emit::BundleType::Module,
+ emit_options: ts_config_result.ts_config.into(),
+ emit_ignore_directives: true,
+ },
+ )
+}
diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs
index aacaf3d83..04ed9d033 100644
--- a/cli/tools/coverage/mod.rs
+++ b/cli/tools/coverage/mod.rs
@@ -13,6 +13,7 @@ use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
+use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::sourcemap::SourceMap;
@@ -608,6 +609,10 @@ pub async fn cover_files(
flags: Flags,
coverage_flags: CoverageFlags,
) -> Result<(), AnyError> {
+ if coverage_flags.files.is_empty() {
+ return Err(generic_error("No matching coverage profiles found"));
+ }
+
let ps = ProcState::build(flags).await?;
let script_coverages =
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs
index 0e915677a..fd7f68b71 100644
--- a/cli/tools/installer.rs
+++ b/cli/tools/installer.rs
@@ -6,6 +6,7 @@ use crate::args::Flags;
use crate::args::InstallFlags;
use crate::args::TypeCheckMode;
use crate::npm::NpmPackageReference;
+use crate::proc_state::ProcState;
use crate::util::fs::canonicalize_path_maybe_not_exists;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
@@ -215,7 +216,21 @@ pub fn uninstall(name: String, root: Option<PathBuf>) -> Result<(), AnyError> {
Ok(())
}
-pub fn install(
+pub async fn install_command(
+ flags: Flags,
+ install_flags: InstallFlags,
+) -> Result<(), AnyError> {
+ // ensure the module is cached
+ ProcState::build(flags.clone())
+ .await?
+ .load_and_type_check_files(&[install_flags.module_url.clone()])
+ .await?;
+
+ // create the install shim
+ create_install_shim(flags, install_flags)
+}
+
+fn create_install_shim(
flags: Flags,
install_flags: InstallFlags,
) -> Result<(), AnyError> {
@@ -567,7 +582,7 @@ mod tests {
let bin_dir = temp_dir.path().join("bin");
std::fs::create_dir(&bin_dir).unwrap();
- install(
+ create_install_shim(
Flags {
unstable: true,
..Flags::default()
@@ -810,7 +825,7 @@ mod tests {
let local_module_url = Url::from_file_path(&local_module).unwrap();
let local_module_str = local_module.to_string_lossy();
- install(
+ create_install_shim(
Flags::default(),
InstallFlags {
module_url: local_module_str.to_string(),
@@ -838,7 +853,7 @@ mod tests {
let bin_dir = temp_dir.path().join("bin");
std::fs::create_dir(&bin_dir).unwrap();
- install(
+ create_install_shim(
Flags::default(),
InstallFlags {
module_url: "http://localhost:4545/echo_server.ts".to_string(),
@@ -857,7 +872,7 @@ mod tests {
assert!(file_path.exists());
// No force. Install failed.
- let no_force_result = install(
+ let no_force_result = create_install_shim(
Flags::default(),
InstallFlags {
module_url: "http://localhost:4545/cat.ts".to_string(), // using a different URL
@@ -877,7 +892,7 @@ mod tests {
assert!(file_content.contains("echo_server.ts"));
// Force. Install success.
- let force_result = install(
+ let force_result = create_install_shim(
Flags::default(),
InstallFlags {
module_url: "http://localhost:4545/cat.ts".to_string(), // using a different URL
@@ -903,7 +918,7 @@ mod tests {
let result = config_file.write_all(config.as_bytes());
assert!(result.is_ok());
- let result = install(
+ let result = create_install_shim(
Flags {
config_flag: ConfigFlag::Path(
config_file_path.to_string_lossy().to_string(),
@@ -936,7 +951,7 @@ mod tests {
let bin_dir = temp_dir.path().join("bin");
std::fs::create_dir(&bin_dir).unwrap();
- install(
+ create_install_shim(
Flags::default(),
InstallFlags {
module_url: "http://localhost:4545/echo_server.ts".to_string(),
@@ -976,7 +991,7 @@ mod tests {
let local_module_str = local_module.to_string_lossy();
std::fs::write(&local_module, "// Some JavaScript I guess").unwrap();
- install(
+ create_install_shim(
Flags::default(),
InstallFlags {
module_url: local_module_str.to_string(),
@@ -1016,7 +1031,7 @@ mod tests {
let result = import_map_file.write_all(import_map.as_bytes());
assert!(result.is_ok());
- let result = install(
+ let result = create_install_shim(
Flags {
import_map_path: Some(import_map_path.to_string_lossy().to_string()),
..Flags::default()
@@ -1062,7 +1077,7 @@ mod tests {
Url::from_file_path(module_path).unwrap().to_string();
assert!(file_module_string.starts_with("file:///"));
- let result = install(
+ let result = create_install_shim(
Flags::default(),
InstallFlags {
module_url: file_module_string.to_string(),
diff --git a/cli/tools/mod.rs b/cli/tools/mod.rs
index b992a2e9e..595fdd760 100644
--- a/cli/tools/mod.rs
+++ b/cli/tools/mod.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
pub mod bench;
+pub mod bundle;
pub mod check;
pub mod coverage;
pub mod doc;
@@ -10,6 +11,7 @@ pub mod init;
pub mod installer;
pub mod lint;
pub mod repl;
+pub mod run;
pub mod standalone;
pub mod task;
pub mod test;
diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs
index 502105139..cde4efa28 100644
--- a/cli/tools/repl/mod.rs
+++ b/cli/tools/repl/mod.rs
@@ -1,11 +1,13 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use crate::args::Flags;
use crate::args::ReplFlags;
use crate::colors;
use crate::proc_state::ProcState;
+use crate::worker::create_main_worker;
use deno_core::error::AnyError;
+use deno_core::resolve_url_or_path;
use deno_runtime::permissions::Permissions;
-use deno_runtime::worker::MainWorker;
use rustyline::error::ReadlineError;
mod cdp;
@@ -76,11 +78,17 @@ async fn read_eval_file(
Ok((*file.source).to_string())
}
-pub async fn run(
- ps: &ProcState,
- worker: MainWorker,
- repl_flags: ReplFlags,
-) -> Result<i32, AnyError> {
+pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result<i32, AnyError> {
+ let main_module = resolve_url_or_path("./$deno$repl.ts").unwrap();
+ let ps = ProcState::build(flags).await?;
+ let mut worker = create_main_worker(
+ &ps,
+ main_module.clone(),
+ Permissions::from_options(&ps.options.permissions_options())?,
+ )
+ .await?;
+ worker.setup_repl().await?;
+ let worker = worker.into_main_worker();
let mut repl_session = ReplSession::initialize(worker).await?;
let mut rustyline_channel = rustyline_channel();
let mut should_exit_on_interrupt = false;
@@ -95,7 +103,7 @@ pub async fn run(
if let Some(eval_files) = repl_flags.eval_files {
for eval_file in eval_files {
- match read_eval_file(ps, &eval_file).await {
+ match read_eval_file(&ps, &eval_file).await {
Ok(eval_source) => {
let output = repl_session
.evaluate_line_and_get_output(&eval_source)
diff --git a/cli/tools/run.rs b/cli/tools/run.rs
new file mode 100644
index 000000000..d714c55d3
--- /dev/null
+++ b/cli/tools/run.rs
@@ -0,0 +1,169 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use std::io::Read;
+use std::path::PathBuf;
+use std::sync::Arc;
+
+use deno_ast::MediaType;
+use deno_ast::ModuleSpecifier;
+use deno_core::error::AnyError;
+use deno_core::resolve_url_or_path;
+use deno_runtime::permissions::Permissions;
+
+use crate::args::EvalFlags;
+use crate::args::Flags;
+use crate::args::RunFlags;
+use crate::file_fetcher::File;
+use crate::npm::NpmPackageReference;
+use crate::proc_state::ProcState;
+use crate::util;
+use crate::worker::create_main_worker;
+
+pub async fn run_script(
+ flags: Flags,
+ run_flags: RunFlags,
+) -> Result<i32, AnyError> {
+ if !flags.has_permission() && flags.has_permission_in_argv() {
+ log::warn!(
+ "{}",
+ crate::colors::yellow(
+ r#"Permission flags have likely been incorrectly set after the script argument.
+To grant permissions, set them before the script argument. For example:
+ deno run --allow-read=. main.js"#
+ )
+ );
+ }
+
+ if flags.watch.is_some() {
+ return run_with_watch(flags, run_flags.script).await;
+ }
+
+ // TODO(bartlomieju): actually I think it will also fail if there's an import
+ // map specified and bare specifier is used on the command line - this should
+ // probably call `ProcState::resolve` instead
+ let ps = ProcState::build(flags).await?;
+
+ // Run a background task that checks for available upgrades. If an earlier
+ // run of this background task found a new version of Deno.
+ super::upgrade::check_for_upgrades(ps.dir.upgrade_check_file_path());
+
+ let main_module = if NpmPackageReference::from_str(&run_flags.script).is_ok()
+ {
+ ModuleSpecifier::parse(&run_flags.script)?
+ } else {
+ resolve_url_or_path(&run_flags.script)?
+ };
+ let permissions =
+ Permissions::from_options(&ps.options.permissions_options())?;
+ let mut worker =
+ create_main_worker(&ps, main_module.clone(), permissions).await?;
+
+ let exit_code = worker.run().await?;
+ Ok(exit_code)
+}
+
+pub async fn run_from_stdin(flags: Flags) -> Result<i32, AnyError> {
+ let ps = ProcState::build(flags).await?;
+ let main_module = resolve_url_or_path("./$deno$stdin.ts").unwrap();
+ let mut worker = create_main_worker(
+ &ps.clone(),
+ main_module.clone(),
+ Permissions::from_options(&ps.options.permissions_options())?,
+ )
+ .await?;
+
+ let mut source = Vec::new();
+ std::io::stdin().read_to_end(&mut source)?;
+ // Create a dummy source file.
+ let source_file = File {
+ local: main_module.clone().to_file_path().unwrap(),
+ maybe_types: None,
+ media_type: MediaType::TypeScript,
+ source: String::from_utf8(source)?.into(),
+ specifier: main_module.clone(),
+ maybe_headers: None,
+ };
+ // Save our fake file into file fetcher cache
+ // to allow module access by TS compiler
+ ps.file_fetcher.insert_cached(source_file);
+
+ let exit_code = worker.run().await?;
+ Ok(exit_code)
+}
+
+// TODO(bartlomieju): this function is not handling `exit_code` set by the runtime
+// code properly.
+async fn run_with_watch(flags: Flags, script: String) -> Result<i32, AnyError> {
+ let flags = Arc::new(flags);
+ let main_module = resolve_url_or_path(&script)?;
+ let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
+
+ let operation = |(sender, main_module): (
+ tokio::sync::mpsc::UnboundedSender<Vec<PathBuf>>,
+ ModuleSpecifier,
+ )| {
+ let flags = flags.clone();
+ Ok(async move {
+ let ps =
+ ProcState::build_for_file_watcher((*flags).clone(), sender.clone())
+ .await?;
+ let permissions =
+ Permissions::from_options(&ps.options.permissions_options())?;
+ let worker =
+ create_main_worker(&ps, main_module.clone(), permissions).await?;
+ worker.run_for_watcher().await?;
+
+ Ok(())
+ })
+ };
+
+ util::file_watcher::watch_func2(
+ receiver,
+ operation,
+ (sender, main_module),
+ util::file_watcher::PrintConfig {
+ job_name: "Process".to_string(),
+ clear_screen: !flags.no_clear_screen,
+ },
+ )
+ .await?;
+
+ Ok(0)
+}
+
+pub async fn eval_command(
+ flags: Flags,
+ eval_flags: EvalFlags,
+) -> Result<i32, AnyError> {
+ // deno_graph works off of extensions for local files to determine the media
+ // type, and so our "fake" specifier needs to have the proper extension.
+ let main_module =
+ resolve_url_or_path(&format!("./$deno$eval.{}", eval_flags.ext))?;
+ let ps = ProcState::build(flags).await?;
+ let permissions =
+ Permissions::from_options(&ps.options.permissions_options())?;
+ let mut worker =
+ create_main_worker(&ps, main_module.clone(), permissions).await?;
+ // Create a dummy source file.
+ let source_code = if eval_flags.print {
+ format!("console.log({})", eval_flags.code)
+ } else {
+ eval_flags.code
+ }
+ .into_bytes();
+
+ let file = File {
+ local: main_module.clone().to_file_path().unwrap(),
+ maybe_types: None,
+ media_type: MediaType::Unknown,
+ source: String::from_utf8(source_code)?.into(),
+ specifier: main_module.clone(),
+ maybe_headers: None,
+ };
+
+ // Save our fake file into file fetcher cache
+ // to allow module access by TS compiler.
+ ps.file_fetcher.insert_cached(file);
+ let exit_code = worker.run().await?;
+ Ok(exit_code)
+}
diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs
index 5e9867b12..f7a258a73 100644
--- a/cli/tools/standalone.rs
+++ b/cli/tools/standalone.rs
@@ -1,7 +1,10 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::args::CompileFlags;
+use crate::args::Flags;
use crate::cache::DenoDir;
+use crate::graph_util::create_graph_and_maybe_check;
+use crate::graph_util::error_for_any_npm_specifier;
use crate::standalone::Metadata;
use crate::standalone::MAGIC_TRAILER;
use crate::util::path::path_has_trailing_slash;
@@ -14,6 +17,7 @@ use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_graph::ModuleSpecifier;
+use deno_runtime::colors;
use deno_runtime::deno_fetch::reqwest::Client;
use deno_runtime::permissions::Permissions;
use std::env;
@@ -25,10 +29,59 @@ use std::io::SeekFrom;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
+use std::sync::Arc;
use super::installer::infer_name_from_url;
-pub async fn get_base_binary(
+pub async fn compile(
+ flags: Flags,
+ compile_flags: CompileFlags,
+) -> Result<(), AnyError> {
+ let ps = ProcState::build(flags.clone()).await?;
+ let module_specifier = resolve_url_or_path(&compile_flags.source_file)?;
+ let deno_dir = &ps.dir;
+
+ let output_path = resolve_compile_executable_output_path(&compile_flags)?;
+
+ let graph = Arc::try_unwrap(
+ create_graph_and_maybe_check(module_specifier.clone(), &ps).await?,
+ )
+ .unwrap();
+
+ // at the moment, we don't support npm specifiers in deno_compile, so show an error
+ error_for_any_npm_specifier(&graph)?;
+
+ graph.valid()?;
+
+ let parser = ps.parsed_source_cache.as_capturing_parser();
+ let eszip = eszip::EszipV2::from_graph(graph, &parser, Default::default())?;
+
+ log::info!(
+ "{} {}",
+ colors::green("Compile"),
+ module_specifier.to_string()
+ );
+
+ // Select base binary based on target
+ let original_binary =
+ get_base_binary(deno_dir, compile_flags.target.clone()).await?;
+
+ let final_bin = create_standalone_binary(
+ original_binary,
+ eszip,
+ module_specifier.clone(),
+ &compile_flags,
+ ps,
+ )
+ .await?;
+
+ log::info!("{} {}", colors::green("Emit"), output_path.display());
+
+ write_standalone_binary(output_path, final_bin).await?;
+ Ok(())
+}
+
+async fn get_base_binary(
deno_dir: &DenoDir,
target: Option<String>,
) -> Result<Vec<u8>, AnyError> {
@@ -90,7 +143,7 @@ async fn download_base_binary(
/// This functions creates a standalone deno binary by appending a bundle
/// and magic trailer to the currently executing binary.
-pub async fn create_standalone_binary(
+async fn create_standalone_binary(
mut original_bin: Vec<u8>,
eszip: eszip::EszipV2,
entrypoint: ModuleSpecifier,
@@ -159,7 +212,7 @@ pub async fn create_standalone_binary(
/// This function writes out a final binary to specified path. If output path
/// is not already standalone binary it will return error instead.
-pub async fn write_standalone_binary(
+async fn write_standalone_binary(
output_path: PathBuf,
final_bin: Vec<u8>,
) -> Result<(), AnyError> {
@@ -228,7 +281,7 @@ pub async fn write_standalone_binary(
Ok(())
}
-pub fn resolve_compile_executable_output_path(
+fn resolve_compile_executable_output_path(
compile_flags: &CompileFlags,
) -> Result<PathBuf, AnyError> {
let module_specifier = resolve_url_or_path(&compile_flags.source_file)?;