use clap::{Parser, Subcommand};
use crate::shared::error::{Error, ErrorCode};
#[derive(Parser, Debug)]
#[command(name = "afhttp", version, verbatim_doc_comment)]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Host(crate::cli::cmd::host::Args),
Fetch(Box<crate::cli::cmd::fetch::Args>),
Upload(crate::cli::cmd::upload::Args),
Cdp(crate::cli::cmd::cdp::Args),
Ui(crate::cli::cmd::ui::Args),
Health(crate::cli::cmd::health::Args),
Capabilities(crate::cli::cmd::capabilities::Args),
Profile(crate::cli::cmd::profile::Args),
Tabs(crate::cli::cmd::tabs::Args),
Skill(crate::cli::cmd::skill::Args),
Container(crate::cli::cmd::container::Args),
}
pub struct Parsed {
pub command: Command,
}
pub fn parse() -> Result<Parsed, Error> {
let cli = Cli::try_parse().map_err(|e| {
use clap::error::ErrorKind;
if matches!(
e.kind(),
ErrorKind::DisplayHelp
| ErrorKind::DisplayVersion
| ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
) {
let _ = e.print();
std::process::exit(0);
}
Error::new(ErrorCode::InvalidArgument, e.to_string())
})?;
Ok(Parsed {
command: cli.command,
})
}
#[cfg(test)]
mod tests {
use clap::CommandFactory;
use super::*;
#[test]
fn clap_command_flag_snapshot_matches() {
let mut snapshot = String::new();
write_command_snapshot(&Cli::command(), 0, &mut snapshot);
assert_eq!(
snapshot,
include_str!("../../tests/golden/cli-command-flags.txt")
);
}
#[test]
fn cli_contract_has_no_legacy_aliases() {
let command = Cli::command();
assert_eq!(command.get_subcommands().count(), 11);
let mut snapshot = String::new();
write_command_snapshot(&command, 0, &mut snapshot);
for forbidden in [
" command download\n",
"--profile-name",
concat!("profile", "_name"),
concat!("?", "profile="),
"legacy",
] {
assert!(
!snapshot.contains(forbidden),
"CLI contract retained forbidden legacy surface {forbidden:?}: {snapshot}"
);
}
}
fn write_command_snapshot(cmd: &clap::Command, depth: usize, out: &mut String) {
let indent = " ".repeat(depth);
out.push_str(&format!("{indent}command {}\n", cmd.get_name()));
for arg in cmd.get_arguments() {
let long = arg
.get_long()
.map(|v| format!(" --{v}"))
.unwrap_or_default();
out.push_str(&format!("{indent} arg {}{long}\n", arg.get_id()));
}
for sub in cmd.get_subcommands() {
write_command_snapshot(sub, depth + 1, out);
}
}
}