use super::installed_lock;
pub async fn refresh_installed_cache() {
if let Ok(Ok(body)) =
tokio::task::spawn_blocking(|| crate::util::pacman::run_pacman(&["-Qq"])).await
{
let set: std::collections::HashSet<String> =
body.lines().map(|s| s.trim().to_string()).collect();
if let Ok(mut g) = installed_lock().write() {
*g = set;
}
}
}
#[must_use]
pub fn is_installed(name: &str) -> bool {
installed_lock()
.read()
.ok()
.is_some_and(|s| s.contains(name))
}
#[cfg(test)]
mod tests {
#[test]
fn is_installed_returns_false_when_uninitialized_or_missing() {
let _guard = crate::global_test_mutex()
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if let Ok(mut g) = super::installed_lock().write() {
g.clear();
}
assert!(!super::is_installed("foo"));
}
#[test]
fn is_installed_checks_membership_in_cached_set() {
let _guard = crate::global_test_mutex()
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if let Ok(mut g) = super::installed_lock().write() {
g.clear();
g.insert("bar".to_string());
}
assert!(super::is_installed("bar"));
assert!(!super::is_installed("baz"));
}
#[cfg(not(target_os = "windows"))]
#[allow(clippy::await_holding_lock)]
#[tokio::test]
async fn refresh_installed_cache_populates_cache_from_pacman_output() {
struct PathGuard {
original: String,
}
impl Drop for PathGuard {
fn drop(&mut self) {
unsafe {
std::env::set_var("PATH", &self.original);
}
}
}
let _guard = crate::global_test_mutex_lock();
if let Ok(mut g) = super::installed_lock().write() {
g.clear();
}
let original_path = std::env::var("PATH").unwrap_or_default();
let _path_guard = PathGuard {
original: original_path.clone(),
};
let mut root = std::env::temp_dir();
root.push(format!(
"pacsea_fake_pacman_qq_{}_{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("System time is before UNIX epoch")
.as_nanos()
));
std::fs::create_dir_all(&root).expect("failed to create test root directory");
let mut bin = root.clone();
bin.push("bin");
std::fs::create_dir_all(&bin).expect("failed to create test bin directory");
let mut script = bin.clone();
script.push("pacman");
let body = r#"#!/usr/bin/env bash
set -e
if [[ "$1" == "-Qq" ]]; then
echo "alpha"
echo "beta"
exit 0
fi
exit 1
"#;
std::fs::write(&script, body).expect("failed to write test pacman script");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perm = std::fs::metadata(&script)
.expect("failed to read test pacman script metadata")
.permissions();
perm.set_mode(0o755);
std::fs::set_permissions(&script, perm)
.expect("failed to set test pacman script permissions");
}
let new_path = format!("{}:{original_path}", bin.to_string_lossy());
unsafe {
std::env::set_var("PATH", &new_path);
}
super::refresh_installed_cache().await;
let _ = std::fs::remove_dir_all(&root);
assert!(super::is_installed("alpha"));
assert!(super::is_installed("beta"));
assert!(!super::is_installed("gamma"));
}
}