diff --git a/cli/installer.rs b/cli/installer.rs index 78840b92947487..52fc3d17046fb2 100644 --- a/cli/installer.rs +++ b/cli/installer.rs @@ -1,5 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::flags::Flags; +use crate::global_state::GlobalState; +use deno_core::ErrBox; use log::Level; use regex::{Regex, RegexBuilder}; use std::env; @@ -79,6 +81,22 @@ deno {} "$@" Ok(()) } +async fn generate_bundle( + flags: Flags, + module_url: &str, + script_path: PathBuf, +) -> Result<(), ErrBox> { + let global_state = GlobalState::new(flags)?; + global_state + .ts_compiler + .bundle( + global_state.clone(), + module_url.to_owned(), + Some(script_path), + ) + .await +} + fn get_installer_root() -> Result { if let Ok(env_dir) = env::var("DENO_INSTALL_ROOT") { if !env_dir.is_empty() { @@ -121,14 +139,14 @@ fn infer_name_from_url(url: &Url) -> Option { Some(stem) } -pub fn install( +pub async fn install( flags: Flags, module_url: &str, args: Vec, name: Option, root: Option, force: bool, -) -> Result<(), Error> { +) -> Result<(), ErrBox> { let root = if let Some(root) = root { root.canonicalize()? } else { @@ -139,10 +157,10 @@ pub fn install( // ensure directory exists if let Ok(metadata) = fs::metadata(&installation_dir) { if !metadata.is_dir() { - return Err(Error::new( + return Err(ErrBox::from(Error::new( ErrorKind::Other, "Installation path is not a directory", - )); + ))); } } else { fs::create_dir_all(&installation_dir)?; @@ -166,29 +184,30 @@ pub fn install( let name = match name { Some(name) => name, - None => return Err(Error::new( + None => return Err(ErrBox::from(Error::new( ErrorKind::Other, "An executable name was not provided. One could not be inferred from the URL. Aborting.", - )), + ))), }; validate_name(name.as_str())?; let mut file_path = installation_dir.join(&name); + let script_path = file_path.with_extension("js"); if cfg!(windows) { file_path = file_path.with_extension("cmd"); } if file_path.exists() && !force { - return Err(Error::new( + return Err(ErrBox::from(Error::new( ErrorKind::Other, "Existing installation found. Aborting (Use -f to overwrite).", - )); + ))); }; let mut executable_args = vec!["run".to_string()]; executable_args.extend_from_slice(&flags.to_permission_args()); - if let Some(ca_file) = flags.ca_file { + if let Some(ca_file) = flags.ca_file.clone() { executable_args.push("--cert".to_string()); executable_args.push(ca_file) } @@ -201,10 +220,10 @@ pub fn install( Level::Debug => "debug", Level::Info => "info", _ => { - return Err(Error::new( + return Err(ErrBox::from(Error::new( ErrorKind::Other, format!("invalid log level {}", log_level), - )) + ))) } }; executable_args.push(log_level.to_string()); @@ -215,10 +234,11 @@ pub fn install( executable_args.push("--unstable".to_string()); } - executable_args.push(module_url.to_string()); + executable_args.push(script_path.to_string_lossy().to_string()); executable_args.extend_from_slice(&args); generate_executable_file(file_path.to_owned(), executable_args)?; + generate_bundle(flags, module_url.as_str(), script_path).await?; println!("✅ Successfully installed {}", name); println!("{}", file_path.to_string_lossy()); @@ -322,9 +342,10 @@ mod tests { assert_eq!(infer_name_from_url(&Url::parse("file:///").unwrap()), None); } - #[test] - fn install_basic() { + #[tokio::test] + async fn install_basic() { let _guard = ENV_LOCK.lock().ok(); + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let temp_dir_str = temp_dir.path().to_string_lossy().to_string(); // NOTE: this test overrides environmental variables @@ -346,6 +367,7 @@ mod tests { None, false, ) + .await .expect("Install failed"); let mut file_path = temp_dir.path().join(".deno/bin/echo_test"); @@ -359,8 +381,8 @@ mod tests { // It's annoying when shell scripts don't have NL at the end. assert_eq!(content.chars().last().unwrap(), '\n'); - assert!(content - .contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#)); + assert!(content.contains(r#""run""#)); + assert!(content.contains(r#"echo_test.js"#)); if let Some(home) = original_home { env::set_var("HOME", home); } @@ -370,10 +392,13 @@ mod tests { if let Some(install_root) = original_install_root { env::set_var("DENO_INSTALL_ROOT", install_root); } + + drop(http_server_guard); } - #[test] - fn install_unstable() { + #[tokio::test] + async fn install_unstable() { + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -389,6 +414,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_test"); @@ -397,16 +423,19 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); let content = fs::read_to_string(file_path).unwrap(); println!("this is the file path {:?}", content); - assert!(content.contains( - r#""run" "--unstable" "http://localhost:4545/cli/tests/echo_server.ts"# - )); + assert!(content.contains(r#""run" "--unstable""#)); + assert!(content.contains(r#"echo_test.js"#)); + + drop(http_server_guard); } - #[test] - fn install_inferred_name() { + #[tokio::test] + async fn install_inferred_name() { + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -419,6 +448,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_server"); @@ -427,13 +457,18 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); + let content = fs::read_to_string(file_path).unwrap(); - assert!(content - .contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#)); + assert!(content.contains(r#""run""#)); + assert!(content.contains(r#"echo_server.js"#)); + + drop(http_server_guard); } - #[test] - fn install_inferred_name_from_parent() { + #[tokio::test] + async fn install_inferred_name_from_parent() { + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -446,6 +481,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("subdir"); @@ -454,13 +490,18 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); + let content = fs::read_to_string(file_path).unwrap(); - assert!(content - .contains(r#""run" "http://localhost:4545/cli/tests/subdir/main.ts""#)); + assert!(content.contains(r#""run""#)); + assert!(content.contains(r#"subdir.js"#)); + + drop(http_server_guard); } - #[test] - fn install_custom_dir_option() { + #[tokio::test] + async fn install_custom_dir_option() { + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -473,6 +514,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_test"); @@ -481,14 +523,19 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); + let content = fs::read_to_string(file_path).unwrap(); - assert!(content - .contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#)); + assert!(content.contains(r#""run""#)); + assert!(content.contains(r#"echo_test.js"#)); + + drop(http_server_guard); } - #[test] - fn install_custom_dir_env_var() { + #[tokio::test] + async fn install_custom_dir_env_var() { let _guard = ENV_LOCK.lock().ok(); + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -503,6 +550,7 @@ mod tests { None, false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_test"); @@ -511,16 +559,22 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); + let content = fs::read_to_string(file_path).unwrap(); - assert!(content - .contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#)); + assert!(content.contains(r#""run""#)); + assert!(content.contains(r#"echo_test.js"#)); + if let Some(install_root) = original_install_root { env::set_var("DENO_INSTALL_ROOT", install_root); } + + drop(http_server_guard); } - #[test] - fn install_with_flags() { + #[tokio::test] + async fn install_with_flags() { + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -538,6 +592,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_test"); @@ -546,17 +601,21 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); + let content = fs::read_to_string(file_path).unwrap(); - assert!(content.contains(r#""run" "--allow-read" "--allow-net" "--quiet" "http://localhost:4545/cli/tests/echo_server.ts" "--foobar""#)); + assert!(content.contains(r#""run""#)); + assert!(content.contains(r#"echo_test.js"#)); + + drop(http_server_guard); } - #[test] - fn install_local_module() { + #[tokio::test] + async fn install_local_module() { let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); - let local_module = env::current_dir().unwrap().join("echo_server.ts"); - let local_module_url = Url::from_file_path(&local_module).unwrap(); + let local_module = env::current_dir().unwrap().join("tests/echo_server.ts"); let local_module_str = local_module.to_string_lossy(); install( @@ -567,6 +626,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_test"); @@ -575,12 +635,14 @@ mod tests { } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); let content = fs::read_to_string(file_path).unwrap(); - assert!(content.contains(&local_module_url.to_string())); + assert!(content.contains("echo_test.js")); } - #[test] - fn install_force() { + #[tokio::test] + async fn install_force() { + let http_server_guard = crate::test_util::http_server(); let temp_dir = TempDir::new().expect("tempdir fail"); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -593,6 +655,7 @@ mod tests { Some(temp_dir.path().to_path_buf()), false, ) + .await .expect("Install failed"); let mut file_path = bin_dir.join("echo_test"); @@ -600,16 +663,21 @@ mod tests { file_path = file_path.with_extension("cmd"); } assert!(file_path.exists()); + assert!(file_path.with_extension("js").exists()); // No force. Install failed. let no_force_result = install( - Flags::default(), + Flags { + unstable: true, + ..Flags::default() + }, "http://localhost:4545/cli/tests/cat.ts", // using a different URL vec![], Some("echo_test".to_string()), Some(temp_dir.path().to_path_buf()), false, - ); + ) + .await; assert!(no_force_result.is_err()); assert!(no_force_result .unwrap_err() @@ -617,20 +685,26 @@ mod tests { .contains("Existing installation found")); // Assert not modified let file_content = fs::read_to_string(&file_path).unwrap(); - assert!(file_content.contains("echo_server.ts")); + assert!(!file_content.contains("--unstable")); // Force. Install success. let force_result = install( - Flags::default(), + Flags { + unstable: true, + ..Flags::default() + }, "http://localhost:4545/cli/tests/cat.ts", // using a different URL vec![], Some("echo_test".to_string()), Some(temp_dir.path().to_path_buf()), true, - ); + ) + .await; assert!(force_result.is_ok()); // Assert modified let file_content_2 = fs::read_to_string(&file_path).unwrap(); - assert!(file_content_2.contains("cat.ts")); + assert!(file_content_2.contains("--unstable")); + + drop(http_server_guard); } } diff --git a/cli/main.rs b/cli/main.rs index 68ba5e7763c5c3..5811f4a9ea0068 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -307,15 +307,7 @@ async fn install_command( root: Option, force: bool, ) -> Result<(), ErrBox> { - // Firstly fetch and compile module, this step ensures that module exists. - let mut fetch_flags = flags.clone(); - fetch_flags.reload = true; - 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, &module_url, args, name, root, force) - .map_err(ErrBox::from) + installer::install(flags, &module_url, args, name, root, force).await } async fn cache_command(flags: Flags, files: Vec) -> Result<(), ErrBox> {