use clap::{Args, Parser, Subcommand};
use xbp::commands::curl;
use xbp::commands::redeploy_v2::run_redeploy_v2;
use xbp::commands::{install_package, run_config, run_ports, run_redeploy, run_setup};
use xbp::commands::{pm2_list, pm2_logs};
use xbp::logging::{init_logger, log_error, log_info, log_success};
#[derive(Parser, Debug)]
#[command(
name = "xbp",
version,
about = "XBP CLI",
disable_help_subcommand = false
)]
struct Cli {
#[arg(long, global = true)]
debug: bool,
#[arg(short = 'l', help = "List pm2 processes")]
list: bool,
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand, Debug)]
enum Commands {
Ports(PortsCmd),
Setup,
Redeploy,
RedeployV2(RedeployV2Cmd),
Config,
Install { package: String },
Logs(LogsCmd),
List,
Curl,
}
#[derive(Args, Debug)]
struct PortsCmd {
#[arg(short = 'p', long = "port")]
port: Option<u16>,
#[arg(long = "kill")]
kill: bool,
#[arg(short = 'n')]
nginx: bool,
}
#[derive(Args, Debug)]
struct RedeployV2Cmd {
#[arg(short = 'p', long = "password")]
password: Option<String>,
#[arg(short = 'u', long = "username")]
username: Option<String>,
#[arg(short = 'h', long = "host")]
host: Option<String>,
#[arg(short = 'd', long = "project-dir")]
project_dir: Option<String>,
}
#[derive(Args, Debug)]
struct LogsCmd {
#[arg()]
project: Option<String>,
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let debug = cli.debug;
if let Err(e) = init_logger(debug).await {
eprintln!("Failed to initialize logger: {}", e);
}
if cli.list && cli.command.is_none() {
if let Err(e) = pm2_list(debug).await {
eprintln!("\x1b[91m❌ pm2 list failed: {}\x1b[0m", e);
}
return;
}
match cli.command {
Some(Commands::Ports(cmd)) => {
let mut sim_args: Vec<String> = Vec::new();
if let Some(p) = cmd.port {
sim_args.push("-p".to_string());
sim_args.push(p.to_string());
}
if cmd.kill {
sim_args.push("--kill".to_string());
}
if cmd.nginx {
sim_args.push("-n".to_string());
}
if let Err(e) = run_ports(&sim_args, debug).await {
eprintln!("\x1b[91mError running ports: {}\x1b[0m", e);
}
}
Some(Commands::Setup) => {
if let Err(e) = run_setup(debug).await {
eprintln!("\x1b[91mSetup failed: {}\x1b[0m", e);
}
}
Some(Commands::Redeploy) => {
if let Err(e) = run_redeploy(debug).await {
eprintln!("\x1b[91mRedeploy failed: {}\x1b[0m", e);
let _ = log_error("redeploy", "Redeploy failed", Some(&e)).await;
}
}
Some(Commands::RedeployV2(cmd)) => {
let _ = log_info("redeploy_v2", "Starting remote redeploy process", None).await;
match run_redeploy_v2(cmd.password, cmd.username, cmd.host, cmd.project_dir, debug)
.await
{
Ok(()) => {}
Err(e) => {
eprintln!("\x1b[91mRemote redeploy failed: {}\x1b[0m", e);
let _ = log_error("redeploy_v2", "Remote redeploy failed", Some(&e)).await;
}
}
}
Some(Commands::Config) => {
let _ = run_config(debug).await;
}
Some(Commands::Install { package }) => {
let install_msg = format!("Installing package: {}", package);
let _ = log_info("install", &install_msg, None).await;
match install_package(&package, debug).await {
Ok(()) => {
println!("Installation successful");
let success_msg = format!("Successfully installed: {}", package);
let _ = log_success("install", &success_msg, None).await;
}
Err(e) => {
eprintln!("Installation failed: {}", e);
let error_msg = format!("Failed to install: {}", package);
let _ = log_error("install", &error_msg, Some(&e)).await;
}
}
}
Some(Commands::Logs(cmd)) => {
if let Err(e) = pm2_logs(cmd.project, debug).await {
eprintln!("\x1b[91m❌ pm2 logs failed: {}\x1b[0m", e);
}
}
Some(Commands::List) => {
if let Err(e) = pm2_list(debug).await {
eprintln!("\x1b[91m❌ pm2 list failed: {}\x1b[0m", e);
}
}
Some(Commands::Curl) => {
if let Err(e) = curl::run_curl(debug).await {
eprintln!("\x1b[91m❌ Curl command failed: {}\x1b[0m", e);
}
}
None => {
eprintln!("Usage: xbp [SUBCOMMAND] | xbp -l");
}
}
}