From 5319b85f14d919c8a3f390a8db53c95922f1cf8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 5 Sep 2024 12:51:37 +0100 Subject: [PATCH] feat(uninstall): alias to 'deno remove' if -g flag missing (#25461) Close https://github.com/denoland/deno/issues/25457 --- cli/args/flags.rs | 104 ++++++++++++++++++++--------- cli/main.rs | 2 +- cli/tools/installer.rs | 38 +++++------ tests/integration/install_tests.rs | 6 +- 4 files changed, 96 insertions(+), 54 deletions(-) diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 9397f21807..d81e9e9493 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -253,7 +253,6 @@ pub enum InstallFlagsLocal { #[derive(Clone, Debug, Eq, PartialEq)] pub struct InstallFlags { - pub global: bool, pub kind: InstallKind, } @@ -277,14 +276,12 @@ pub struct UninstallFlagsGlobal { #[derive(Clone, Debug, Eq, PartialEq)] pub enum UninstallKind { - #[allow(unused)] - Local, + Local(RemoveFlags), Global(UninstallFlagsGlobal), } #[derive(Clone, Debug, Eq, PartialEq)] pub struct UninstallFlags { - pub global: bool, pub kind: UninstallKind, } @@ -2493,11 +2490,12 @@ fn jupyter_subcommand() -> Command { fn uninstall_subcommand() -> Command { command( "uninstall", - cstr!("Uninstalls an executable script in the installation root's bin directory. - deno uninstall serve + cstr!("Uninstalls a dependency or an executable script in the installation root's bin directory. + deno uninstall @std/dotenv chalk + deno uninstall --global file_server To change the installation root, use --root flag: - deno uninstall --root /usr/local serve + deno uninstall --global --root /usr/local serve The installation root is determined, in order of precedence: - --root option @@ -2507,11 +2505,12 @@ The installation root is determined, in order of precedence: ) .defer(|cmd| { cmd - .arg(Arg::new("name").required_unless_present("help")) + .arg(Arg::new("name-or-package").required_unless_present("help")) .arg( Arg::new("root") .long("root") .help("Installation root") + .requires("global") .value_hint(ValueHint::DirPath), ) .arg( @@ -2521,6 +2520,13 @@ The installation root is determined, in order of precedence: .help("Remove globally installed package or module") .action(ArgAction::SetTrue), ) + .arg( + Arg::new("additional-packages") + .help("List of additional packages to remove") + .conflicts_with("global") + .num_args(1..) + .action(ArgAction::Append) + ) }) } @@ -4430,8 +4436,6 @@ fn install_parse(flags: &mut Flags, matches: &mut ArgMatches) { let args = cmd_values.collect(); flags.subcommand = DenoSubcommand::Install(InstallFlags { - // TODO(bartlomieju): remove for 2.0 - global, kind: InstallKind::Global(InstallFlagsGlobal { name, module_url, @@ -4448,7 +4452,6 @@ fn install_parse(flags: &mut Flags, matches: &mut ArgMatches) { if matches.get_flag("entrypoint") { let entrypoints = matches.remove_many::("cmd").unwrap_or_default(); flags.subcommand = DenoSubcommand::Install(InstallFlags { - global, kind: InstallKind::Local(InstallFlagsLocal::Entrypoints( entrypoints.collect(), )), @@ -4458,12 +4461,10 @@ fn install_parse(flags: &mut Flags, matches: &mut ArgMatches) { .map(|packages| add_parse_inner(matches, Some(packages))) { flags.subcommand = DenoSubcommand::Install(InstallFlags { - global, kind: InstallKind::Local(InstallFlagsLocal::Add(add_files)), }) } else { flags.subcommand = DenoSubcommand::Install(InstallFlags { - global, kind: InstallKind::Local(InstallFlagsLocal::TopLevel), }); } @@ -4554,15 +4555,24 @@ fn jupyter_parse(flags: &mut Flags, matches: &mut ArgMatches) { } fn uninstall_parse(flags: &mut Flags, matches: &mut ArgMatches) { - let root = matches.remove_one::("root"); - let global = matches.get_flag("global"); - let name = matches.remove_one::("name").unwrap(); - flags.subcommand = DenoSubcommand::Uninstall(UninstallFlags { - // TODO(bartlomieju): remove once `deno uninstall` supports both local and - // global installs - global, - kind: UninstallKind::Global(UninstallFlagsGlobal { name, root }), - }); + let name = matches.remove_one::("name-or-package").unwrap(); + + let kind = if matches.get_flag("global") { + let root = matches.remove_one::("root"); + UninstallKind::Global(UninstallFlagsGlobal { name, root }) + } else { + let packages: Vec<_> = vec![name] + .into_iter() + .chain( + matches + .remove_many::("additional-packages") + .unwrap_or_default(), + ) + .collect(); + UninstallKind::Local(RemoveFlags { packages }) + }; + + flags.subcommand = DenoSubcommand::Uninstall(UninstallFlags { kind }); } fn lsp_parse(flags: &mut Flags, _matches: &mut ArgMatches) { @@ -7896,7 +7906,6 @@ mod tests { root: None, force: false, }), - global: true, }), ..Flags::default() } @@ -7919,7 +7928,6 @@ mod tests { root: None, force: false, }), - global: true, }), ..Flags::default() } @@ -7941,7 +7949,6 @@ mod tests { root: Some("/foo".to_string()), force: true, }), - global: true, }), import_map_path: Some("import_map.json".to_string()), no_remote: true, @@ -7968,16 +7975,31 @@ mod tests { #[test] fn uninstall() { - let r = flags_from_vec(svec!["deno", "uninstall", "file_server"]); + let r = flags_from_vec(svec!["deno", "uninstall"]); + assert!(r.is_err(),); + + let r = flags_from_vec(svec!["deno", "uninstall", "@std/load"]); assert_eq!( r.unwrap(), Flags { subcommand: DenoSubcommand::Uninstall(UninstallFlags { - kind: UninstallKind::Global(UninstallFlagsGlobal { - name: "file_server".to_string(), - root: None, + kind: UninstallKind::Local(RemoveFlags { + packages: vec!["@std/load".to_string()], + }), + }), + ..Flags::default() + } + ); + + let r = + flags_from_vec(svec!["deno", "uninstall", "file_server", "@std/load"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Uninstall(UninstallFlags { + kind: UninstallKind::Local(RemoveFlags { + packages: vec!["file_server".to_string(), "@std/load".to_string()], }), - global: false, }), ..Flags::default() } @@ -7992,7 +8014,27 @@ mod tests { name: "file_server".to_string(), root: None, }), - global: true, + }), + ..Flags::default() + } + ); + + let r = flags_from_vec(svec![ + "deno", + "uninstall", + "-g", + "--root", + "/user/foo/bar", + "file_server" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Uninstall(UninstallFlags { + kind: UninstallKind::Global(UninstallFlagsGlobal { + name: "file_server".to_string(), + root: Some("/user/foo/bar".to_string()), + }), }), ..Flags::default() } diff --git a/cli/main.rs b/cli/main.rs index c0899ee100..3b366306ab 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -161,7 +161,7 @@ async fn run_subcommand(flags: Arc) -> Result { tools::jupyter::kernel(flags, jupyter_flags).await }), DenoSubcommand::Uninstall(uninstall_flags) => spawn_subcommand(async { - tools::installer::uninstall(uninstall_flags) + tools::installer::uninstall(flags, uninstall_flags).await }), DenoSubcommand::Lsp => spawn_subcommand(async { lsp::start().await }), DenoSubcommand::Lint(lint_flags) => spawn_subcommand(async { diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index 987f3c0694..065c5aa1ca 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -198,14 +198,15 @@ pub async fn infer_name_from_url( Some(stem.to_string()) } -pub fn uninstall(uninstall_flags: UninstallFlags) -> Result<(), AnyError> { - if !uninstall_flags.global { - log::warn!("⚠️ `deno install` behavior will change in Deno 2. To preserve the current behavior use the `-g` or `--global` flag."); - } - +pub async fn uninstall( + flags: Arc, + uninstall_flags: UninstallFlags, +) -> Result<(), AnyError> { let uninstall_flags = match uninstall_flags.kind { UninstallKind::Global(flags) => flags, - UninstallKind::Local => unreachable!(), + UninstallKind::Local(remove_flags) => { + return super::registry::remove(flags, remove_flags).await; + } }; let cwd = std::env::current_dir().context("Unable to get CWD")?; @@ -332,10 +333,6 @@ pub async fn install_command( ) -> Result<(), AnyError> { match install_flags.kind { InstallKind::Global(global_flags) => { - if !install_flags.global { - log::warn!("⚠️ `deno install` behavior will change in Deno 2. To preserve the current behavior use the `-g` or `--global` flag."); - } - install_global(flags, global_flags).await } InstallKind::Local(local_flags) => { @@ -1512,8 +1509,8 @@ mod tests { assert!(content.contains(&expected_string)); } - #[test] - fn uninstall_basic() { + #[tokio::test] + async fn uninstall_basic() { let temp_dir = TempDir::new(); let bin_dir = temp_dir.path().join("bin"); std::fs::create_dir(&bin_dir).unwrap(); @@ -1540,13 +1537,16 @@ mod tests { File::create(file_path).unwrap(); } - uninstall(UninstallFlags { - kind: UninstallKind::Global(UninstallFlagsGlobal { - name: "echo_test".to_string(), - root: Some(temp_dir.path().to_string()), - }), - global: false, - }) + uninstall( + Default::default(), + UninstallFlags { + kind: UninstallKind::Global(UninstallFlagsGlobal { + name: "echo_test".to_string(), + root: Some(temp_dir.path().to_string()), + }), + }, + ) + .await .unwrap(); assert!(!file_path.exists()); diff --git a/tests/integration/install_tests.rs b/tests/integration/install_tests.rs index 7d671e0209..2c7725443c 100644 --- a/tests/integration/install_tests.rs +++ b/tests/integration/install_tests.rs @@ -62,7 +62,7 @@ fn install_basic() { // now uninstall context .new_command() - .args("uninstall echo_test") + .args("uninstall -g echo_test") .envs([ ("HOME", temp_dir_str.as_str()), ("USERPROFILE", temp_dir_str.as_str()), @@ -139,7 +139,7 @@ fn install_basic_global() { // now uninstall context .new_command() - .args("uninstall echo_test") + .args("uninstall -g echo_test") .envs([ ("HOME", temp_dir_str.as_str()), ("USERPROFILE", temp_dir_str.as_str()), @@ -274,7 +274,7 @@ fn installer_test_remote_module_run() { // now uninstall with the relative path context .new_command() - .args("uninstall --root ./root echo_test") + .args("uninstall -g --root ./root echo_test") .run() .skip_output_check() .assert_exit_code(0);