use clap::{Args, Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(
name = "xbp",
version,
about = "XBP CLI",
disable_help_subcommand = false
)]
pub struct Cli {
#[arg(long, global = true)]
pub debug: bool,
#[arg(short = 'l', help = "List pm2 processes")]
pub list: bool,
#[arg(short = 'p', long = "port", help = "Filter by port number")]
pub port: Option<u16>,
#[arg(long, help = "Open logs directory")]
pub logs: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Ports(PortsCmd),
Setup,
Redeploy {
#[arg(
help = "Service name to redeploy (optional, uses legacy redeploy.sh if not provided)"
)]
service_name: Option<String>,
},
RedeployV2(RedeployV2Cmd),
Config(ConfigCmd),
Install {
package: String,
},
Logs(LogsCmd),
List,
Curl(CurlCmd),
Services,
Service {
#[arg(help = "Command to run: build, install, start, dev, or --help")]
command: Option<String>,
#[arg(help = "Service name")]
service_name: Option<String>,
},
Nginx(NginxCmd),
Diag(DiagCmd),
Monitor(MonitorCmd),
Snapshot,
Resurrect,
Stop {
#[arg(help = "PM2 process name or 'all' (default: all)")]
target: Option<String>,
},
Flush {
#[arg(help = "Optional PM2 process name")]
target: Option<String>,
},
Login,
Version(VersionCmd),
Env {
#[arg(help = "PM2 process name or id")]
target: String,
},
Tail(TailCmd),
Start {
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
Generate(GenerateCmd),
Secrets(SecretsCmd),
#[cfg(feature = "monitoring")]
Monitoring(MonitoringCmd),
}
#[derive(Args, Debug)]
pub struct PortsCmd {
#[arg(short = 'p', long = "port")]
pub port: Option<u16>,
#[arg(long = "kill")]
pub kill: bool,
#[arg(short = 'n', long = "nginx")]
pub nginx: bool,
#[arg(
long = "full",
help = "Show reconciled active, NGINX, and XBP project ports"
)]
pub full: bool,
}
#[derive(Args, Debug)]
pub struct ConfigCmd {
#[arg(
long,
help = "Show the current project config instead of opening global XBP paths"
)]
pub project: bool,
#[arg(long, help = "Print global XBP paths without opening them")]
pub no_open: bool,
}
#[derive(Args, Debug)]
pub struct CurlCmd {
#[arg(help = "URL or domain to fetch, e.g. example.com or https://example.com/api")]
pub url: Option<String>,
#[arg(long, help = "Disable the default 15 second timeout")]
pub no_timeout: bool,
}
#[derive(Args, Debug)]
pub struct VersionCmd {
#[arg(
help = "Show versions, bump with major/minor/patch, or set an explicit version like 1.2.3"
)]
pub target: Option<String>,
#[arg(long, help = "Show normalized git tags from `git tag --list`")]
pub git: bool,
}
#[derive(Args, Debug)]
pub struct RedeployV2Cmd {
#[arg(short = 'p', long = "password")]
pub password: Option<String>,
#[arg(short = 'u', long = "username")]
pub username: Option<String>,
#[arg(short = 'h', long = "host")]
pub host: Option<String>,
#[arg(short = 'd', long = "project-dir")]
pub project_dir: Option<String>,
}
#[derive(Args, Debug)]
pub struct LogsCmd {
#[arg()]
pub project: Option<String>,
#[arg(long = "ssh-host", help = "SSH host to stream logs from")]
pub ssh_host: Option<String>,
#[arg(long = "ssh-username", help = "SSH username for remote host")]
pub ssh_username: Option<String>,
#[arg(long = "ssh-password", help = "SSH password for remote host")]
pub ssh_password: Option<String>,
}
#[derive(Args, Debug)]
pub struct NginxCmd {
#[command(subcommand)]
pub command: NginxSubCommand,
}
#[derive(Subcommand, Debug)]
pub enum NginxSubCommand {
Setup {
#[arg(short, long, help = "Domain name")]
domain: String,
#[arg(short, long, help = "Port to proxy to")]
port: u16,
},
List,
Show {
#[arg(help = "Optional domain name to inspect")]
domain: Option<String>,
},
Edit {
#[arg(help = "Domain name to edit")]
domain: String,
},
Update {
#[arg(short, long, help = "Domain name to update")]
domain: String,
#[arg(short, long, help = "New port to proxy to")]
port: u16,
},
}
#[derive(Args, Debug)]
pub struct DiagCmd {
#[arg(long, help = "Check Nginx configuration")]
pub nginx: bool,
#[arg(long, help = "Check specific ports (comma-separated)")]
pub ports: Option<String>,
#[arg(long, help = "Skip internet speed test")]
pub no_speed_test: bool,
}
#[derive(Args, Debug)]
pub struct MonitorCmd {
#[command(subcommand)]
pub command: Option<MonitorSubCommand>,
}
#[derive(Subcommand, Debug)]
pub enum MonitorSubCommand {
Check,
Start,
}
#[cfg(feature = "monitoring")]
#[derive(Args, Debug)]
pub struct MonitoringCmd {
#[command(subcommand)]
pub command: MonitoringSubCommand,
}
#[cfg(feature = "monitoring")]
#[derive(Subcommand, Debug)]
pub enum MonitoringSubCommand {
Serve {
#[arg(
short,
long,
default_value = "prodzilla.yml",
help = "Monitoring config file"
)]
file: String,
},
RunOnce {
#[arg(
short,
long,
default_value = "prodzilla.yml",
help = "Monitoring config file"
)]
file: String,
#[arg(long, help = "Run probes only")]
probes_only: bool,
#[arg(long, help = "Run stories only")]
stories_only: bool,
},
List {
#[arg(
short,
long,
default_value = "prodzilla.yml",
help = "Monitoring config file"
)]
file: String,
},
}
#[derive(Args, Debug)]
pub struct TailCmd {
#[arg(long, help = "Tail Kafka topic instead of log files")]
pub kafka: bool,
#[arg(long, help = "Ship logs to Kafka")]
pub ship: bool,
}
#[derive(Args, Debug)]
pub struct GenerateCmd {
#[command(subcommand)]
pub command: GenerateSubCommand,
}
#[derive(Subcommand, Debug)]
pub enum GenerateSubCommand {
Systemd(GenerateSystemdCmd),
}
#[derive(Args, Debug)]
pub struct SecretsCmd {
#[arg(long, help = "GitHub repository override (owner/repo)")]
pub repo: Option<String>,
#[command(subcommand)]
pub command: Option<SecretsSubCommand>,
}
#[derive(Subcommand, Debug)]
pub enum SecretsSubCommand {
List,
Push {
#[arg(long, help = "Path to env file to push (defaults to .env.local/.env)")]
file: Option<String>,
#[arg(long, help = "Force overwrite existing repository variables")]
force: bool,
},
Pull {
#[arg(long, help = "Output file path (default: .env.local)")]
output: Option<String>,
},
GenerateDefault {
#[arg(long, help = "Output file path (default: .env.default)")]
output: Option<String>,
},
Verify,
Help,
}
#[derive(Args, Debug)]
pub struct GenerateSystemdCmd {
#[arg(
long,
default_value = "/etc/systemd/system",
help = "Directory where the systemd units are written"
)]
pub output_dir: PathBuf,
#[arg(long, help = "Only generate the unit for this service name")]
pub service: Option<String>,
}