use std::{fs::File, io::Read}; use dnf::Dnf; use pacman::Pacman; use portage::Portage; use serde::{Deserialize, Serialize}; use crate::error::{Error, Result}; mod dnf; mod pacman; mod portage; #[derive(Debug, Serialize, Deserialize)] pub struct PackageList { packages: Vec, manager: Manager, } impl PackageList { pub fn install(&self) -> Result<()> { self.manager .to_package_manager() .install(self.packages.clone()) } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Package { pub id: String, pub version: String, pub explicit: bool, } #[derive(Debug, Clone, clap::ValueEnum, Serialize, Deserialize)] pub enum Manager { Dnf, Pacman, Portage, } impl Manager { pub fn from_sys() -> Result { #[cfg(not(target_os = "linux"))] return Err(Error::Unsupported); #[cfg(target_os = "linux")] { let mut os_release = File::open("/etc/os-release")?; let mut content = String::new(); os_release.read_to_string(&mut content)?; let lines: Vec<&str> = content.split('\n').collect(); for line in lines { let Some((key, value)) = line.split_once('=') else { continue; }; if key == "ID" { return Self::from_str(value); } } Err(Error::Unsupported) } } fn from_str(value: &str) -> Result { Ok(match value { "fedora" => Self::Dnf, "arch" => Self::Pacman, "gentoo" => Self::Portage, _ => return Err(Error::Unsupported), }) } pub fn to_package_manager(&self) -> Box { match self { Self::Dnf => Box::new(Dnf), Self::Pacman => Box::new(Pacman), Self::Portage => Box::new(Portage), } } } pub trait PackageManager { fn get_installed(&self) -> Result; fn install(&self, pkgs: Vec) -> Result<()>; }