156 lines
3.8 KiB
Rust
156 lines
3.8 KiB
Rust
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
|
|
}
|
|
|
|
#[tracing::instrument(skip(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(())
|
|
}
|
|
|
|
#[tracing::instrument(skip(self, password))]
|
|
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<bool, PackageError> {
|
|
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()
|
|
}
|
|
}
|