diff options
Diffstat (limited to 'cli/tools/installer.rs')
-rw-r--r-- | cli/tools/installer.rs | 419 |
1 files changed, 184 insertions, 235 deletions
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index e762e064c..383bf74cf 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -46,11 +46,12 @@ fn validate_name(exec_name: &str) -> Result<(), AnyError> { /// One compatible with cmd & powershell with a .cmd extension /// A second compatible with git bash / MINGW64 /// Generate batch script to satisfy that. -fn generate_executable_file( - mut file_path: PathBuf, - args: Vec<String>, -) -> Result<(), AnyError> { - let args: Vec<String> = args.iter().map(|c| format!("\"{}\"", c)).collect(); +fn generate_executable_file(shim_data: &ShimData) -> Result<(), AnyError> { + let args: Vec<String> = shim_data + .args + .iter() + .map(|c| format!("\"{}\"", c)) + .collect(); let template = format!( "% generated by deno install %\n@deno {} %*\n", args @@ -59,12 +60,11 @@ fn generate_executable_file( .collect::<Vec<_>>() .join(" ") ); - let mut file = File::create(&file_path)?; + let mut file = File::create(&shim_data.file_path)?; file.write_all(template.as_bytes())?; // write file for bash // create filepath without extensions - file_path.set_extension(""); let template = format!( r#"#!/bin/sh # generated by deno install @@ -72,19 +72,17 @@ deno {} "$@" "#, args.join(" "), ); - let mut file = File::create(&file_path)?; + let mut file = File::create(&shim_data.file_path.with_extension(""))?; file.write_all(template.as_bytes())?; Ok(()) } #[cfg(not(windows))] -fn generate_executable_file( - file_path: PathBuf, - args: Vec<String>, -) -> Result<(), AnyError> { +fn generate_executable_file(shim_data: &ShimData) -> Result<(), AnyError> { use shell_escape::escape; - let args: Vec<String> = args - .into_iter() + let args: Vec<String> = shim_data + .args + .iter() .map(|c| escape(c.into()).into_owned()) .collect(); let template = format!( @@ -94,12 +92,12 @@ exec deno {} "$@" "#, args.join(" "), ); - let mut file = File::create(&file_path)?; + let mut file = File::create(&shim_data.file_path)?; file.write_all(template.as_bytes())?; - let _metadata = fs::metadata(&file_path)?; + let _metadata = fs::metadata(&shim_data.file_path)?; let mut permissions = _metadata.permissions(); permissions.set_mode(0o755); - fs::set_permissions(&file_path, permissions)?; + fs::set_permissions(&shim_data.file_path, permissions)?; Ok(()) } @@ -195,27 +193,73 @@ pub fn install( flags: Flags, install_flags: InstallFlags, ) -> Result<(), AnyError> { - let root = if let Some(root) = install_flags.root { - canonicalize_path(&root)? - } else { - get_installer_root()? - }; - let installation_dir = root.join("bin"); + let shim_data = resolve_shim_data(&flags, &install_flags)?; // ensure directory exists - if let Ok(metadata) = fs::metadata(&installation_dir) { + if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) { if !metadata.is_dir() { return Err(generic_error("Installation path is not a directory")); } } else { - fs::create_dir_all(&installation_dir)?; + fs::create_dir_all(&shim_data.installation_dir)?; }; + if shim_data.file_path.exists() && !install_flags.force { + return Err(generic_error( + "Existing installation found. Aborting (Use -f to overwrite).", + )); + }; + + generate_executable_file(&shim_data)?; + for (path, contents) in shim_data.extra_files { + fs::write(path, contents)?; + } + + println!("✅ Successfully installed {}", shim_data.name); + println!("{}", shim_data.file_path.display()); + if cfg!(windows) { + let display_path = shim_data.file_path.with_extension(""); + println!("{} (shell)", display_path.display()); + } + let installation_dir_str = shim_data.installation_dir.to_string_lossy(); + + if !is_in_path(&shim_data.installation_dir) { + println!("ℹ️ Add {} to PATH", installation_dir_str); + if cfg!(windows) { + println!(" set PATH=%PATH%;{}", installation_dir_str); + } else { + println!(" export PATH=\"{}:$PATH\"", installation_dir_str); + } + } + + Ok(()) +} + +struct ShimData { + name: String, + installation_dir: PathBuf, + file_path: PathBuf, + args: Vec<String>, + extra_files: Vec<(PathBuf, String)>, +} + +fn resolve_shim_data( + flags: &Flags, + install_flags: &InstallFlags, +) -> Result<ShimData, AnyError> { + let root = if let Some(root) = &install_flags.root { + canonicalize_path(root)? + } else { + get_installer_root()? + }; + let installation_dir = root.join("bin"); + // Check if module_url is remote let module_url = resolve_url_or_path(&install_flags.module_url)?; let name = install_flags .name + .clone() .or_else(|| infer_name_from_url(&module_url)); let name = match name { @@ -232,12 +276,6 @@ pub fn install( file_path = file_path.with_extension("cmd"); } - if file_path.exists() && !install_flags.force { - return Err(generic_error( - "Existing installation found. Aborting (Use -f to overwrite).", - )); - }; - let mut extra_files: Vec<(PathBuf, String)> = vec![]; let mut executable_args = vec!["run".to_string()]; @@ -246,9 +284,9 @@ pub fn install( executable_args.push("--location".to_string()); executable_args.push(url.to_string()); } - if let Some(ca_file) = flags.ca_file { + if let Some(ca_file) = &flags.ca_file { executable_args.push("--cert".to_string()); - executable_args.push(ca_file) + executable_args.push(ca_file.to_owned()) } if let Some(log_level) = flags.log_level { if log_level == Level::Error { @@ -311,13 +349,13 @@ pub fn install( executable_args.push(format!("--inspect-brk={}", inspect_brk.to_string())); } - if let Some(import_map_path) = flags.import_map_path { - let import_map_url = resolve_url_or_path(&import_map_path)?; + if let Some(import_map_path) = &flags.import_map_path { + let import_map_url = resolve_url_or_path(import_map_path)?; executable_args.push("--import-map".to_string()); executable_args.push(import_map_url.to_string()); } - if let Some(config_path) = flags.config_path { + if let Some(config_path) = &flags.config_path { let mut copy_path = file_path.clone(); copy_path.set_extension("tsconfig.json"); executable_args.push("--config".to_string()); @@ -325,7 +363,7 @@ pub fn install( extra_files.push((copy_path, fs::read_to_string(config_path)?)); } - if let Some(lock_path) = flags.lock { + if let Some(lock_path) = &flags.lock { let mut copy_path = file_path.clone(); copy_path.set_extension("lock.json"); executable_args.push("--lock".to_string()); @@ -336,29 +374,13 @@ pub fn install( executable_args.push(module_url.to_string()); executable_args.extend_from_slice(&install_flags.args); - generate_executable_file(file_path.to_owned(), executable_args)?; - for (path, contents) in extra_files { - fs::write(path, contents)?; - } - - println!("✅ Successfully installed {}", name); - println!("{}", file_path.to_string_lossy()); - if cfg!(windows) { - file_path.set_extension(""); - println!("{} (shell)", file_path.to_string_lossy()); - } - let installation_dir_str = installation_dir.to_string_lossy(); - - if !is_in_path(&installation_dir) { - println!("ℹ️ Add {} to PATH", installation_dir_str); - if cfg!(windows) { - println!(" set PATH=%PATH%;{}", installation_dir_str); - } else { - println!(" export PATH=\"{}:$PATH\"", installation_dir_str); - } - } - - Ok(()) + Ok(ShimData { + name, + installation_dir, + file_path, + args: executable_args, + extra_files, + }) } fn is_in_path(dir: &Path) -> bool { @@ -484,6 +506,16 @@ mod tests { ) .expect("Install failed"); + if let Some(home) = original_home { + env::set_var("HOME", home); + } + if let Some(user_profile) = original_user_profile { + env::set_var("USERPROFILE", user_profile); + } + if let Some(install_root) = original_install_root { + env::set_var("DENO_INSTALL_ROOT", install_root); + } + let mut file_path = temp_dir.path().join(".deno/bin/echo_test"); assert!(file_path.exists()); @@ -502,15 +534,6 @@ mod tests { } else { assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#)); } - if let Some(home) = original_home { - env::set_var("HOME", home); - } - if let Some(user_profile) = original_user_profile { - env::set_var("USERPROFILE", user_profile); - } - if let Some(install_root) = original_install_root { - env::set_var("DENO_INSTALL_ROOT", install_root); - } } #[test] @@ -554,142 +577,66 @@ mod tests { } #[test] - fn install_prompt() { - let temp_dir = TempDir::new().expect("tempdir fail"); - let bin_dir = temp_dir.path().join("bin"); - std::fs::create_dir(&bin_dir).unwrap(); - - install( - Flags { - prompt: true, - ..Flags::default() - }, - InstallFlags { - module_url: "http://localhost:4545/echo_server.ts".to_string(), - args: vec![], - name: Some("echo_test".to_string()), - root: Some(temp_dir.path().to_path_buf()), - force: false, - }, - ) - .unwrap(); - - let mut file_path = bin_dir.join("echo_test"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } - - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!(content.contains( - r#""run" "--prompt" "http://localhost:4545/echo_server.ts""# - )); - } else { - assert!(content - .contains(r#"run --prompt 'http://localhost:4545/echo_server.ts'"#)); - } - } - - #[test] fn install_inferred_name() { - let temp_dir = TempDir::new().expect("tempdir fail"); - let bin_dir = temp_dir.path().join("bin"); - std::fs::create_dir(&bin_dir).unwrap(); - - install( - Flags::default(), - InstallFlags { + let shim_data = resolve_shim_data( + &Flags::default(), + &InstallFlags { module_url: "http://localhost:4545/echo_server.ts".to_string(), args: vec![], name: None, - root: Some(temp_dir.path().to_path_buf()), + root: Some(env::temp_dir()), force: false, }, ) - .expect("Install failed"); - - let mut file_path = bin_dir.join("echo_server"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } + .unwrap(); - assert!(file_path.exists()); - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!( - content.contains(r#""run" "http://localhost:4545/echo_server.ts""#) - ); - } else { - assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#)); - } + assert_eq!(shim_data.name, "echo_server"); + assert_eq!( + shim_data.args, + vec!["run", "http://localhost:4545/echo_server.ts",] + ); } #[test] fn install_inferred_name_from_parent() { - let temp_dir = TempDir::new().expect("tempdir fail"); - let bin_dir = temp_dir.path().join("bin"); - std::fs::create_dir(&bin_dir).unwrap(); - - install( - Flags::default(), - InstallFlags { + let shim_data = resolve_shim_data( + &Flags::default(), + &InstallFlags { module_url: "http://localhost:4545/subdir/main.ts".to_string(), args: vec![], name: None, - root: Some(temp_dir.path().to_path_buf()), + root: Some(env::temp_dir()), force: false, }, ) - .expect("Install failed"); - - let mut file_path = bin_dir.join("subdir"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } + .unwrap(); - assert!(file_path.exists()); - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!( - content.contains(r#""run" "http://localhost:4545/subdir/main.ts""#) - ); - } else { - assert!(content.contains(r#"run 'http://localhost:4545/subdir/main.ts'"#)); - } + assert_eq!(shim_data.name, "subdir"); + assert_eq!( + shim_data.args, + vec!["run", "http://localhost:4545/subdir/main.ts",] + ); } #[test] fn install_custom_dir_option() { - let temp_dir = TempDir::new().expect("tempdir fail"); - let bin_dir = temp_dir.path().join("bin"); - std::fs::create_dir(&bin_dir).unwrap(); - - install( - Flags::default(), - InstallFlags { + let shim_data = resolve_shim_data( + &Flags::default(), + &InstallFlags { module_url: "http://localhost:4545/echo_server.ts".to_string(), args: vec![], name: Some("echo_test".to_string()), - root: Some(temp_dir.path().to_path_buf()), + root: Some(env::temp_dir()), force: false, }, ) - .expect("Install failed"); - - let mut file_path = bin_dir.join("echo_test"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } + .unwrap(); - assert!(file_path.exists()); - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!( - content.contains(r#""run" "http://localhost:4545/echo_server.ts""#) - ); - } else { - assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#)); - } + assert_eq!(shim_data.name, "echo_test"); + assert_eq!( + shim_data.args, + vec!["run", "http://localhost:4545/echo_server.ts",] + ); } #[test] @@ -701,9 +648,9 @@ mod tests { let original_install_root = env::var_os("DENO_INSTALL_ROOT"); env::set_var("DENO_INSTALL_ROOT", temp_dir.path().to_path_buf()); - install( - Flags::default(), - InstallFlags { + let shim_data = resolve_shim_data( + &Flags::default(), + &InstallFlags { module_url: "http://localhost:4545/echo_server.ts".to_string(), args: vec![], name: Some("echo_test".to_string()), @@ -711,100 +658,102 @@ mod tests { force: false, }, ) - .expect("Install failed"); - - let mut file_path = bin_dir.join("echo_test"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } + .unwrap(); - assert!(file_path.exists()); - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!( - content.contains(r#""run" "http://localhost:4545/echo_server.ts""#) - ); - } else { - assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#)); - } if let Some(install_root) = original_install_root { env::set_var("DENO_INSTALL_ROOT", install_root); } + + assert_eq!( + fs::canonicalize(shim_data.installation_dir).unwrap(), + fs::canonicalize(bin_dir).unwrap() + ); + assert_eq!(shim_data.name, "echo_test"); + assert_eq!( + shim_data.args, + vec!["run", "http://localhost:4545/echo_server.ts",] + ); } #[test] fn install_with_flags() { - let temp_dir = TempDir::new().expect("tempdir fail"); - let bin_dir = temp_dir.path().join("bin"); - std::fs::create_dir(&bin_dir).unwrap(); - - install( - Flags { + let shim_data = resolve_shim_data( + &Flags { allow_net: Some(vec![]), allow_read: Some(vec![]), check: CheckFlag::None, log_level: Some(Level::Error), ..Flags::default() }, - InstallFlags { + &InstallFlags { module_url: "http://localhost:4545/echo_server.ts".to_string(), args: vec!["--foobar".to_string()], name: Some("echo_test".to_string()), - root: Some(temp_dir.path().to_path_buf()), + root: Some(env::temp_dir()), force: false, }, ) - .expect("Install failed"); + .unwrap(); - let mut file_path = bin_dir.join("echo_test"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } + assert_eq!(shim_data.name, "echo_test"); + assert_eq!( + shim_data.args, + vec![ + "run", + "--allow-read", + "--allow-net", + "--quiet", + "--no-check", + "http://localhost:4545/echo_server.ts", + "--foobar", + ] + ); + } - assert!(file_path.exists()); - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!(content.contains(r#""run" "--allow-read" "--allow-net" "--quiet" "--no-check" "http://localhost:4545/echo_server.ts" "--foobar""#)); - } else { - assert!(content.contains(r#"run --allow-read --allow-net --quiet --no-check 'http://localhost:4545/echo_server.ts' --foobar"#)); - } + #[test] + fn install_prompt() { + let shim_data = resolve_shim_data( + &Flags { + prompt: true, + ..Flags::default() + }, + &InstallFlags { + module_url: "http://localhost:4545/echo_server.ts".to_string(), + args: vec![], + name: Some("echo_test".to_string()), + root: Some(env::temp_dir()), + force: false, + }, + ) + .unwrap(); + + assert_eq!( + shim_data.args, + vec!["run", "--prompt", "http://localhost:4545/echo_server.ts",] + ); } #[test] fn install_allow_all() { - let temp_dir = TempDir::new().expect("tempdir fail"); - let bin_dir = temp_dir.path().join("bin"); - std::fs::create_dir(&bin_dir).unwrap(); - - install( - Flags { + let shim_data = resolve_shim_data( + &Flags { allow_all: true, ..Flags::default() }, - InstallFlags { + &InstallFlags { module_url: "http://localhost:4545/echo_server.ts".to_string(), args: vec![], name: Some("echo_test".to_string()), - root: Some(temp_dir.path().to_path_buf()), + root: Some(env::temp_dir()), force: false, }, ) .unwrap(); - let mut file_path = bin_dir.join("echo_test"); - if cfg!(windows) { - file_path = file_path.with_extension("cmd"); - } - - let content = fs::read_to_string(file_path).unwrap(); - if cfg!(windows) { - assert!(content.contains( - r#""run" "--allow-all" "http://localhost:4545/echo_server.ts""# - )); - } else { - assert!(content - .contains(r#"run --allow-all 'http://localhost:4545/echo_server.ts'"#)); - } + assert_eq!( + shim_data.args, + vec!["run", "--allow-all", "http://localhost:4545/echo_server.ts",] + ); } #[test] |