use super::{PackageError, PackageManager}; use std::io::Write; use std::process::{Command, Stdio}; pub struct Pacman { dry_run: bool, use_sudo: bool, } impl Pacman { pub fn new() -> Self { Self { dry_run: false, use_sudo: true, } } pub fn dry_run(mut self, dry_run: bool) -> Self { self.dry_run = dry_run; self } pub fn use_sudo(mut self, use_sudo: bool) -> Self { self.use_sudo = use_sudo; self } fn run_pacman(&self, args: &[&str]) -> Result<(), PackageError> { if self.dry_run { let prefix = if self.use_sudo { "sudo " } else { "" }; println!("[dry-run] {}pacman {}", prefix, args.join(" ")); return Ok(()); } let output = if self.use_sudo { Command::new("sudo").arg("pacman").args(args).output()? } else { Command::new("pacman").args(args).output()? }; if !output.status.success() { return Err(PackageError::InstallFailed { package: args.join(" "), message: String::from_utf8_lossy(&output.stderr).to_string(), }); } Ok(()) } fn run_pacman_with_password(&self, args: &[&str], password: &str) -> Result<(), PackageError> { if self.dry_run { println!("[dry-run] sudo pacman {}", args.join(" ")); return Ok(()); } let mut child = Command::new("sudo") .arg("-S") .arg("pacman") .args(args) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn()?; if let Some(mut stdin) = child.stdin.take() { writeln!(stdin, "{}", password).ok(); } let output = child.wait_with_output()?; if !output.status.success() { return Err(PackageError::InstallFailed { package: args.join(" "), message: String::from_utf8_lossy(&output.stderr).to_string(), }); } Ok(()) } } impl PackageManager for Pacman { fn name(&self) -> &'static str { "pacman" } fn is_available(&self) -> bool { std::path::Path::new("/usr/bin/pacman").exists() } fn needs_sudo(&self) -> bool { self.use_sudo } fn install(&self, packages: &[String]) -> Result<(), PackageError> { if packages.is_empty() { return Ok(()); } let mut args = vec!["-S", "--noconfirm"]; for pkg in packages { args.push(pkg); } self.run_pacman(&args) } fn install_with_sudo(&self, packages: &[String], password: &str) -> Result<(), PackageError> { if packages.is_empty() { return Ok(()); } let mut args = vec!["-S", "--noconfirm"]; for pkg in packages { args.push(pkg); } self.run_pacman_with_password(&args, password) } fn uninstall(&self, packages: &[String]) -> Result<(), PackageError> { if packages.is_empty() { return Ok(()); } let mut args = vec!["-R", "--noconfirm"]; for pkg in packages { args.push(pkg); } self.run_pacman(&args) } fn is_installed(&self, package: &str) -> Result { let output = Command::new("pacman").args(["-Q", package]).output()?; Ok(output.status.success()) } fn update(&self) -> Result<(), PackageError> { self.run_pacman(&["-Sy"]) } fn upgrade(&self) -> Result<(), PackageError> { self.run_pacman(&["-Syu", "--noconfirm"]) } } impl Default for Pacman { fn default() -> Self { Self::new() } }