use std::any::Any;
use std::sync::Arc;
use crate::cli::{CliArgType, CliCommandRegistration};
pub struct CliBuilder {
state: Option<Arc<dyn Any + Send + Sync>>,
name: String,
}
impl Default for CliBuilder {
fn default() -> Self {
Self {
state: None,
name: env!("CARGO_PKG_NAME").to_string(),
}
}
}
impl CliBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_dependencies(state: Arc<dyn Any + Send + Sync>) -> Self {
Self {
state: Some(state),
name: env!("CARGO_PKG_NAME").to_string(),
}
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
pub fn state(&self) -> Option<&Arc<dyn Any + Send + Sync>> {
self.state.as_ref()
}
pub fn build(&self) -> clap::Command {
let mut root = clap::Command::new(self.name.clone())
.version(env!("CARGO_PKG_VERSION"))
.about("SDForge multi-protocol CLI");
for reg in inventory::iter::<CliCommandRegistration>() {
root = root.subcommand(build_subcommand(reg));
}
#[cfg(feature = "docs")]
{
root = root.subcommand(crate::cli::docs_subcommand::docs_subcommand_definition());
}
root
}
}
fn build_subcommand(reg: &CliCommandRegistration) -> clap::Command {
let mut sub = clap::Command::new(reg.name)
.version(reg.version)
.about(reg.description);
for arg in reg.args {
match arg.arg_type {
CliArgType::Path => {
let clap_arg = clap::Arg::new(arg.name)
.help(arg.description)
.required(arg.required);
sub = sub.arg(clap_arg);
}
CliArgType::Body => {
let mut clap_arg = clap::Arg::new(arg.name)
.help(arg.description)
.long(arg.name);
if arg.required {
clap_arg = clap_arg.required(true);
}
if let Some(default) = arg.default {
clap_arg = clap_arg.default_value(default);
}
sub = sub.arg(clap_arg);
}
CliArgType::State => {
}
}
}
sub
}