diff --git a/src/builder/pacman.rs b/src/builder/pacman.rs index f0fa34f..ef25968 100644 --- a/src/builder/pacman.rs +++ b/src/builder/pacman.rs @@ -1,6 +1,11 @@ use std::path::{Path, PathBuf}; -use crate::internal::{commands::ShellCommand, error::AppResult, structs::Options}; +use crate::internal::{ + commands::{ShellCommand, StringOutput}, + error::AppResult, + is_tty, + structs::Options, +}; #[derive(Debug, Default)] pub struct PacmanInstallBuilder { @@ -93,6 +98,7 @@ enum PacmanQueryType { All, Info, Native, + Orphaned, } #[derive(Clone, Copy, Debug)] @@ -134,6 +140,10 @@ impl PacmanQueryBuilder { Self::new(PacmanQueryType::Info) } + pub fn orphaned() -> Self { + Self::new(PacmanQueryType::Orphaned) + } + pub fn package(mut self, package: String) -> Self { self.packages.push(package); @@ -177,20 +187,32 @@ impl PacmanQueryBuilder { Ok(packages) } + pub async fn query_as_string_output(self) -> AppResult { + let output = self.build_command().wait_with_output().await?; + Ok(output) + } + fn build_command(self) -> ShellCommand { - let mut command = ShellCommand::pacman().arg("-Q").arg("--color").arg("never"); + let mut command = ShellCommand::pacman().arg("-Q"); command = match self.query_type { PacmanQueryType::Foreign => command.arg("-m"), PacmanQueryType::Info => command.arg("-i"), PacmanQueryType::Native => command.arg("-n"), + PacmanQueryType::Orphaned => command.arg("-dtq"), PacmanQueryType::All => command, }; command = command.arg("--color"); command = match self.color { PacmanColor::Always => command.arg("always"), - PacmanColor::Auto => command.arg("auto"), + PacmanColor::Auto => { + if is_tty() { + command.arg("always") + } else { + command.arg("never") + } + } PacmanColor::Never => command.arg("never"), }; @@ -235,6 +257,8 @@ impl PacmanSearchBuilder { pub struct PacmanUninstallBuilder { packages: Vec, no_confirm: bool, + no_save: bool, + recursive: bool, } impl PacmanUninstallBuilder { @@ -251,6 +275,18 @@ impl PacmanUninstallBuilder { self } + pub fn no_save(mut self, no_save: bool) -> Self { + self.no_save = no_save; + + self + } + + pub fn recursive(mut self, recursive: bool) -> Self { + self.recursive = recursive; + + self + } + #[tracing::instrument(level = "trace")] pub async fn uninstall(self) -> AppResult<()> { let mut command = ShellCommand::pacman() @@ -262,6 +298,14 @@ impl PacmanUninstallBuilder { command = command.arg("--noconfirm"); } + if self.no_save { + command = command.arg("-n") + } + + if self.recursive { + command = command.arg("-s") + } + command.wait_success().await } } diff --git a/src/internal/commands.rs b/src/internal/commands.rs index e2ef0c9..d9fc695 100644 --- a/src/internal/commands.rs +++ b/src/internal/commands.rs @@ -25,13 +25,7 @@ pub struct ShellCommand { impl ShellCommand { pub fn pacman() -> Self { - let pacman_cmd = Self::new("pacman"); - - if is_tty() { - pacman_cmd.arg("--color=always") - } else { - pacman_cmd - } + Self::new("pacman") } pub fn paccache() -> Self { diff --git a/src/operations/clean.rs b/src/operations/clean.rs index b8943b9..cc5c2a7 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -1,11 +1,10 @@ use crate::builder::paccache::PaccacheBuilder; use crate::builder::pacman::PacmanQueryBuilder; +use crate::builder::pacman::PacmanUninstallBuilder; use crate::builder::rm::RmBuilder; use crate::crash; -use crate::internal::commands::ShellCommand; use crate::internal::config::Config; -use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; use crate::internal::utils::get_cache_dir; @@ -19,11 +18,10 @@ pub async fn clean(options: Options) { let quiet = options.quiet; // Check for orphaned packages - let orphaned_packages = ShellCommand::pacman() - .arg("-Qdtq") - .wait_with_output() + let orphaned_packages = PacmanQueryBuilder::orphaned() + .query_as_string_output() .await - .silent_unwrap(AppExitCode::PacmanError); + .unwrap(); if orphaned_packages.stdout.as_str().is_empty() { // If no orphaned packages found, do nothing @@ -32,7 +30,7 @@ pub async fn clean(options: Options) { // Prompt users whether to remove orphaned packages tracing::info!( "Removing orphans would uninstall the following packages: \n{}", - &orphaned_packages.stdout + &orphaned_packages.stdout.trim_end() ); let cont = prompt!(default no, "Continue?"); if !cont { @@ -41,37 +39,28 @@ pub async fn clean(options: Options) { std::process::exit(AppExitCode::PacmanError as i32); } - // Build pacman args - let mut pacman_args = vec!["-Rns"]; - if noconfirm { - pacman_args.push("--noconfirm"); - } - // Collect orphaned packages into a vector - let orphaned_packages_vec = orphaned_packages.stdout.split('\n').collect::>(); - for package in &orphaned_packages_vec { - if !package.is_empty() { - pacman_args.push(package); - } - } + let orphaned_packages_vec = orphaned_packages + .stdout + .trim_end() + .split('\n') + .collect::>(); tracing::debug!("Removing orphans: {:?}", orphaned_packages_vec); // Remove orphaned packages - let pacman_result = ShellCommand::pacman() - .elevated() - .args(pacman_args) - .wait() + PacmanUninstallBuilder::default() + .no_save(true) + .recursive(true) + .no_confirm(noconfirm) + .packages(orphaned_packages_vec) + .uninstall() .await - .silent_unwrap(AppExitCode::PacmanError); - - if pacman_result.success() { - // If pacman succeeded, notify user - tracing::info!("Successfully removed orphans"); - } else { - // If pacman failed, crash - crash!(AppExitCode::PacmanError, "Failed to remove orphans",); - } + .unwrap_or_else(|_| { + crash!(AppExitCode::PacmanError, "Failed to remove orphans",); + }); + + tracing::info!("Successfully removed orphans"); } // Prompt the user whether to clear the Amethyst cache