refact: overhaul arg parsing
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
use crate::core::get_version_string;
|
||||
use clap::{Arg, ArgAction, 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");
|
||||
|
||||
Command::new("pacdef")
|
||||
.about("multi-backend declarative package manager for Linux")
|
||||
.version(get_version_string())
|
||||
.arg_required_else_help(true)
|
||||
.subcommand_required(true)
|
||||
.subcommands([group_cmd, package_cmd, version_cmd])
|
||||
.subcommand_value_name("subcommand")
|
||||
.disable_help_subcommand(true)
|
||||
.disable_version_flag(true)
|
||||
}
|
||||
|
||||
/// Build the `pacdef group` subcommand.
|
||||
fn get_group_cmd() -> Command {
|
||||
let edit = Command::new("edit")
|
||||
.about("edit one or more existing group")
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new("groups")
|
||||
.num_args(1..)
|
||||
.required(true)
|
||||
.help("a previously imported group"),
|
||||
)
|
||||
.visible_alias("e");
|
||||
|
||||
let import = Command::new("import")
|
||||
.about("import one or more group files")
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new("files")
|
||||
.num_args(1..)
|
||||
.required(true)
|
||||
.help("the file to import as group"),
|
||||
)
|
||||
.visible_alias("i");
|
||||
|
||||
let list = Command::new("list")
|
||||
.about("list names of imported groups")
|
||||
.visible_alias("l");
|
||||
|
||||
let new = Command::new("new")
|
||||
.about("create new group files")
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new("edit")
|
||||
.short('e')
|
||||
.long("edit")
|
||||
.help("edit the new group files after creation")
|
||||
.action(clap::ArgAction::SetTrue),
|
||||
)
|
||||
.arg(Arg::new("groups").num_args(1..).required(true))
|
||||
.visible_alias("n");
|
||||
|
||||
let remove = Command::new("remove")
|
||||
.about("remove one or more previously imported groups")
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new("groups")
|
||||
.num_args(1..)
|
||||
.required(true)
|
||||
.help("a previously imported group that will be removed"),
|
||||
)
|
||||
.visible_alias("r");
|
||||
|
||||
let show = Command::new("show")
|
||||
.about("show packages under an imported group")
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new("groups")
|
||||
.num_args(1..)
|
||||
.required(true)
|
||||
.help("group file(s) to show"),
|
||||
)
|
||||
.visible_alias("s");
|
||||
|
||||
Command::new("group")
|
||||
.arg_required_else_help(true)
|
||||
.about("manage groups")
|
||||
.visible_alias("g")
|
||||
.subcommand_required(true)
|
||||
.subcommands([edit, import, list, new, remove, show])
|
||||
}
|
||||
|
||||
/// Build the `pacdef package` subcommand.
|
||||
fn get_package_cmd() -> Command {
|
||||
let sync = Command::new("sync")
|
||||
.about("install packages from all imported groups")
|
||||
.visible_alias("sy")
|
||||
.arg(build_noconfirm_arg());
|
||||
|
||||
let clean = Command::new("clean")
|
||||
.about("remove unmanaged packages")
|
||||
.visible_alias("c")
|
||||
.arg(build_noconfirm_arg());
|
||||
|
||||
let unmanaged = Command::new("unmanaged")
|
||||
.about("show explicitly installed packages not managed by pacdef")
|
||||
.visible_alias("u");
|
||||
|
||||
let review = Command::new("review")
|
||||
.about("review unmanaged packages")
|
||||
.visible_alias("r");
|
||||
|
||||
let search = Command::new("search")
|
||||
.visible_alias("se")
|
||||
.about("search for packages which match a provided regex")
|
||||
.arg_required_else_help(true)
|
||||
.arg(
|
||||
Arg::new("regex")
|
||||
.required(true)
|
||||
.help("the regular expression the package must match"),
|
||||
);
|
||||
|
||||
Command::new("package")
|
||||
.arg_required_else_help(true)
|
||||
.about("manage packages")
|
||||
.visible_alias("p")
|
||||
.subcommand_required(true)
|
||||
.subcommands([clean, review, search, sync, unmanaged])
|
||||
}
|
||||
|
||||
fn build_noconfirm_arg() -> Arg {
|
||||
Arg::new("noconfirm")
|
||||
.long("noconfirm")
|
||||
.help("do not ask for any confirmation")
|
||||
.action(ArgAction::SetTrue)
|
||||
}
|
||||
@@ -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<String>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Groups(pub Vec<String>);
|
||||
|
||||
#[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);
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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<T>(args: &clap::ArgMatches, id: &str) -> T
|
||||
where
|
||||
T: std::any::Any + Clone + Sync + Send + 'static,
|
||||
{
|
||||
args.get_one::<T>(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::<String>("groups")
|
||||
.expect(ARGS_CONSISTENT)
|
||||
.cloned()
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user