use super::pkgbuild_cache::{PkgbuildSourceKind, parse_pkgbuild_cached};
use super::pkgbuild_fetch::{fetch_pkgbuild_sync, fetch_srcinfo_sync};
use super::pkgbuild_parse::parse_backup_from_srcinfo;
use crate::state::types::Source;
use std::process::Command;
pub fn get_backup_files(name: &str, source: &Source) -> Result<Vec<String>, String> {
if let Ok(backup_files) = get_backup_files_from_installed(name)
&& !backup_files.is_empty()
{
tracing::debug!(
"Found {} backup files from installed package {}",
backup_files.len(),
name
);
return Ok(backup_files);
}
match source {
Source::Official { .. } => {
match fetch_pkgbuild_sync(name) {
Ok(pkgbuild) => {
let entry =
parse_pkgbuild_cached(name, None, PkgbuildSourceKind::Official, &pkgbuild);
let backup_files = entry.backup_files;
if !backup_files.is_empty() {
tracing::debug!(
"Found {} backup files from PKGBUILD for {}",
backup_files.len(),
name
);
return Ok(backup_files);
}
}
Err(e) => {
tracing::debug!("Failed to fetch PKGBUILD for {}: {}", name, e);
}
}
Ok(Vec::new())
}
Source::Aur => {
match fetch_srcinfo_sync(name) {
Ok(srcinfo) => {
let backup_files = parse_backup_from_srcinfo(&srcinfo);
if !backup_files.is_empty() {
tracing::debug!(
"Found {} backup files from .SRCINFO for {}",
backup_files.len(),
name
);
return Ok(backup_files);
}
}
Err(e) => {
tracing::debug!("Failed to fetch .SRCINFO for {}: {}", name, e);
}
}
match fetch_pkgbuild_sync(name) {
Ok(pkgbuild) => {
let entry =
parse_pkgbuild_cached(name, None, PkgbuildSourceKind::Aur, &pkgbuild);
let backup_files = entry.backup_files;
if !backup_files.is_empty() {
tracing::debug!(
"Found {} backup files from PKGBUILD for {}",
backup_files.len(),
name
);
return Ok(backup_files);
}
}
Err(e) => {
tracing::debug!("Failed to fetch PKGBUILD for {}: {}", name, e);
}
}
Ok(Vec::new())
}
}
}
pub fn get_backup_files_from_installed(name: &str) -> Result<Vec<String>, String> {
tracing::debug!("Running: pacman -Qii {}", name);
let output = Command::new("pacman")
.args(["-Qii", name])
.env("LC_ALL", "C")
.env("LANG", "C")
.output()
.map_err(|e| {
tracing::error!("Failed to execute pacman -Qii {}: {}", name, e);
format!("pacman -Qii failed: {e}")
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
if stderr.contains("was not found") {
tracing::debug!("Package {} is not installed", name);
return Ok(Vec::new());
}
tracing::error!(
"pacman -Qii {} failed with status {:?}: {}",
name,
output.status.code(),
stderr
);
return Err(format!("pacman -Qii failed for {name}: {stderr}"));
}
let text = String::from_utf8_lossy(&output.stdout);
let mut backup_files = Vec::new();
let mut in_backup_section = false;
for line in text.lines() {
if line.starts_with("Backup Files") {
in_backup_section = true;
if let Some(colon_pos) = line.find(':') {
let files_str = line[colon_pos + 1..].trim();
if !files_str.is_empty() && files_str != "None" {
for file in files_str.split_whitespace() {
backup_files.push(file.to_string());
}
}
}
} else if in_backup_section {
if line.starts_with(" ") || line.starts_with('\t') {
for file in line.split_whitespace() {
backup_files.push(file.to_string());
}
} else {
break;
}
}
}
tracing::debug!(
"Found {} backup files for installed package {}",
backup_files.len(),
name
);
Ok(backup_files)
}