use crate::{
config::pkg::InstallHint,
error::Error,
os::{Distro, Os},
utils::which::SearchPath,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DetectedPackageManager {
Brew,
Dnf5,
Apt,
Pacman,
Cargo,
}
impl DetectedPackageManager {
pub fn name(self) -> &'static str {
match self {
Self::Brew => "brew",
Self::Dnf5 => "dnf",
Self::Apt => "apt",
Self::Pacman => "pacman",
Self::Cargo => "cargo",
}
}
pub fn packages_for(self, hint: &InstallHint) -> &[String] {
match self {
Self::Brew => &hint.brew.packages,
Self::Dnf5 => &hint.dnf5.packages,
Self::Apt => &hint.apt.packages,
Self::Pacman => &hint.pacman.packages,
Self::Cargo => &hint.cargo.packages,
}
}
pub fn install_command(self, packages: &[String]) -> String {
match self {
Self::Brew => format!("brew install {}", packages.join(" ")),
Self::Dnf5 => format!("sudo dnf install {}", packages.join(" ")),
Self::Apt => format!("sudo apt install {}", packages.join(" ")),
Self::Pacman => format!("sudo pacman -S {}", packages.join(" ")),
Self::Cargo => format!("cargo install {}", packages.join(" ")),
}
}
}
pub fn detect(path: &SearchPath, os: &Os) -> Result<Option<DetectedPackageManager>, Error> {
if crate::utils::which::exists("brew", path)? {
return Ok(Some(DetectedPackageManager::Brew));
}
Ok(detect_native(os))
}
pub fn detect_native(os: &Os) -> Option<DetectedPackageManager> {
match os {
Os::Macos => None,
Os::Linux(linux) => match linux.distro {
Distro::Fedora(_) => Some(DetectedPackageManager::Dnf5),
Distro::Ubuntu(_) => Some(DetectedPackageManager::Apt),
Distro::Arch => Some(DetectedPackageManager::Pacman),
},
}
}
pub fn detect_supplementary(path: &SearchPath) -> Result<Vec<DetectedPackageManager>, Error> {
let mut out = Vec::new();
if crate::utils::which::exists("cargo", path)? {
out.push(DetectedPackageManager::Cargo);
}
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::pkg::{AptHint, BrewHint, CargoHint, Dnf5Hint, PacmanHint};
use crate::os::{Distro, Fedora, FedoraVersion, Linux};
fn fedora42() -> Os {
Os::Linux(Linux {
distro: Distro::Fedora(Fedora {
version: FedoraVersion::F42,
}),
})
}
#[test]
fn detect_native_returns_dnf5_for_fedora_42() {
assert_eq!(
detect_native(&fedora42()),
Some(DetectedPackageManager::Dnf5)
);
}
#[test]
fn detect_native_returns_none_for_macos() {
assert_eq!(detect_native(&Os::Macos), None);
}
#[test]
fn dnf5_user_facing_name_drops_version_suffix() {
assert_eq!(DetectedPackageManager::Dnf5.name(), "dnf");
}
#[test]
fn cargo_name_and_install_command() {
assert_eq!(DetectedPackageManager::Cargo.name(), "cargo");
let pkgs = vec!["skim".into(), "starship".into()];
assert_eq!(
DetectedPackageManager::Cargo.install_command(&pkgs),
"cargo install skim starship",
);
}
#[test]
fn packages_for_each_manager_reads_its_own_field() {
let hint = InstallHint {
brew: BrewHint {
packages: vec!["sk".into()],
},
dnf5: Dnf5Hint {
packages: vec!["starship".into()],
},
apt: AptHint {
packages: vec!["starship".into()],
},
pacman: PacmanHint {
packages: vec!["skim".into()],
},
cargo: CargoHint {
packages: vec!["skim".into()],
},
};
assert_eq!(DetectedPackageManager::Brew.packages_for(&hint), ["sk"]);
assert_eq!(
DetectedPackageManager::Dnf5.packages_for(&hint),
["starship"],
);
assert_eq!(
DetectedPackageManager::Apt.packages_for(&hint),
["starship"],
);
assert_eq!(DetectedPackageManager::Pacman.packages_for(&hint), ["skim"],);
assert_eq!(DetectedPackageManager::Cargo.packages_for(&hint), ["skim"]);
}
#[test]
fn packages_for_empty_returns_empty_slice() {
let hint = InstallHint::default();
assert!(DetectedPackageManager::Brew.packages_for(&hint).is_empty());
assert!(DetectedPackageManager::Dnf5.packages_for(&hint).is_empty());
assert!(DetectedPackageManager::Apt.packages_for(&hint).is_empty());
assert!(
DetectedPackageManager::Pacman
.packages_for(&hint)
.is_empty()
);
assert!(DetectedPackageManager::Cargo.packages_for(&hint).is_empty());
}
#[test]
fn install_command_joins_packages_with_spaces() {
let pkgs = vec!["sk".into(), "starship".into()];
assert_eq!(
DetectedPackageManager::Brew.install_command(&pkgs),
"brew install sk starship"
);
assert_eq!(
DetectedPackageManager::Dnf5.install_command(&pkgs),
"sudo dnf install sk starship"
);
assert_eq!(
DetectedPackageManager::Pacman.install_command(&pkgs),
"sudo pacman -S sk starship"
);
assert_eq!(
DetectedPackageManager::Cargo.install_command(&pkgs),
"cargo install sk starship"
);
}
}