use clap::{CommandFactory, FromArgMatches, Parser, Subcommand};
use clap_complete::Shell;
#[derive(Parser, Debug)]
#[command(
name = "fez",
version,
about = "Agent-native management CLI for Fedora/RHEL"
)]
pub struct Cli {
#[arg(long, global = true)]
pub host: Option<String>,
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub dry_run: bool,
#[arg(long, global = true)]
pub force: bool,
#[command(subcommand)]
pub command: TopCommand,
}
impl Cli {
#[must_use]
pub fn resolved_host(&self) -> String {
crate::transport::from_host(self.host.as_deref()).host_label()
}
}
pub fn raw_command() -> clap::Command {
<Cli as CommandFactory>::command()
}
pub fn command() -> clap::Command {
crate::capability::help::inject(raw_command())
}
pub fn parse() -> Cli {
let matches = command().get_matches();
Cli::from_arg_matches(&matches).expect("clap validated args")
}
#[derive(Subcommand, Debug)]
pub enum TopCommand {
Capabilities,
Describe {
capability: String,
},
Guide,
Completions {
#[arg(value_enum)]
shell: Shell,
},
#[command(hide = true)]
Man,
Services {
#[command(subcommand)]
action: ServicesAction,
},
Mcp,
}
#[derive(Subcommand, Debug)]
pub enum ServicesAction {
List {
#[arg(long)]
state: Option<String>,
},
Status {
unit: String,
},
Logs {
unit: String,
#[arg(long)]
since: Option<String>,
#[arg(long)]
priority: Option<String>,
#[arg(long)]
lines: Option<u32>,
#[arg(long)]
follow: bool,
},
Start {
unit: String,
},
Stop {
unit: String,
},
Restart {
unit: String,
},
Reload {
unit: String,
},
Enable {
unit: String,
#[arg(long)]
now: bool,
},
Disable {
unit: String,
#[arg(long)]
now: bool,
},
}
#[cfg(test)]
mod tests {
use super::*;
fn cli(args: &[&str]) -> Cli {
Cli::try_parse_from(args).expect("args parse")
}
#[test]
fn resolved_host_defaults_to_localhost() {
assert_eq!(
cli(&["fez", "services", "list"]).resolved_host(),
"localhost"
);
}
#[test]
fn resolved_host_normalizes_local_alias() {
assert_eq!(
cli(&["fez", "--host", "local", "services", "list"]).resolved_host(),
"localhost"
);
}
#[test]
fn resolved_host_passes_through_explicit_host() {
assert_eq!(
cli(&["fez", "--host", "fedora@box.example", "services", "list"]).resolved_host(),
"fedora@box.example"
);
}
}