use std::path::Path;
use std::process::Command;
use std::time::SystemTime;
pub fn get_file_db_sync_timestamp() -> Option<SystemTime> {
let sync_dir = Path::new("/var/lib/pacman/sync");
if !sync_dir.exists() {
tracing::debug!("Pacman sync directory does not exist");
return None;
}
let mut latest_time: Option<SystemTime> = None;
if let Ok(entries) = std::fs::read_dir(sync_dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("files")
&& let Ok(metadata) = std::fs::metadata(&path)
&& let Ok(modified) = metadata.modified()
{
latest_time = Some(latest_time.map_or(modified, |prev| {
if modified > prev { modified } else { prev }
}));
}
}
}
latest_time
}
#[must_use]
pub fn get_file_db_sync_info() -> Option<(u64, String, u8)> {
let sync_time = get_file_db_sync_timestamp()?;
let now = SystemTime::now();
let age = now.duration_since(sync_time).ok()?;
let age_days = age.as_secs() / 86400;
let date_str = crate::util::ts_to_date(
sync_time
.duration_since(SystemTime::UNIX_EPOCH)
.ok()
.and_then(|d| i64::try_from(d.as_secs()).ok()),
);
let color_category = if age_days < 7 {
0 } else if age_days < 30 {
1 } else {
2 };
Some((age_days, date_str, color_category))
}
#[must_use]
pub fn is_file_db_stale(max_age_days: u64) -> Option<bool> {
let sync_time = get_file_db_sync_timestamp()?;
let now = SystemTime::now();
let age = now.duration_since(sync_time).ok()?;
let age_days = age.as_secs() / 86400;
Some(age_days >= max_age_days)
}
pub fn ensure_file_db_synced(force: bool, max_age_days: u64) -> Result<bool, String> {
if force {
tracing::debug!("Force syncing pacman file database...");
} else if let Some(is_stale) = is_file_db_stale(max_age_days) {
if is_stale {
tracing::debug!(
"File database is stale (older than {} days), syncing...",
max_age_days
);
} else {
tracing::debug!("File database is fresh, skipping sync");
return Ok(false);
}
} else {
tracing::debug!("Cannot determine file database timestamp, attempting sync...");
}
let output = Command::new("pacman")
.args(["-Fy"])
.env("LC_ALL", "C")
.env("LANG", "C")
.output()
.map_err(|e| format!("Failed to execute pacman -Fy: {e}"))?;
if output.status.success() {
tracing::debug!("File database sync successful");
Ok(true)
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
let error_msg = format!("File database sync failed: {stderr}");
tracing::warn!("{}", error_msg);
Err(error_msg)
}
}