From 3f0307aab929ed83e2f602cf33763162095cd343 Mon Sep 17 00:00:00 2001 From: Rabindra Dhakal Date: Sat, 2 Nov 2024 20:57:57 +0545 Subject: [PATCH] fix(remove): improve package removal --- src/cli.rs | 4 +++ src/lib.rs | 4 +-- src/package/mod.rs | 10 +------- src/package/remove.rs | 30 +++++++--------------- src/registry/installed.rs | 36 ++++++++++++++------------ src/registry/mod.rs | 6 +++-- src/registry/storage.rs | 54 ++++++++++++++++++++++++++++++++++----- 7 files changed, 87 insertions(+), 57 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 8d5e929..7d23623 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -81,6 +81,10 @@ pub enum Commands { /// Packages to remove #[arg(required = true)] packages: Vec, + + /// Remove exact package only + #[arg(required = false, long, short)] + exact: bool, }, /// Sync with remote metadata diff --git a/src/lib.rs b/src/lib.rs index 8eeab36..0295efd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,8 +70,8 @@ pub async fn init() -> Result<()> { // nothing to do here // it can be used to force sync without doing any other operation } - Commands::Remove { packages } => { - registry.remove_packages(&packages).await?; + Commands::Remove { packages, exact } => { + registry.remove_packages(&packages, exact).await?; } Commands::Update { packages } => { registry.update(packages.as_deref()).await?; diff --git a/src/package/mod.rs b/src/package/mod.rs index e531b39..22ee353 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -1,7 +1,7 @@ mod appimage; pub mod image; mod install; -mod remove; +pub mod remove; pub mod run; pub mod update; @@ -10,7 +10,6 @@ use std::{path::PathBuf, sync::Arc}; use anyhow::Result; use indicatif::MultiProgress; use install::Installer; -use remove::Remover; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; @@ -73,13 +72,6 @@ impl ResolvedPackage { .await?; Ok(()) } - - pub async fn remove(&self) -> Result<()> { - let remover = Remover::new(self).await?; - let mut installed_packages = InstalledPackages::new().await?; - remover.execute(&mut installed_packages).await?; - Ok(()) - } } impl Package { diff --git a/src/package/remove.rs b/src/package/remove.rs index 8e15946..f354047 100644 --- a/src/package/remove.rs +++ b/src/package/remove.rs @@ -9,42 +9,30 @@ use crate::{ constant::BIN_PATH, }, package::appimage::remove_applinks, - registry::installed::InstalledPackages, + registry::installed::{InstalledPackage, InstalledPackages}, success, }; -use super::ResolvedPackage; - pub struct Remover { - resolved_package: ResolvedPackage, + package: InstalledPackage, } impl Remover { - pub async fn new(resolved_package: &ResolvedPackage) -> Result { + pub async fn new(package: &InstalledPackage) -> Result { Ok(Self { - resolved_package: resolved_package.to_owned(), + package: package.clone(), }) } pub async fn execute(&self, installed_packages: &mut InstalledPackages) -> Result<()> { - let package = &self.resolved_package.package; - let installed = installed_packages.find_package(&self.resolved_package); - let Some(installed) = installed else { - return Err(anyhow::anyhow!( - "Package {}-{} is not installed.", - package.full_name('/').color(Color::Blue), - package.version.clone().color(Color::Green) - )); - }; + let package = &self.package; - let install_dir = package.get_install_dir(&installed.checksum); - let install_path = package.get_install_path(&installed.checksum); + let install_dir = package.get_install_dir(); + let install_path = package.get_install_path(); self.remove_symlink(&install_path).await?; remove_applinks(&package.name, &package.bin_name, &install_path).await?; self.remove_package_path(&install_dir).await?; - installed_packages - .unregister_package(&self.resolved_package) - .await?; + installed_packages.unregister_package(&self.package).await?; success!( "Package {} removed successfully.", @@ -55,7 +43,7 @@ impl Remover { } pub async fn remove_symlink(&self, install_path: &Path) -> Result<()> { - let package = &self.resolved_package.package; + let package = &self.package; let symlink_path = BIN_PATH.join(&package.bin_name); if symlink_path.exists() { let target = fs::read_link(&symlink_path).await?; diff --git a/src/registry/installed.rs b/src/registry/installed.rs index 422b542..50e0daa 100644 --- a/src/registry/installed.rs +++ b/src/registry/installed.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; use anyhow::{Context, Result}; use chrono::{DateTime, Utc}; @@ -8,10 +8,10 @@ use tokio::fs; use crate::{ core::{ color::{Color, ColorExt}, - constant::{BIN_PATH, INSTALL_TRACK_PATH}, + constant::{BIN_PATH, INSTALL_TRACK_PATH, PACKAGES_PATH}, util::{format_bytes, parse_size}, }, - package::{parse_package_query, ResolvedPackage}, + package::{parse_package_query, remove::Remover, ResolvedPackage}, }; use super::storage::PackageStorage; @@ -111,25 +111,21 @@ impl InstalledPackages { Ok(()) } - pub async fn unregister_package(&mut self, resolved_package: &ResolvedPackage) -> Result<()> { - match self.is_installed(resolved_package) { - true => { - self.packages.retain(|installed| { - installed.full_name('-') != resolved_package.package.full_name('-') - }); - } - false => { - return Err(anyhow::anyhow!( - "Package is not registered to install database." - )) - } - }; + pub async fn unregister_package(&mut self, installed_package: &InstalledPackage) -> Result<()> { + self.packages + .retain(|installed| installed.full_name('-') != installed_package.full_name('-')); self.save().await?; Ok(()) } + pub async fn remove(&mut self, installed_package: &InstalledPackage) -> Result<()> { + let remover = Remover::new(installed_package).await?; + remover.execute(self).await?; + Ok(()) + } + pub async fn save(&self) -> Result<()> { let path = INSTALL_TRACK_PATH.join("latest"); @@ -259,4 +255,12 @@ impl InstalledPackage { .unwrap_or_default(); format!("{}{}", family_prefix, self.name) } + + pub fn get_install_dir(&self) -> PathBuf { + PACKAGES_PATH.join(format!("{}-{}", &self.checksum[..8], self.full_name('-'))) + } + + pub fn get_install_path(&self) -> PathBuf { + self.get_install_dir().join(&self.bin_name) + } } diff --git a/src/registry/mod.rs b/src/registry/mod.rs index e740333..ad40b6c 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -105,8 +105,10 @@ impl PackageRegistry { .await } - pub async fn remove_packages(&self, package_names: &[String]) -> Result<()> { - self.storage.remove_packages(package_names).await + pub async fn remove_packages(&self, package_names: &[String], exact: bool) -> Result<()> { + self.storage + .remove_packages(package_names, self.installed_packages.clone(), exact) + .await } pub async fn search(&self, package_name: &str, case_sensitive: bool) -> Result<()> { diff --git a/src/registry/storage.rs b/src/registry/storage.rs index 1c1253b..32daf49 100644 --- a/src/registry/storage.rs +++ b/src/registry/storage.rs @@ -200,13 +200,53 @@ impl PackageStorage { Ok(()) } - pub async fn remove_packages(&self, package_names: &[String]) -> Result<()> { - let resolved_packages: Vec = package_names - .iter() - .filter_map(|package_name| self.resolve_package(package_name, false).ok()) - .collect(); - for package in resolved_packages { - package.remove().await?; + pub async fn remove_packages( + &self, + package_names: &[String], + installed_packages: Arc>, + exact: bool, + ) -> Result<()> { + let mut mut_guard = installed_packages.lock().await; + let installed_packages = &mut_guard.packages; + + let mut packages_to_remove = Vec::new(); + for package_name in package_names.iter() { + let query = parse_package_query(package_name); + let mut matching_packages = Vec::new(); + + for package in installed_packages { + if package.name != query.name { + continue; + } + if let Some(ref ckey) = query.collection { + if package.collection != *ckey { + continue; + } + } + + let family_matches = match (&query.family, &package.family) { + (None, None) => true, + (None, Some(_)) => !exact, + (Some(ref query_family), Some(ref package_family)) => { + query_family == package_family + } + _ => false, + }; + + if family_matches { + matching_packages.push(package.clone()); + } + } + + if matching_packages.is_empty() { + error!("{} is not installed.", package_name); + } else { + packages_to_remove.extend(matching_packages); + } + } + + for package in packages_to_remove { + mut_guard.remove(&package).await?; } Ok(())