CLI app for developers prototyping atproto functionality
1//! Root clap parser and dispatch entry point.
2
3use clap::Parser;
4use miette::Result;
5use std::process::ExitCode;
6use tracing_subscriber::{EnvFilter, fmt};
7
8use crate::commands::Command;
9use crate::common::diagnostics::install_miette_handler;
10
11/// Top-level `atproto-devtool` CLI.
12#[derive(Debug, Parser)]
13#[command(
14 name = "atproto-devtool",
15 version,
16 about = "Diagnostics and conformance tooling for atproto services.",
17 long_about = None,
18)]
19struct Cli {
20 /// Enable verbose (DEBUG-level) logging to stderr.
21 #[arg(long, global = true)]
22 verbose: bool,
23
24 /// Disable ANSI color in rendered diagnostics.
25 #[arg(long, global = true)]
26 no_color: bool,
27
28 #[command(subcommand)]
29 command: Command,
30}
31
32/// Parse `std::env::args()`, install global handlers, and dispatch.
33///
34/// Returns `Result<ExitCode, miette::Report>` to propagate exit codes through
35/// the dispatch chain. The main handler renders errors with exit code 1.
36pub async fn run() -> Result<ExitCode> {
37 let cli = Cli::parse();
38
39 // Check NO_COLOR environment variable in addition to --no-color flag.
40 // NO_COLOR takes effect if present and non-empty, per https://no-color.org/
41 let no_color = cli.no_color || std::env::var("NO_COLOR").is_ok();
42
43 install_miette_handler(no_color)?;
44 install_tracing(cli.verbose);
45
46 cli.command.run(no_color).await
47}
48
49fn install_tracing(verbose: bool) {
50 let default_filter = if verbose { "debug" } else { "warn" };
51 let filter =
52 EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default_filter));
53
54 let _ = fmt()
55 .with_env_filter(filter)
56 .with_writer(std::io::stderr)
57 .try_init();
58}