From a4639a1c3a5d2b1de908fdd77597d6415722e081 Mon Sep 17 00:00:00 2001 From: steven-omaha <35634100+steven-omaha@users.noreply.github.com> Date: Tue, 23 May 2023 17:28:51 +0200 Subject: [PATCH] refact: overhaul arg parsing --- Cargo.lock | 24 ++-- crates/pacdef_core/Cargo.toml | 6 +- crates/pacdef_core/src/action.rs | 19 --- .../pacdef_core/src/{args.rs => args/cli.rs} | 57 ++------ crates/pacdef_core/src/args/datastructure.rs | 40 ++++++ crates/pacdef_core/src/args/mod.rs | 12 ++ crates/pacdef_core/src/args/parsing.rs | 70 ++++++++++ crates/pacdef_core/src/core.rs | 130 +++++++----------- crates/pacdef_core/src/lib.rs | 1 - crates/pacdef_core/src/path.rs | 14 ++ crates/pacdef_core/src/search.rs | 22 +-- crates/pacdef_macros/src/action.rs | 77 ----------- crates/pacdef_macros/src/lib.rs | 8 -- 13 files changed, 222 insertions(+), 258 deletions(-) delete mode 100644 crates/pacdef_core/src/action.rs rename crates/pacdef_core/src/{args.rs => args/cli.rs} (73%) create mode 100644 crates/pacdef_core/src/args/datastructure.rs create mode 100644 crates/pacdef_core/src/args/mod.rs create mode 100644 crates/pacdef_core/src/args/parsing.rs delete mode 100644 crates/pacdef_macros/src/action.rs diff --git a/Cargo.lock b/Cargo.lock index a247b5f..3384e07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,18 +107,18 @@ checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "clap" -version = "4.2.7" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.2.7" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" dependencies = [ "anstream", "anstyle", @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "codespan-reporting" @@ -321,9 +321,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "numtoa" @@ -437,18 +437,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" dependencies = [ "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rust-apt" diff --git a/crates/pacdef_core/Cargo.toml b/crates/pacdef_core/Cargo.toml index f2ab788..1632a18 100644 --- a/crates/pacdef_core/Cargo.toml +++ b/crates/pacdef_core/Cargo.toml @@ -11,10 +11,10 @@ categories = ["command-line-utilities"] [dependencies] anyhow = { workspace = true } -clap = "4.2" +clap = "4.3" const_format = { version = "0.2", default-features = false } -path-absolutize = "3.0" -regex = { version = "1.7", default-features = false, features = ["std"] } +path-absolutize = "3.1" +regex = { version = "1.8", default-features = false, features = ["std"] } termios = "0.3" walkdir = "2.3" diff --git a/crates/pacdef_core/src/action.rs b/crates/pacdef_core/src/action.rs deleted file mode 100644 index fd21253..0000000 --- a/crates/pacdef_core/src/action.rs +++ /dev/null @@ -1,19 +0,0 @@ -use pacdef_macros::Action; - -/// All main actions the program can perform. Variants of the enum relate to -/// the different subcommands. -#[derive(Debug, Action)] -pub enum Actions { - Clean, - Edit, - Import, - List, - New, - Remove, - Review, - Search, - Show, - Sync, - Unmanaged, - Version, -} diff --git a/crates/pacdef_core/src/args.rs b/crates/pacdef_core/src/args/cli.rs similarity index 73% rename from crates/pacdef_core/src/args.rs rename to crates/pacdef_core/src/args/cli.rs index e34673e..857580a 100644 --- a/crates/pacdef_core/src/args.rs +++ b/crates/pacdef_core/src/args/cli.rs @@ -1,18 +1,11 @@ -use std::path::PathBuf; - -use anyhow::{Context, Result}; -use clap::{Arg, ArgAction, ArgMatches, Command}; -use path_absolutize::Absolutize; - -use crate::action::*; use crate::core::get_version_string; +use clap::{Arg, ArgAction, Command}; -/// Build the `pacdef` argument parser, with subcommands for `version`, -/// `group` and `package`. -fn build_cli() -> Command { +#[must_use] +pub(super) fn build_cli() -> Command { let package_cmd = get_package_cmd(); let group_cmd = get_group_cmd(); - let version_cmd = Command::new(VERSION).about("show version info"); + let version_cmd = Command::new("version").about("show version info"); Command::new("pacdef") .about("multi-backend declarative package manager for Linux") @@ -27,7 +20,7 @@ fn build_cli() -> Command { /// Build the `pacdef group` subcommand. fn get_group_cmd() -> Command { - let edit = Command::new(EDIT) + let edit = Command::new("edit") .about("edit one or more existing group") .arg_required_else_help(true) .arg( @@ -38,7 +31,7 @@ fn get_group_cmd() -> Command { ) .visible_alias("e"); - let import = Command::new(IMPORT) + let import = Command::new("import") .about("import one or more group files") .arg_required_else_help(true) .arg( @@ -49,11 +42,11 @@ fn get_group_cmd() -> Command { ) .visible_alias("i"); - let list = Command::new(LIST) + let list = Command::new("list") .about("list names of imported groups") .visible_alias("l"); - let new = Command::new(NEW) + let new = Command::new("new") .about("create new group files") .arg_required_else_help(true) .arg( @@ -66,7 +59,7 @@ fn get_group_cmd() -> Command { .arg(Arg::new("groups").num_args(1..).required(true)) .visible_alias("n"); - let remove = Command::new(REMOVE) + let remove = Command::new("remove") .about("remove one or more previously imported groups") .arg_required_else_help(true) .arg( @@ -77,7 +70,7 @@ fn get_group_cmd() -> Command { ) .visible_alias("r"); - let show = Command::new(SHOW) + let show = Command::new("show") .about("show packages under an imported group") .arg_required_else_help(true) .arg( @@ -98,25 +91,25 @@ fn get_group_cmd() -> Command { /// Build the `pacdef package` subcommand. fn get_package_cmd() -> Command { - let sync = Command::new(SYNC) + let sync = Command::new("sync") .about("install packages from all imported groups") .visible_alias("sy") .arg(build_noconfirm_arg()); - let clean = Command::new(CLEAN) + let clean = Command::new("clean") .about("remove unmanaged packages") .visible_alias("c") .arg(build_noconfirm_arg()); - let unmanaged = Command::new(UNMANAGED) + let unmanaged = Command::new("unmanaged") .about("show explicitly installed packages not managed by pacdef") .visible_alias("u"); - let review = Command::new(REVIEW) + let review = Command::new("review") .about("review unmanaged packages") .visible_alias("r"); - let search = Command::new(SEARCH) + let search = Command::new("search") .visible_alias("se") .about("search for packages which match a provided regex") .arg_required_else_help(true) @@ -140,23 +133,3 @@ fn build_noconfirm_arg() -> Arg { .help("do not ask for any confirmation") .action(ArgAction::SetTrue) } - -/// Get and parse the CLI arguments. Returns an instance of [`clap::ArgMatches`]. -#[must_use] -pub fn get() -> clap::ArgMatches { - build_cli().get_matches() -} - -/// For each file argument, return the absolute path to the file. -pub fn get_absolutized_file_paths(arg_match: &ArgMatches) -> Result> { - Ok(arg_match - .get_many::("files") - .context("getting files from args")? - .map(PathBuf::from) - .map(|path| { - path.absolutize() - .expect("absolute path should exist") - .into_owned() - }) - .collect()) -} diff --git a/crates/pacdef_core/src/args/datastructure.rs b/crates/pacdef_core/src/args/datastructure.rs new file mode 100644 index 0000000..5250f27 --- /dev/null +++ b/crates/pacdef_core/src/args/datastructure.rs @@ -0,0 +1,40 @@ +#[derive(Debug)] +pub enum Arguments { + Group(GroupAction), + Package(PackageAction), + Version, +} + +#[derive(Debug)] +pub enum GroupAction { + Edit(Groups), + Import(Groups), + List, + New(Groups, Edit), + Remove(Groups), + Show(Groups), +} + +#[derive(Debug)] +pub struct Files(pub Vec); + +#[derive(Debug)] +pub struct Groups(pub Vec); + +#[derive(Debug)] +pub enum PackageAction { + Clean(Noconfirm), + Review, + Search(Regex), + Sync(Noconfirm), + Unmanaged, +} + +#[derive(Debug)] +pub struct Regex(pub String); + +#[derive(Debug)] +pub struct Edit(pub bool); + +#[derive(Debug)] +pub struct Noconfirm(pub bool); diff --git a/crates/pacdef_core/src/args/mod.rs b/crates/pacdef_core/src/args/mod.rs new file mode 100644 index 0000000..638b586 --- /dev/null +++ b/crates/pacdef_core/src/args/mod.rs @@ -0,0 +1,12 @@ +mod cli; +mod datastructure; +mod parsing; + +pub use datastructure::*; + +/// Get and parse the CLI arguments. +#[must_use] +pub fn get() -> Arguments { + let args = cli::build_cli().get_matches(); + parsing::parse(args) +} diff --git a/crates/pacdef_core/src/args/parsing.rs b/crates/pacdef_core/src/args/parsing.rs new file mode 100644 index 0000000..5a54f14 --- /dev/null +++ b/crates/pacdef_core/src/args/parsing.rs @@ -0,0 +1,70 @@ +use super::datastructure::*; + +const ARGS_CONSISTENT: &str = "argument declaration and parsing must be consistent"; + +pub(super) fn parse(args: clap::ArgMatches) -> Arguments { + match args.subcommand() { + Some(("group", args)) => Arguments::Group(parse_group_args(args)), + Some(("package", args)) => Arguments::Package(parse_package_args(args)), + Some(("version", _)) => Arguments::Version, + Some(value) => panic!("main subcommand was not matched: {value:?}"), + None => unreachable!("prevented by clap"), + } +} + +fn parse_group_args(args: &clap::ArgMatches) -> GroupAction { + use GroupAction::*; + + match args.subcommand() { + Some(("edit", args)) => Edit(get_groups(args)), + Some(("import", args)) => Import(get_groups(args)), + Some(("list", _)) => List, + Some(("new", args)) => New(get_groups(args), get_edit(args)), + Some(("remove", args)) => Remove(get_groups(args)), + Some(("show", args)) => Show(get_groups(args)), + Some(value) => panic!("group subcommand was not matched: {value:?}"), + None => unreachable!("prevented by clap"), + } +} + +fn parse_package_args(args: &clap::ArgMatches) -> PackageAction { + use PackageAction::*; + + match args.subcommand() { + Some(("clean", args)) => Clean(get_noconfirm(args)), + Some(("review", _)) => Review, + Some(("search", args)) => Search(get_regex(args)), + Some(("sync", args)) => Sync(get_noconfirm(args)), + Some(("unmanaged", _)) => Unmanaged, + Some(value) => panic!("package subcommand was not matched: {value:?}"), + None => unreachable!("prevented by clap"), + } +} + +fn get_one_arg(args: &clap::ArgMatches, id: &str) -> T +where + T: std::any::Any + Clone + Sync + Send + 'static, +{ + args.get_one::(id).expect(ARGS_CONSISTENT).to_owned() +} + +fn get_regex(args: &clap::ArgMatches) -> Regex { + Regex(get_one_arg(args, "regex")) +} + +fn get_noconfirm(args: &clap::ArgMatches) -> Noconfirm { + Noconfirm(get_one_arg(args, "noconfirm")) +} + +fn get_edit(args: &clap::ArgMatches) -> Edit { + Edit(get_one_arg(args, "edit")) +} + +fn get_groups(args: &clap::ArgMatches) -> Groups { + Groups( + args.get_many::("groups") + .expect(ARGS_CONSISTENT) + .cloned() + .collect(), + ) +} diff --git a/crates/pacdef_core/src/core.rs b/crates/pacdef_core/src/core.rs index 4686eee..157296e 100644 --- a/crates/pacdef_core/src/core.rs +++ b/crates/pacdef_core/src/core.rs @@ -4,28 +4,24 @@ use std::os::unix::fs::symlink; use std::path::Path; use anyhow::{bail, ensure, Context, Result}; -use clap::ArgMatches; use const_format::formatcp; -use crate::action::*; -use crate::args; +use crate::args::{self, PackageAction}; use crate::backend::{Backend, Backends, ToDoPerBackend}; use crate::cmd::run_edit_command; use crate::env::get_single_var; -use crate::path::{binary_in_path, get_group_dir}; +use crate::path::{binary_in_path, get_absolutized_file_paths, get_group_dir}; use crate::review; use crate::search; use crate::ui::get_user_confirmation; use crate::Config; use crate::Group; -const UNREACHABLE_ARM: &str = "argument parser requires some subcommand to return an `ArgMatches`"; -const ACTION_NOT_MATCHED: &str = "could not match action"; - /// Most data that is required during runtime of the program. +/// `args` is an `Option` so that we can take ownership later without cloning. #[allow(dead_code)] // "`config` is only needed on Arch Linux" pub struct Pacdef { - args: ArgMatches, + args: Option, config: Config, groups: HashSet, } @@ -34,9 +30,9 @@ impl Pacdef { /// Creates a new [`Pacdef`]. `config` should be passed from [`Config::load`], and `args` from /// [`args::get`]. #[must_use] - pub const fn new(args: ArgMatches, config: Config, groups: HashSet) -> Self { + pub const fn new(args: args::Arguments, config: Config, groups: HashSet) -> Self { Self { - args, + args: Some(args), config, groups, } @@ -57,37 +53,39 @@ impl Pacdef { /// This function propagates errors from the underlying functions. #[allow(clippy::unit_arg)] pub fn run_action_from_arg(mut self) -> Result<()> { - match self.args.subcommand() { - Some(("group", args)) => match args.subcommand() { - Some((EDIT, args)) => self.edit_group_files(args).context("editing group files"), - Some((IMPORT, args)) => self.import_groups(args).context("importing groups"), - Some((LIST, _)) => Ok(self.show_groups()), - Some((NEW, args)) => self.new_groups(args).context("creating new group files"), - Some((REMOVE, args)) => self.remove_groups(args).context("removing groups"), - Some((SHOW, args)) => self.show_group_content(args).context("showing groups"), + match self + .args + .take() + .expect("if there were no args we would not get to here") + { + args::Arguments::Group(group_args) => self.run_group_subcommand(&group_args), + args::Arguments::Package(package_args) => self.run_package_subcommand(&package_args), + args::Arguments::Version => Ok(self.show_version()), + } + } - Some((_, _)) => panic!("{ACTION_NOT_MATCHED}"), - None => unreachable!("{UNREACHABLE_ARM}"), - }, + fn run_group_subcommand(self, args: &args::GroupAction) -> Result<()> { + use args::GroupAction::*; - Some(("package", args)) => match args.subcommand() { - Some((CLEAN, args)) => self.clean_packages(&args.clone()), - Some((REVIEW, _)) => review::review(self.get_unmanaged_packages()?, self.groups) - .context("review unmanaged packages"), - Some((SEARCH, args)) => { - search::search_packages(args, &self.groups).context("searching packages") - } - Some((SYNC, args)) => self.install_packages(&args.clone()), // TODO fix cloning - Some((UNMANAGED, _)) => self.show_unmanaged_packages(), + match args { + Edit(groups) => self.edit_groups(&groups.0), + Import(groups) => self.import_groups(&groups.0), + List => self.show_groups(), + New(groups, args::Edit(edit)) => self.new_groups(&groups.0, *edit), + Remove(groups) => self.remove_groups(&groups.0), + Show(groups) => self.show_group_content(&groups.0), + } + } - Some((_, _)) => panic!("{ACTION_NOT_MATCHED}"), - None => unreachable!("{UNREACHABLE_ARM}"), - }, + fn run_package_subcommand(mut self, args: &PackageAction) -> Result<()> { + use args::PackageAction::*; - Some((VERSION, _)) => Ok(self.show_version()), - - Some((_, _)) => panic!("{ACTION_NOT_MATCHED}"), - None => unreachable!("{UNREACHABLE_ARM}"), + match args { + Clean(noconfirm) => self.clean_packages(noconfirm.0), + Review => review::review(self.get_unmanaged_packages()?, self.groups), + Search(regex) => search::search_packages(®ex.0, &self.groups), + Sync(noconfirm) => self.install_packages(noconfirm.0), + Unmanaged => self.show_unmanaged_packages(), } } @@ -137,7 +135,7 @@ impl Pacdef { } } - fn install_packages(&mut self, args: &ArgMatches) -> Result<()> { + fn install_packages(&mut self, noconfirm: bool) -> Result<()> { let to_install = self.get_missing_packages()?; if to_install.nothing_to_do_for_all_backends() { @@ -148,10 +146,6 @@ impl Pacdef { println!("Would install the following packages:\n"); to_install.show().context("printing things to do")?; - let noconfirm = *args - .get_one::("noconfirm") - .expect("has a default value"); - println!(); if noconfirm { println!("proceeding without confirmation"); @@ -162,8 +156,8 @@ impl Pacdef { to_install.install_missing_packages(noconfirm) } - fn edit_group_files(&self, arg_matches: &ArgMatches) -> Result<()> { - let group_files = get_group_file_paths_matching_args(arg_matches, &self.groups) + fn edit_groups(&self, groups: &[String]) -> Result<()> { + let group_files = get_group_file_paths_matching_args(groups, &self.groups) .context("getting group files for args")?; let success = run_edit_command(&group_files) @@ -225,15 +219,16 @@ impl Pacdef { Ok(result) } - fn show_groups(self) { + fn show_groups(self) -> Result<()> { let mut vec: Vec<_> = self.groups.iter().collect(); vec.sort_unstable(); for g in vec { println!("{}", g.name); } + Ok(()) } - fn clean_packages(&mut self, args: &ArgMatches) -> Result<()> { + fn clean_packages(&mut self, noconfirm: bool) -> Result<()> { let to_remove = self.get_unmanaged_packages()?; if to_remove.nothing_to_do_for_all_backends() { @@ -244,10 +239,6 @@ impl Pacdef { println!("Would remove the following packages:\n"); to_remove.show().context("printing things to do")?; - let noconfirm = *args - .get_one::("noconfirm") - .expect("has a default value"); - println!(); if noconfirm { println!("proceeding without confirmation"); @@ -258,17 +249,12 @@ impl Pacdef { to_remove.remove_unmanaged_packages(noconfirm) } - fn show_group_content(&self, groups: &ArgMatches) -> Result<()> { - let args: Vec<_> = groups - .get_many::("groups") - .context("getting groups from args")? - .collect(); - + fn show_group_content(&self, args: &[String]) -> Result<()> { let mut errors = vec![]; let mut groups = vec![]; // make sure all args exist before doing anything - for arg_group in &args { + for arg_group in args { let group = self.groups.iter().find(|g| g.name == **arg_group); let group = match group { @@ -312,8 +298,8 @@ impl Pacdef { } #[allow(clippy::unused_self)] - fn import_groups(&self, args: &ArgMatches) -> Result<()> { - let files = args::get_absolutized_file_paths(args)?; + fn import_groups(&self, file_names: &[String]) -> Result<()> { + let files = get_absolutized_file_paths(file_names)?; let groups_dir = get_group_dir()?; for target in files { @@ -341,8 +327,8 @@ impl Pacdef { Ok(()) } - fn remove_groups(&self, arg_match: &ArgMatches) -> Result<()> { - let paths = get_group_file_paths_matching_args(arg_match, &self.groups)?; + fn remove_groups(&self, groups: &[String]) -> Result<()> { + let paths = get_group_file_paths_matching_args(groups, &self.groups)?; for file in paths { remove_file(file)?; @@ -352,16 +338,11 @@ impl Pacdef { } #[allow(clippy::unused_self)] - fn new_groups(&self, arg_matches: &ArgMatches) -> Result<()> { + fn new_groups(&self, new_groups: &[String], edit: bool) -> Result<()> { let group_path = get_group_dir()?; - let new_group_names: Vec<_> = arg_matches - .get_many::("groups") - .context("getting groups from args")? - .collect(); - // prevent group names that resolve to directories - for name in &new_group_names { + for name in new_groups { ensure!( *name != ".", crate::Error::InvalidGroupName(".".to_string()) @@ -372,8 +353,8 @@ impl Pacdef { ); } - let paths: Vec<_> = new_group_names - .into_iter() + let paths: Vec<_> = new_groups + .iter() .map(|name| { let mut base = group_path.clone(); base.push(name); @@ -392,7 +373,7 @@ impl Pacdef { File::create(file)?; } - if arg_matches.get_flag("edit") { + if edit { let success = run_edit_command(&paths) .context("running editor")? .success(); @@ -410,14 +391,9 @@ impl Pacdef { /// /// This function will return an error if any of the arguments do not match one of group names. fn get_group_file_paths_matching_args<'a>( - arg_match: &ArgMatches, + file_names: &[String], groups: &'a HashSet, ) -> Result> { - let file_names: Vec<_> = arg_match - .get_many::("groups") - .context("getting groups from args")? - .collect(); - let name_group_map: HashMap<&str, &Group> = groups.iter().map(|g| (g.name.as_str(), g)).collect(); diff --git a/crates/pacdef_core/src/lib.rs b/crates/pacdef_core/src/lib.rs index c1ba70c..d0a8216 100644 --- a/crates/pacdef_core/src/lib.rs +++ b/crates/pacdef_core/src/lib.rs @@ -21,7 +21,6 @@ This library contains all logic that happens in `pacdef` under the hood. missing_docs )] -mod action; mod args; mod backend; mod cmd; diff --git a/crates/pacdef_core/src/path.rs b/crates/pacdef_core/src/path.rs index fd355c5..e5805ad 100644 --- a/crates/pacdef_core/src/path.rs +++ b/crates/pacdef_core/src/path.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use std::{env, path::Path}; use anyhow::{Context, Result}; +use path_absolutize::Absolutize; const CONFIG_FILE_NAME: &str = "pacdef.yaml"; const CONFIG_FILE_NAME_OLD: &str = "pacdef.conf"; @@ -120,6 +121,19 @@ where relative_path } +/// For each file argument, return the absolute path to the file. +pub(crate) fn get_absolutized_file_paths(arg_match: &[String]) -> Result> { + Ok(arg_match + .iter() + .map(PathBuf::from) + .map(|path| { + path.absolutize() + .expect("absolute path should exist") + .into_owned() + }) + .collect()) +} + #[cfg(test)] mod tests { use std::path::PathBuf; diff --git a/crates/pacdef_core/src/search.rs b/crates/pacdef_core/src/search.rs index 23e5a9e..7d3e160 100644 --- a/crates/pacdef_core/src/search.rs +++ b/crates/pacdef_core/src/search.rs @@ -2,8 +2,7 @@ use std::collections::HashSet; use std::iter::Peekable; use std::vec::IntoIter; -use anyhow::{bail, Context, Result}; -use clap::ArgMatches; +use anyhow::{bail, Result}; use regex::Regex; use crate::grouping::{Group, Package, Section}; @@ -17,8 +16,8 @@ use crate::grouping::{Group, Package, Section}; /// This function will return an error if /// - an invalid regex was provided, or /// - no matching packages could be found. -pub fn search_packages(args: &ArgMatches, groups: &HashSet) -> Result<()> { - let re = get_regex_from_args(args)?; +pub fn search_packages(regex_str: &str, groups: &HashSet) -> Result<()> { + let re = Regex::new(regex_str)?; let mut vec = vec![]; @@ -41,21 +40,6 @@ pub fn search_packages(args: &ArgMatches, groups: &HashSet) -> Result<()> Ok(()) } -/// Extract the user-provided regex from the command-line args. -/// -/// # Errors -/// -/// This function will return an error if an invalid regex was provided. -fn get_regex_from_args(args: &ArgMatches) -> Result { - let search_string = args - .get_one::("regex") - .context("getting search string from arg")?; - - let re = Regex::new(search_string)?; - - Ok(re) -} - fn print_triples(mut vec: Vec<(&Group, &Section, &Package)>) { vec.sort_unstable(); diff --git a/crates/pacdef_macros/src/action.rs b/crates/pacdef_macros/src/action.rs deleted file mode 100644 index 47ef05b..0000000 --- a/crates/pacdef_macros/src/action.rs +++ /dev/null @@ -1,77 +0,0 @@ -use proc_macro::TokenStream; -use quote::quote; -use syn::{DeriveInput, __private::TokenStream2}; - -pub fn action(input: TokenStream) -> TokenStream { - let input = syn::parse::(input).expect("I don't know when this could fail"); - - let name = &input.ident; - - let syn::Data::Enum(enum_data) = &input.data else { - panic!("`Register` can only be used on enums"); - }; - - let variant_description = generate_variant_description(enum_data); - let variant_constants = generate_variant_constants(name, enum_data); - - let expanded = compile_output(name, variant_description, variant_constants); - - TokenStream::from(expanded) -} - -fn generate_variant_description( - enum_data: &syn::DataEnum, -) -> impl Iterator + '_ { - let variant_matches_backend = enum_data.variants.iter().map(|variant| { - let variant_name = &variant.ident; - let variant_lowercase = - proc_macro2::Literal::string(&variant_name.to_string().to_lowercase()); - quote! { - Self::#variant_name => #variant_lowercase, - } - }); - variant_matches_backend -} - -fn generate_variant_constants<'a>( - name: &'a syn::Ident, - enum_data: &'a syn::DataEnum, -) -> impl Iterator + 'a { - let result = enum_data.variants.iter().map(move |variant| { - let variant_name = &variant.ident; - - let variant_uppercase = proc_macro2::Ident::new( - &variant_name.to_string().to_uppercase(), - proc_macro2::Span::call_site(), - ); - - quote! { - pub const #variant_uppercase: &str = #name::#variant_name.name(); - } - }); - result -} - -fn compile_output( - name: &syn::Ident, - variant_description: T, - variant_constants: U, -) -> TokenStream2 -where - T: Iterator, - U: Iterator, -{ - let expanded = quote! { - impl #name { - /// Return the lowercase name of the enum variant as `&str`. - const fn name(&self) -> &'static str { - match self { - #(#variant_description)* - } - } - } - - #(#variant_constants)* - }; - expanded -} diff --git a/crates/pacdef_macros/src/lib.rs b/crates/pacdef_macros/src/lib.rs index 40161a5..70466be 100644 --- a/crates/pacdef_macros/src/lib.rs +++ b/crates/pacdef_macros/src/lib.rs @@ -21,7 +21,6 @@ Procedural macros for `pacdef`. missing_docs )] -mod action; mod register; use proc_macro::TokenStream; @@ -32,10 +31,3 @@ use proc_macro::TokenStream; pub fn register(input: TokenStream) -> TokenStream { register::register(input) } - -/// Derive public constants from each variant of the enum, such that the name of the constant is -/// the name of the variant in all caps, and the value is the name of the variant in lowercase. -#[proc_macro_derive(Action)] -pub fn action(input: TokenStream) -> TokenStream { - action::action(input) -}