use std::ffi::OsString;
use subx_cli::cli::output::{self, OutputMode};
#[tokio::main]
async fn main() {
let argv: Vec<OsString> = std::env::args_os().collect();
let tentative_mode = sniff_output_mode(&argv);
let tentative_quiet = sniff_quiet(&argv);
if tentative_quiet && tentative_mode.is_json() {
let _ = env_logger::Builder::new()
.filter_level(log::LevelFilter::Off)
.try_init();
} else {
env_logger::init();
}
let cli_parse = <subx_cli::cli::Cli as clap::Parser>::try_parse_from(argv.iter());
if let Err(err) = cli_parse {
handle_clap_error(err, tentative_mode);
}
let outcome = run_application().await;
match outcome.result {
Ok(_) => std::process::exit(0),
Err(e) => {
if outcome.output_mode.is_json() {
output::emit_error(outcome.output_mode, outcome.command, &e);
} else {
eprintln!("{}", e.user_friendly_message());
}
std::process::exit(e.exit_code());
}
}
}
fn sniff_quiet(argv: &[OsString]) -> bool {
let mut iter = argv.iter().skip(1);
while let Some(arg) = iter.next() {
let s = match arg.to_str() {
Some(s) => s,
None => continue,
};
if s == "--quiet" {
return true;
}
if s == "--output" {
let _ = iter.next();
continue;
}
if s.starts_with("--output=") {
continue;
}
if !s.starts_with('-') {
break;
}
}
false
}
fn sniff_output_mode(argv: &[OsString]) -> OutputMode {
let mut iter = argv.iter().skip(1);
while let Some(arg) = iter.next() {
let s = match arg.to_str() {
Some(s) => s,
None => continue,
};
if let Some(value) = s.strip_prefix("--output=") {
if let Some(mode) = OutputMode::from_token(value) {
return mode;
}
} else if s == "--output" {
if let Some(value) = iter.next().and_then(|v| v.to_str())
&& let Some(mode) = OutputMode::from_token(value)
{
return mode;
}
} else if !s.starts_with('-') {
break;
}
}
if let Ok(value) = std::env::var("SUBX_OUTPUT")
&& let Some(mode) = OutputMode::from_token(&value)
{
return mode;
}
OutputMode::Text
}
fn handle_clap_error(err: clap::Error, tentative_mode: OutputMode) -> ! {
use clap::error::ErrorKind;
let exit_code = err.exit_code();
match err.kind() {
ErrorKind::DisplayHelp
| ErrorKind::DisplayVersion
| ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => {
let _ = err.print();
std::process::exit(exit_code);
}
_ => {
if tentative_mode.is_json() {
let rendered = err.render().to_string();
let message = output::strip_ansi(&rendered);
output::emit_argument_parsing_error(None, message, exit_code);
} else {
let _ = err.print();
}
std::process::exit(exit_code);
}
}
}
async fn run_application() -> subx_cli::cli::RunOutcome {
match subx_cli::config::ProductionConfigService::new() {
Ok(config_service) => subx_cli::cli::run_with_config(&config_service).await,
Err(e) => subx_cli::cli::RunOutcome {
output_mode: output::active_mode(),
quiet: false,
command: "",
result: Err(e),
},
}
}