summaryrefslogtreecommitdiff
path: root/cli/tools
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools')
-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
7 files changed, 432 insertions, 22 deletions
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)?;