use crate::APP;
use crate::STATS_SOCKET_PATH;
use crate::TRACE_FILE_PREFIX;
use anyhow::Result;
use clap::{Command, Parser, Subcommand};
use clap_complete::{generate, Shell};
use std::fs::File;
use std::io;
use std::path::PathBuf;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(args_conflicts_with_subcommands = true)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Commands>,
#[clap(flatten)]
pub tui: TuiArgs,
}
#[derive(Clone, Parser, Debug)]
#[command(about = APP)]
pub struct TuiArgs {
#[arg(short = 'r', long, default_missing_value = "250")]
pub tick_rate_ms: Option<usize>,
#[arg(short = 'f', long, default_missing_value = "250")]
pub frame_rate_ms: Option<usize>,
#[arg(short, long, default_missing_value = "false")]
pub debug: Option<bool>,
#[arg(short, long, default_missing_value = "false")]
pub exclude_bpf: Option<bool>,
#[arg(short, long, default_missing_value = STATS_SOCKET_PATH.to_string())]
pub stats_socket_path: Option<String>,
#[arg(short, long, default_missing_value = TRACE_FILE_PREFIX.to_string())]
pub trace_file_prefix: Option<String>,
#[arg(long, default_missing_value = "5")]
pub trace_ticks: Option<usize>,
#[arg(long)]
pub trace_duration_ms: Option<u64>,
#[arg(long, default_missing_value = "4", value_parser = clap::value_parser!(u16).range(2..128))]
pub worker_threads: Option<u16>,
#[arg(long, default_missing_value = "3")]
pub trace_tick_warmup: Option<usize>,
#[arg(long)]
pub trace_warmup_ms: Option<u64>,
#[arg(long, default_value_t = -1)]
pub process_id: i32,
#[arg(long, num_args = 1.., value_parser)]
pub perf_events: Vec<String>,
#[arg(long, default_value = "cpu:cpu_total_util_percent")]
pub default_profiling_event: String,
#[arg(long)]
pub layered: bool,
#[arg(
long,
default_value_t = false,
requires("experimental_long_tail_tracing_symbol"),
requires("experimental_long_tail_tracing_binary")
)]
pub experimental_long_tail_tracing: bool,
#[arg(long)]
pub experimental_long_tail_tracing_symbol: Option<String>,
#[arg(long)]
pub experimental_long_tail_tracing_binary: Option<String>,
#[arg(long, default_value_t = 100000000)]
pub experimental_long_tail_tracing_min_latency_ns: u64,
#[arg(long, default_value_t = false)]
pub mangoapp_tracing: bool,
#[arg(long, default_value_t = 1000)]
pub mangoapp_poll_intvl_ms: u64,
#[arg(long, default_value = "mangoapp")]
pub mangoapp_path: String,
}
#[derive(Clone, Parser, Debug)]
#[command(about = "Collects a trace")]
pub struct TraceArgs {
#[arg(short = 'd', long, default_value_t = 1000)]
pub trace_ms: u64,
#[arg(short = 'o', long)]
pub output_file: Option<String>,
#[clap(short = 'v', long, action = clap::ArgAction::Count)]
pub verbose: u8,
#[clap(short = 'k', long, num_args = 1.., value_parser)]
pub kprobes: Vec<String>,
#[clap(short = 's', long)]
pub system_stats: bool,
}
#[derive(Clone, Parser, Debug)]
#[command(about = "Runs the MCP server for scheduler data access")]
pub struct McpArgs {
#[arg(short = 'd', long)]
pub daemon: bool,
#[arg(short = 'l', long)]
pub enable_logging: bool,
#[clap(short = 'v', long, action = clap::ArgAction::Count)]
pub verbose: u8,
#[arg(long, default_value = STATS_SOCKET_PATH)]
pub stats_socket_path: String,
#[arg(long, default_value_t = -1)]
pub process_id: i32,
#[arg(long)]
pub layered: bool,
}
#[allow(clippy::large_enum_variant)]
#[derive(Subcommand)]
pub enum Commands {
Tui(TuiArgs),
Trace(TraceArgs),
Mcp(McpArgs),
#[clap(hide = true)]
GenerateCompletions {
#[clap(short, long, default_value = "bash")]
shell: Shell,
#[arg(long, value_parser(clap::value_parser!(PathBuf)))]
output: Option<PathBuf>,
},
}
pub fn generate_completions(mut app: Command, shell: Shell, output: Option<PathBuf>) -> Result<()> {
let mut file: Box<dyn io::Write> = match output {
Some(path) => Box::new(File::create(path)?),
None => Box::new(io::stdout()),
};
generate(shell, &mut app, "scxtop", &mut file);
Ok(())
}