From efc32a0452f273ff5f943b8ad46f46a51f9eae52 Mon Sep 17 00:00:00 2001 From: Guilherme Soares Date: Tue, 16 Jan 2024 18:51:40 +0000 Subject: [PATCH] add: uninstall prompt when no version is specified --- README.md | 5 ++- src/cli.rs | 7 ++-- src/handlers/uninstall_handler.rs | 63 ++++++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 67783c8..225a35a 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,10 @@ If Config::version_sync_file_location is set, the version in that file will be p --- -- `bob uninstall |nightly|stable|latest|||` +- `bob uninstall [|nightly|stable|latest|||]` -Uninstall the specified version. +Uninstall the specified version. If no version is specified a prompt is used to select all the versions +to be uninstalled. --- diff --git a/src/cli.rs b/src/cli.rs index f521dd6..ad2df56 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -60,8 +60,9 @@ enum Cli { /// Uninstall the specified version #[clap(visible_alias = "rm")] Uninstall { - /// Version to be uninstalled |nightly|stable||| - version: String, + /// Optional Version to be uninstalled |nightly|stable||| + /// If no Version is provided a prompt is used to select the versions to be uninstalled + version: Option, }, /// Rollback to an existing nightly rollback @@ -134,7 +135,7 @@ pub async fn start(config: Config) -> Result<()> { } Cli::Uninstall { version } => { info!("Starting uninstallation process"); - uninstall_handler::start(&version, config).await?; + uninstall_handler::start(version.as_deref(), config).await?; } Cli::Rollback => rollback_handler::start(config).await?, Cli::Erase => erase_handler::start(config).await?, diff --git a/src/handlers/uninstall_handler.rs b/src/handlers/uninstall_handler.rs index 7164650..7d7b453 100644 --- a/src/handlers/uninstall_handler.rs +++ b/src/handlers/uninstall_handler.rs @@ -1,4 +1,5 @@ use anyhow::{anyhow, Result}; +use dialoguer::{console::Term, theme::ColorfulTheme, Confirm, MultiSelect}; use reqwest::Client; use tokio::fs; use tracing::{info, warn}; @@ -8,10 +9,15 @@ use crate::{ helpers::{self, directories}, }; -pub async fn start(version: &str, config: Config) -> Result<()> { +pub async fn start(version: Option<&str>, config: Config) -> Result<()> { let client = Client::new(); - let version = helpers::version::parse_version_type(&client, version).await?; + let version = match version { + Some(value) => value, + None => return uninstall_selections(&client, &config).await, + }; + + let version = helpers::version::parse_version_type(&client, version).await?; if helpers::version::is_version_used(&version.tag_name, &config).await { warn!("Switch to a different version before proceeding"); return Ok(()); @@ -28,3 +34,56 @@ pub async fn start(version: &str, config: Config) -> Result<()> { info!("Successfully uninstalled version: {}", version.tag_name); Ok(()) } + +async fn uninstall_selections(client: &Client, config: &Config) -> Result<()> { + let downloads_dir = directories::get_downloads_directory(&config).await?; + + let mut paths = fs::read_dir(downloads_dir.clone()).await?; + let mut installed_versions: Vec = Vec::new(); + + while let Some(path) = paths.next_entry().await? { + let name = path.file_name().to_str().unwrap().to_owned(); + + let version = match helpers::version::parse_version_type(&client, &name).await { + Ok(value) => value, + Err(_) => continue, + }; + + if helpers::version::is_version_used(&version.tag_name, &config).await { + continue; + } + installed_versions.push(version.tag_name); + } + + let selections = MultiSelect::with_theme(&ColorfulTheme::default()) + .with_prompt("Toogle with space the versions you wish to uninstall:") + .items(&installed_versions) + .interact_on_opt(&Term::stderr())?; + + match &selections { + Some(ids) if (ids.len() > 0) => { + let confirm = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Do you wish to continue?") + .interact_on_opt(&Term::stderr())?; + + match confirm { + Some(true) => {} + None | Some(false) => { + info!("Uninstall aborted..."); + return Ok(()); + } + } + + for &i in ids { + let path = downloads_dir.join(&installed_versions[i]); + fs::remove_dir_all(path).await?; + info!( + "Successfully uninstalled version: {}", + &installed_versions[i] + ); + } + } + None | Some(_) => info!("Uninstall aborted..."), + } + return Ok(()); +}