use sysknife_core::distro::{DistroFamily, DistroId};
use sysknife_core::action_family::{DEBIAN_ONLY_ACTIONS, FEDORA_ONLY_ACTIONS};
pub fn check_action_distro(action_name: &str, distro: Option<&DistroId>) -> Result<(), String> {
let distro = match distro {
Some(d) => d,
None => return Ok(()), };
let family = distro.family();
if DEBIAN_ONLY_ACTIONS.contains(&action_name) && family != DistroFamily::Debian {
return Err(format!(
"{action_name} is only valid on Debian-family distros (apt/snap/ufw); \
current distro is {distro} ({family_name})",
family_name = family_label(&family),
));
}
if FEDORA_ONLY_ACTIONS.contains(&action_name) && family != DistroFamily::Fedora {
return Err(format!(
"{action_name} is only valid on Fedora-family distros (rpm-ostree/dnf); \
current distro is {distro} ({family_name})",
family_name = family_label(&family),
));
}
if (DEBIAN_ONLY_ACTIONS.contains(&action_name) || FEDORA_ONLY_ACTIONS.contains(&action_name))
&& !distro.is_supported()
{
return Err(format!(
"{action_name} is disabled on unsupported distro {distro}; \
see docs/distro-support.md"
));
}
Ok(())
}
fn family_label(f: &DistroFamily) -> &'static str {
match f {
DistroFamily::Fedora => "Fedora family",
DistroFamily::Debian => "Debian family",
DistroFamily::Other => "unknown family",
}
}
#[cfg(test)]
mod tests {
use super::*;
use sysknife_core::distro::DistroId;
#[test]
fn apt_install_on_fedora_returns_error() {
let distro = DistroId::Fedora { version: 41 };
let result = check_action_distro("AptInstall", Some(&distro));
assert!(result.is_err());
let msg = result.unwrap_err();
assert!(
msg.contains("Debian-family"),
"error must mention Debian-family; got: {msg}"
);
assert!(
msg.contains("Fedora 41"),
"error must mention current distro; got: {msg}"
);
}
#[test]
fn snap_install_on_fedora_silverblue_returns_error() {
let distro = DistroId::FedoraSilverblue { version: 41 };
let result = check_action_distro("SnapInstall", Some(&distro));
assert!(result.is_err());
let msg = result.unwrap_err();
assert!(msg.contains("Debian-family"), "got: {msg}");
assert!(msg.contains("FedoraSilverblue 41"), "got: {msg}");
}
#[test]
fn ufw_allow_on_fedora_returns_error() {
let distro = DistroId::Fedora { version: 41 };
let result = check_action_distro("UfwAllow", Some(&distro));
assert!(result.is_err());
}
#[test]
fn netplan_apply_on_fedora_returns_error() {
let distro = DistroId::Fedora { version: 41 };
let result = check_action_distro("NetplanApply", Some(&distro));
assert!(result.is_err());
}
#[test]
fn distrobox_create_on_fedora_returns_error() {
let distro = DistroId::Fedora { version: 41 };
let result = check_action_distro("DistroboxCreate", Some(&distro));
assert!(result.is_err());
}
#[test]
fn apt_install_on_ubuntu_is_ok() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
assert!(check_action_distro("AptInstall", Some(&distro)).is_ok());
}
#[test]
fn apt_install_on_ubuntu_core_is_rejected() {
let distro = DistroId::UbuntuCore {
major: 24,
minor: 4,
};
assert!(check_action_distro("AptInstall", Some(&distro)).is_err());
}
#[test]
fn apt_install_on_unsupported_ubuntu_release_is_rejected() {
let distro = DistroId::Ubuntu {
major: 18,
minor: 4,
};
assert!(check_action_distro("AptInstall", Some(&distro)).is_err());
}
#[test]
fn apt_install_is_allowed_on_every_supported_ubuntu_release() {
for (major, minor) in [(20, 4), (22, 4), (24, 4), (25, 10), (26, 4), (26, 10)] {
let distro = DistroId::Ubuntu { major, minor };
assert!(
check_action_distro("AptInstall", Some(&distro)).is_ok(),
"AptInstall must route on Ubuntu {major}.{minor:02}"
);
}
}
#[test]
fn snap_install_on_ubuntu_is_ok() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
assert!(check_action_distro("SnapInstall", Some(&distro)).is_ok());
}
#[test]
fn rebase_system_on_ubuntu_returns_error() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
let result = check_action_distro("RebaseSystem", Some(&distro));
assert!(result.is_err());
let msg = result.unwrap_err();
assert!(msg.contains("Fedora-family"), "got: {msg}");
assert!(msg.contains("Ubuntu 24.04"), "got: {msg}");
}
#[test]
fn add_layered_package_on_ubuntu_returns_error() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
let result = check_action_distro("AddLayeredPackage", Some(&distro));
assert!(result.is_err());
}
#[test]
fn no_distro_allows_all_actions() {
assert!(check_action_distro("AptInstall", None).is_ok());
assert!(check_action_distro("RebaseSystem", None).is_ok());
assert!(check_action_distro("GetSystemState", None).is_ok());
}
#[test]
fn get_system_state_allowed_on_fedora() {
let distro = DistroId::Fedora { version: 41 };
assert!(check_action_distro("GetSystemState", Some(&distro)).is_ok());
}
#[test]
fn get_system_state_allowed_on_ubuntu() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
assert!(check_action_distro("GetSystemState", Some(&distro)).is_ok());
}
#[test]
fn install_flatpak_allowed_on_fedora() {
let distro = DistroId::Fedora { version: 41 };
assert!(check_action_distro("InstallFlatpak", Some(&distro)).is_ok());
}
#[test]
fn install_flatpak_allowed_on_ubuntu() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
assert!(check_action_distro("InstallFlatpak", Some(&distro)).is_ok());
}
#[test]
fn all_debian_only_actions_rejected_on_fedora() {
let distro = DistroId::Fedora { version: 41 };
for action in super::DEBIAN_ONLY_ACTIONS {
let result = check_action_distro(action, Some(&distro));
assert!(
result.is_err(),
"{action} should be rejected on Fedora but was allowed"
);
}
}
#[test]
fn all_fedora_only_actions_rejected_on_ubuntu() {
let distro = DistroId::Ubuntu {
major: 24,
minor: 4,
};
for action in super::FEDORA_ONLY_ACTIONS {
let result = check_action_distro(action, Some(&distro));
assert!(
result.is_err(),
"{action} should be rejected on Ubuntu but was allowed"
);
}
}
#[test]
fn distro_id_display_fedora() {
assert_eq!(format!("{}", DistroId::Fedora { version: 41 }), "Fedora 41");
}
#[test]
fn distro_id_display_fedora_silverblue() {
assert_eq!(
format!("{}", DistroId::FedoraSilverblue { version: 41 }),
"FedoraSilverblue 41"
);
}
#[test]
fn distro_id_display_ubuntu() {
assert_eq!(
format!(
"{}",
DistroId::Ubuntu {
major: 24,
minor: 4
}
),
"Ubuntu 24.04"
);
}
#[test]
fn distro_id_display_debian() {
assert_eq!(
format!("{}", DistroId::Debian { version: Some(12) }),
"Debian 12"
);
}
}