Backend trait refactors

- Refactor the confusing/bodgy consts backend macro to use a single
  `BackendInfo` struct
- Combine `supports_as_dependency()` and the `switches_dependency` into a single `Option` type as that is a better representation as it is an optional backend feature.
- Add more types like `Packages`, `Sections` for uniformity.
- Added a crate-private prelude and switches all imports to use a
  prelude glob import (excluding functions because it's nice to only be
  importing types)
- Refactored Backend section name in logging by implementing Display for
  `AnyBackend` that just prints the `section`
This commit is contained in:
ripytide
2024-04-24 17:03:42 +01:00
parent 15b50d8cb0
commit 17e42ca435
26 changed files with 524 additions and 560 deletions
+70 -18
View File
@@ -1,23 +1,53 @@
pub mod actual;
pub mod backend_trait;
pub mod macros;
mod root;
pub mod todo_per_backend;
use crate::backend::backend_trait::Switches;
use crate::backend::backend_trait::Text;
use crate::Group;
use crate::Groups;
use crate::Package;
use anyhow::Result;
use backend_trait::Backend;
use std::collections::HashSet;
use std::fmt::Display;
use self::actual::{
fedora::Fedora, flatpak::Flatpak, python::Python, rust::Rust, rustup::Rustup, void::Void,
};
use crate::prelude::*;
use anyhow::{Context, Result};
#[derive(Debug)]
// A backend with its associated managed packages
pub struct ManagedBackend {
/// All managed packages for this backend, i.e. all packages
/// under the corresponding section in all group files.
pub packages: Packages,
pub any_backend: AnyBackend,
}
impl ManagedBackend {
/// Get unmanaged packages, sorted alphabetically.
///
/// # Errors
///
/// Returns an error if the backend fails to get the explicitly installed packages.
pub fn get_unmanaged_packages_sorted(&self) -> Result<Vec<Package>> {
let installed = self
.any_backend
.get_explicitly_installed_packages()
.context("could not get explicitly installed packages")?;
let mut diff: Vec<_> = installed.difference(&self.packages).cloned().collect();
diff.sort_unstable();
Ok(diff)
}
/// Get missing packages, sorted alphabetically.
///
/// # Errors
///
/// Returns an error if the backend fails to get the installed packages.
pub fn get_missing_packages_sorted(&self) -> Result<Vec<Package>> {
let installed = self
.any_backend
.get_all_installed_packages()
.context("could not get installed packages")?;
let mut diff: Vec<_> = self.packages.difference(&installed).cloned().collect();
diff.sort_unstable();
Ok(diff)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[enum_dispatch::enum_dispatch(Backend)]
pub enum AnyBackend {
#[cfg(feature = "arch")]
@@ -31,22 +61,44 @@ pub enum AnyBackend {
Rustup(Rustup),
Void(Void),
}
impl AnyBackend {
/// Returns an iterator of every variant of backend.
pub fn iter() -> impl Iterator<Item = Self> {
pub fn all(config: &Config) -> impl Iterator<Item = Self> {
vec![
#[cfg(feature = "arch")]
Self::Arch(actual::arch::Arch::new()),
Self::Arch(actual::arch::Arch::new(config)),
#[cfg(feature = "debian")]
Self::Debian(actual::debian::Debian::new()),
Self::Flatpak(Flatpak::new()),
Self::Flatpak(Flatpak::new(config)),
Self::Fedora(Fedora::new()),
Self::Python(Python::new()),
Self::Python(Python::new(config)),
Self::Rust(Rust::new()),
Self::Rustup(Rustup::new()),
Self::Void(Void::new()),
]
.into_iter()
}
pub fn from_section(section: &str, config: &Config) -> Result<Self> {
match section {
#[cfg(feature = "arch")]
"arch" => Ok(Self::Arch(actual::arch::Arch::new(config))),
#[cfg(feature = "debian")]
"debian" => Ok(Self::Debian(actual::debian::Debian::new())),
"flatpak" => Ok(Self::Flatpak(Flatpak::new(config))),
"fedora" => Ok(Self::Fedora(Fedora::new())),
"python" => Ok(Self::Python(Python::new(config))),
"rust" => Ok(Self::Rust(Rust::new())),
"rustup" => Ok(Self::Rustup(Rustup::new())),
"void" => Ok(Self::Void(Void::new())),
_ => Err(anyhow::anyhow!(
"no matching backend for the section: {section}"
)),
}
}
}
impl Display for AnyBackend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.backend_info().section)
}
}