From 80fb9d7252656036303b91825212da03afcfbff0 Mon Sep 17 00:00:00 2001 From: steven-omaha <35634100+steven-omaha@users.noreply.github.com> Date: Fri, 6 Jan 2023 13:31:50 +0100 Subject: [PATCH] get generic backend to work (to some extent) --- Cargo.lock | 33 ++++++++++ Cargo.toml | 2 + src/backend/mod.rs | 80 ++++++++++++++++------- src/backend/pacman.rs | 38 ++++++++--- src/backend/rust.rs | 40 +++++++++--- src/core.rs | 145 +++++++++++++++++++----------------------- 6 files changed, 218 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 972358a..3c02d56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -222,6 +222,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -349,6 +355,8 @@ dependencies = [ "anyhow", "clap", "criterion", + "strum", + "strum_macros", ] [[package]] @@ -440,6 +448,12 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + [[package]] name = "ryu" version = "1.0.12" @@ -498,6 +512,25 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "1.0.107" diff --git a/Cargo.toml b/Cargo.toml index 92e9590..972af51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ alpm = "*" anyhow = "*" # clap 4 until (at least) 4.0.32 have scrapped actual color support. we stay on 3.x until that's fixed. clap = "3.*" +strum = "0.24.1" +strum_macros = "0.24.3" [profile.release] debug = true diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 5c1533e..3b4404b 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -8,37 +8,71 @@ use std::process::Command; use crate::Package; pub use pacman::Pacman; -type Switches = &'static [&'static str]; -type Text = &'static str; +pub use rust::Rust; +pub type Switches = &'static [&'static str]; +pub type Text = &'static str; +#[derive(Debug)] pub enum Backends { Pacman, Rust, } +impl Backends { + pub fn iter() -> BackendIter { + BackendIter(Some(Self::Pacman)) + } +} + +pub struct BackendIter(Option); + +impl Iterator for BackendIter { + type Item = Box; + + fn next(&mut self) -> Option { + match self.0 { + Some(Backends::Pacman) => { + self.0 = Some(Backends::Rust); + Some(Box::new(Pacman::new())) + } + Some(Backends::Rust) => { + self.0 = None; + Some(Box::new(Rust::new())) + } + None => None, + } + } +} + +impl Backends { + pub fn get(&self) -> Box { + match self { + Self::Pacman => Box::new(Pacman { + packages: HashSet::new(), + }), + Self::Rust => Box::new(Rust { + packages: HashSet::new(), + }), + } + } +} + pub trait Backend { - /// The name that introduces the section in the group file - const SECTION: Text; - - /// The binary that should be called to run the associated package manager. - const BINARY: Text; - - /// The switches that signals the `BINARY` that the packages should be installed. - const SWITCHES_INSTALL: Switches; - - /// The switches that signals the `BINARY` that the packages should be removed. - const SWITCHES_REMOVE: Switches; + fn get_binary(&self) -> Text; + fn get_section(&self) -> Text; + fn get_switches_install(&self) -> Switches; + fn get_switches_remove(&self) -> Switches; /// Get all packages that are installed in the system. - fn get_all_installed_packages() -> HashSet; + fn get_all_installed_packages(&self) -> HashSet; /// Get all packages that were installed in the system explicitly. - fn get_explicitly_installed_packages() -> HashSet; + fn get_explicitly_installed_packages(&self) -> HashSet; /// Install the specified packages. - fn install_packages(packages: Vec) { - let mut cmd = Command::new(Self::BINARY); - cmd.args(Self::SWITCHES_INSTALL); + fn install_packages(&self, packages: Vec) { + let mut cmd = Command::new(self.get_binary()); + cmd.args(self.get_switches_install()); for p in packages { cmd.arg(format!("{p}")); } @@ -46,9 +80,9 @@ pub trait Backend { } /// Remove the specified packages. - fn remove_packages(packages: Vec) { - let mut cmd = Command::new(Self::BINARY); - cmd.args(Self::SWITCHES_REMOVE); + fn remove_packages(&self, packages: Vec) { + let mut cmd = Command::new(self.get_binary()); + cmd.args(self.get_switches_remove()); for p in packages { cmd.arg(format!("{p}")); } @@ -56,10 +90,10 @@ pub trait Backend { } /// extract packages from its own section as read from group files - fn extract_packages_from_group_file_content(content: &str) -> HashSet { + fn extract_packages_from_group_file_content(&self, content: &str) -> HashSet { content .lines() - .skip_while(|line| !line.starts_with(&format!("[{}]", Self::SECTION))) + .skip_while(|line| !line.starts_with(&format!("[{}]", self.get_section()))) .skip(1) .filter(|line| !line.starts_with('[')) .fuse() diff --git a/src/backend/pacman.rs b/src/backend/pacman.rs index 611eccf..036ad65 100644 --- a/src/backend/pacman.rs +++ b/src/backend/pacman.rs @@ -6,25 +6,43 @@ use alpm::PackageReason::Explicit; use super::{Backend, Switches, Text}; use crate::Package; -pub struct Pacman(HashSet); +pub struct Pacman { + pub packages: HashSet, +} + +const BINARY: Text = "paru"; +const SECTION: Text = "pacman"; +const SWITCHES_INSTALL: Switches = &["-S"]; +const SWITCHES_REMOVE: Switches = &["-Rsn"]; impl Backend for Pacman { - const BINARY: Text = "paru"; - const SECTION: Text = "pacman"; - const SWITCHES_INSTALL: Switches = &["-S"]; - const SWITCHES_REMOVE: Switches = &["-Rsn"]; + fn get_binary(&self) -> Text { + BINARY + } - fn get_all_installed_packages() -> HashSet { + fn get_section(&self) -> Text { + SECTION + } + + fn get_switches_install(&self) -> Switches { + SWITCHES_INSTALL + } + + fn get_switches_remove(&self) -> Switches { + SWITCHES_REMOVE + } + + fn get_all_installed_packages(&self) -> HashSet { convert_to_pacdef_packages(get_all_installed_packages_from_alpm()) } - fn get_explicitly_installed_packages() -> HashSet { + fn get_explicitly_installed_packages(&self) -> HashSet { convert_to_pacdef_packages(get_explicitly_installed_packages_from_alpm()) } fn add_packages(&mut self, packages: HashSet) { for p in packages { - self.0.insert(p); + self.packages.insert(p); } } } @@ -54,7 +72,9 @@ fn convert_to_pacdef_packages(packages: HashSet) -> HashSet { impl Pacman { pub fn new() -> Self { - Self(HashSet::new()) + Self { + packages: HashSet::new(), + } } } diff --git a/src/backend/rust.rs b/src/backend/rust.rs index 97e1d9e..992a038 100644 --- a/src/backend/rust.rs +++ b/src/backend/rust.rs @@ -3,27 +3,45 @@ use std::{collections::HashSet, process::Command}; use super::{Backend, Switches, Text}; use crate::Package; -pub struct Rust(HashSet); +pub struct Rust { + pub packages: HashSet, +} + +const BINARY: Text = "cargo"; +const SECTION: Text = "rust"; +const SWITCHES_INSTALL: Switches = &["install"]; +const SWITCHES_REMOVE: Switches = &["uninstall"]; impl Backend for Rust { - const BINARY: Text = "cargo"; - const SECTION: Text = "rust"; - const SWITCHES_INSTALL: Switches = &["install"]; - const SWITCHES_REMOVE: Switches = &["uninstall"]; + fn get_binary(&self) -> Text { + BINARY + } - fn get_all_installed_packages() -> HashSet { + fn get_section(&self) -> Text { + SECTION + } + + fn get_switches_install(&self) -> Switches { + SWITCHES_INSTALL + } + + fn get_switches_remove(&self) -> Switches { + SWITCHES_REMOVE + } + + fn get_all_installed_packages(&self) -> HashSet { extract_packages_names(&run_cargo_install_list()) .map(Package::from) .collect() } - fn get_explicitly_installed_packages() -> HashSet { - Self::get_all_installed_packages() + fn get_explicitly_installed_packages(&self) -> HashSet { + self.get_all_installed_packages() } fn add_packages(&mut self, packages: HashSet) { for p in packages { - self.0.insert(p); + self.packages.insert(p); } } } @@ -46,7 +64,9 @@ fn extract_packages_names(output: &str) -> impl Iterator + '_ { impl Rust { pub fn new() -> Self { - Self(HashSet::new()) + Self { + packages: HashSet::new(), + } } } diff --git a/src/core.rs b/src/core.rs index 74ba3fd..bf1ed61 100644 --- a/src/core.rs +++ b/src/core.rs @@ -5,7 +5,7 @@ use anyhow::{bail, Context, Result}; use clap::ArgMatches; use crate::action; -use crate::backend::{Backend, Pacman}; +use crate::backend::{Backend, Backends, Pacman}; use crate::cmd::run_edit_command; use crate::ui::get_user_confirmation; use crate::Group; @@ -13,62 +13,51 @@ use crate::Package; pub struct Pacdef { pub(crate) args: ArgMatches, - pub(crate) groups: Option>, - // action: Box, + pub(crate) groups: HashSet, } impl Pacdef { pub fn new(args: ArgMatches, groups: HashSet) -> Self { - Self { - args, - groups: Some(groups), - // action: Box::new(Self::install_packages), - } + Self { args, groups } } - pub(crate) fn take_packages_as_set(&mut self) -> HashSet { - self.groups - .take() - .unwrap() - .into_iter() - .flat_map(|g| g.packages) - .collect() - } + // pub(crate) fn get_packages_to_install(&mut self) -> Vec { + // let managed = self.take_packages_as_set(); + // let local_packages = Pacman::get_all_installed_packages(); + // let mut diff: Vec<_> = managed + // .into_iter() + // .filter(|p| !local_packages.contains(p)) + // .collect(); + // diff.sort_unstable(); + // diff + // } - pub(crate) fn get_packages_to_install(&mut self) -> Vec { - let managed = self.take_packages_as_set(); - let local_packages = Pacman::get_all_installed_packages(); - let mut diff: Vec<_> = managed - .into_iter() - .filter(|p| !local_packages.contains(p)) - .collect(); - diff.sort_unstable(); - diff - } - - pub(crate) fn install_packages(mut self) { - let diff = self.get_packages_to_install(); - if diff.is_empty() { - println!("nothing to do"); - exit(0); + pub(crate) fn install_packages(&self) { + for b in Backends::iter() { + println!("{}", b.get_binary()); } - println!("Would install the following packages:"); - for p in &diff { - println!(" {p}"); - } - crate::ui::get_user_confirmation(); + // let diff = self.get_packages_to_install(); + // if diff.is_empty() { + // println!("nothing to do"); + // exit(0); + // } + // println!("Would install the following packages:"); + // for p in &diff { + // println!(" {p}"); + // } + // crate::ui::get_user_confirmation(); - Pacman::install_packages(diff); + // Pacman::install_packages(diff); } #[allow(clippy::unit_arg)] pub fn run_action_from_arg(self) -> Result<()> { match self.args.subcommand() { - Some((action::CLEAN, _)) => Ok(self.clean_packages()), + // Some((action::CLEAN, _)) => Ok(self.clean_packages()), Some((action::EDIT, groups)) => self.edit_group_files(groups).context("editing"), - Some((action::GROUPS, _)) => Ok(self.show_groups()), + // Some((action::GROUPS, _)) => Ok(self.show_groups()), Some((action::SYNC, _)) => Ok(self.install_packages()), - Some((action::UNMANAGED, _)) => Ok(self.show_unmanaged_packages()), + // Some((action::UNMANAGED, _)) => Ok(self.show_unmanaged_packages()), Some((action::VERSION, _)) => Ok(self.show_version()), _ => todo!(), } @@ -98,45 +87,45 @@ impl Pacdef { println!("pacdef, version: {}", env!("CARGO_PKG_VERSION")) } - pub(crate) fn show_unmanaged_packages(mut self) { - for p in &self.get_unmanaged_packages() { - println!("{p}"); - } - } + // pub(crate) fn show_unmanaged_packages(mut self) { + // for p in &self.get_unmanaged_packages() { + // println!("{p}"); + // } + // } - /// Returns a `Vec` of alphabetically sorted unmanaged packages. - pub(crate) fn get_unmanaged_packages(&mut self) -> Vec { - let managed = self.take_packages_as_set(); - let explicitly_installed = Pacman::get_explicitly_installed_packages(); - let mut result: Vec<_> = explicitly_installed - .into_iter() - .filter(|p| !managed.contains(p)) - .collect(); - result.sort_unstable(); - result - } + // /// Returns a `Vec` of alphabetically sorted unmanaged packages. + // pub(crate) fn get_unmanaged_packages(&mut self) -> Vec { + // let managed = self.take_packages_as_set(); + // let explicitly_installed = Pacman::get_explicitly_installed_packages(); + // let mut result: Vec<_> = explicitly_installed + // .into_iter() + // .filter(|p| !managed.contains(p)) + // .collect(); + // result.sort_unstable(); + // result + // } - pub(crate) fn show_groups(mut self) { - let groups = self.groups.take().unwrap(); - let mut vec: Vec<_> = groups.iter().collect(); - vec.sort_unstable(); - for g in vec { - println!("{}", g.name); - } - } + // pub(crate) fn show_groups(mut self) { + // let groups = self.groups.take().unwrap(); + // let mut vec: Vec<_> = groups.iter().collect(); + // vec.sort_unstable(); + // for g in vec { + // println!("{}", g.name); + // } + // } - fn clean_packages(mut self) { - let unmanaged = self.get_unmanaged_packages(); - if unmanaged.is_empty() { - println!("nothing to do"); - return; - } + // fn clean_packages(mut self) { + // let unmanaged = self.get_unmanaged_packages(); + // if unmanaged.is_empty() { + // println!("nothing to do"); + // return; + // } - println!("Would remove the following packages and their dependencies:"); - for p in &unmanaged { - println!(" {p}"); - } - get_user_confirmation(); - Pacman::remove_packages(unmanaged); - } + // println!("Would remove the following packages and their dependencies:"); + // for p in &unmanaged { + // println!(" {p}"); + // } + // get_user_confirmation(); + // Pacman::remove_packages(unmanaged); + // } }