use clap::Parser;
use miette::Report;
use cli_args::{CliArgs, OutputFormat};
use errors::AxoAppError;
fn main() {
let config = CliArgs::parse();
axocli::CliAppBuilder::new("axoapp")
.verbose(config.verbose)
.json_errors(config.output_format == OutputFormat::Json)
.start(config, run);
}
fn run(app: &axocli::CliApp<CliArgs>) -> Result<(), Report> {
assert!(
app.config.exclaim_count > 0,
"i have no exclamation marks but i must scream"
);
if app.config.exclaim_count < 3 {
Err(AxoAppError::NotExcitedEnough)?;
}
let message = "hello axoapp";
match app.config.output_format {
OutputFormat::Human => the_impl::print(message, app.config.exclaim_count)?,
OutputFormat::Json => the_impl::print_json(message, app.config.exclaim_count)?,
}
Ok(())
}
mod the_impl {
use crate::errors::Result;
use serde::{Deserialize, Serialize};
pub fn print(message: &str, num_exclaims: u64) -> Result<()> {
print!("{message}");
for _ in 0..num_exclaims {
print!("!");
}
println!();
Ok(())
}
pub fn print_json(message: &str, num_exclaims: u64) -> Result<()> {
#[derive(Serialize, Deserialize)]
struct JsonOutput {
message: String,
num_exclaims: u64,
}
let output = JsonOutput {
message: message.to_owned(),
num_exclaims,
};
serde_json::to_writer_pretty(std::io::stdout(), &output)?;
Ok(())
}
}
mod errors {
use miette::Diagnostic;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, AxoAppError>;
#[derive(Debug, Error, Diagnostic)]
pub enum AxoAppError {
#[error("you're not excited enough!!!!")]
#[diagnostic(help("pass at least 3 to the CLI"))]
NotExcitedEnough,
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),
}
}
mod cli_args {
use clap::{
builder::{PossibleValuesParser, TypedValueParser},
Parser, ValueEnum,
};
use tracing::level_filters::LevelFilter;
#[derive(Parser)]
#[clap(version, about, long_about = None)]
#[clap(args_conflicts_with_subcommands = true)]
pub struct CliArgs {
#[clap(long)]
#[clap(default_value_t = LevelFilter::WARN)]
#[clap(value_parser = PossibleValuesParser::new(["off", "error", "warn", "info", "debug", "trace"]).map(|s| s.parse::<LevelFilter>().expect("possible values are valid")))]
#[clap(help_heading = "GLOBAL OPTIONS", global = true)]
pub verbose: LevelFilter,
#[clap(long, value_enum)]
#[clap(default_value_t = OutputFormat::Human)]
#[clap(help_heading = "GLOBAL OPTIONS", global = true)]
pub output_format: OutputFormat,
pub exclaim_count: u64,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum OutputFormat {
Human,
Json,
}
}