Files
rayhunter/installer-gui/src-tauri/src/introspect.rs
T
2026-06-18 15:25:12 -07:00

118 lines
3.7 KiB
Rust

//! Combines the values we care about from the clap CLI and the modifiers module into something
//! serializable by serde.
use std::collections::HashMap;
use anyhow::Context;
use log::error;
use serde::Serialize;
use crate::modifiers;
#[derive(Debug, Serialize)]
pub struct Command<'a> {
subcommands: Vec<Subcommand<'a>>,
}
impl Command<'_> {
pub fn new(command: &clap::Command) -> Command<'_> {
let subcommand_map: HashMap<&str, &clap::Command> = command
.get_subcommands()
.map(|s| (s.get_name(), s))
.collect();
Command {
// this resulting vector contains the subcommands that are found in both
// command.get_subcommands() and modifiers::subcommand_modifiers() in the order defined
// by subcommand_modifiers()
subcommands: modifiers::subcommand_modifiers()
.iter()
.filter_map(|modifier| match subcommand_map.get(modifier.command) {
Some(clap_command) => Some(Subcommand::new(clap_command, modifier)),
None => {
error!(
"failed to find clap command for subcommand {}",
modifier.command
);
None
}
})
.collect(),
}
}
}
#[derive(Debug, Serialize)]
struct Argument<'a> {
advanced: bool,
flag: String,
label: &'a str,
takes_values: bool,
}
#[derive(Debug, Serialize)]
struct Subcommand<'a> {
arguments: Vec<Argument<'a>>,
command: &'a str,
label: &'a str,
}
impl Argument<'_> {
fn try_new<'a>(
argument: &'a clap::Arg,
modifier: &modifiers::ArgumentModifier<'static>,
) -> anyhow::Result<Argument<'a>> {
let partial_flag = argument.get_long().with_context(|| {
format!(
"Missing long form command line flag for {}",
argument.get_id().as_str(),
)
})?;
Ok(Argument {
advanced: modifier.advanced,
flag: format!("--{}", partial_flag),
label: modifier.gui_label,
takes_values: argument.get_action().takes_values(),
})
}
}
impl Subcommand<'_> {
fn new<'a>(
command: &'a clap::Command,
modifier: &modifiers::SubcommandModifier<'static>,
) -> Subcommand<'a> {
let argument_map: HashMap<&str, &clap::Arg> = command
.get_arguments()
.map(|a| (a.get_id().as_str(), a))
.collect();
Subcommand {
// this resulting vector contains the arguments that are found in both
// command.get_arguments() and modifier.arg_modifiers in the order defined by by
// arg_modifiers
arguments: modifier
.arg_modifiers
.iter()
.filter_map(|arg_modifier| {
let Some(arg) = argument_map.get(arg_modifier.clap_id) else {
error!(
"failed to find clap argument with id {}",
arg_modifier.clap_id
);
return None;
};
match Argument::try_new(arg, arg_modifier) {
Ok(modified_arg) => Some(modified_arg),
Err(err) => {
error!("failed to create modified argument: {:?}", err);
None
}
}
})
.collect(),
command: modifier.command,
label: modifier.gui_label,
}
}
}