revoke-cli 0.3.0

Command-line interface for managing Revoke microservices infrastructure
use clap::{Parser, Subcommand};
use anyhow::Result;
use colored::Colorize;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

mod commands;
mod config;
mod utils;

use commands::*;

/// Revoke Framework CLI - Manage your microservices infrastructure
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
    /// Config file path
    #[arg(short, long, global = true, env = "REVOKE_CONFIG")]
    config: Option<String>,

    /// Verbosity level
    #[arg(short, long, global = true, action = clap::ArgAction::Count)]
    verbose: u8,

    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Manage services
    Service {
        #[command(subcommand)]
        command: ServiceCommands,
    },
    /// Manage configuration
    Config {
        #[command(subcommand)]
        command: ConfigCommands,
    },
    /// Manage gateway
    Gateway {
        #[command(subcommand)]
        command: GatewayCommands,
    },
    /// View traces
    Trace {
        #[command(subcommand)]
        command: TraceCommands,
    },
    /// Health check commands
    Health {
        #[command(subcommand)]
        command: HealthCommands,
    },
    /// Initialize a new Revoke project
    Init {
        /// Project name
        #[arg(default_value = "my-revoke-app")]
        name: String,
        /// Project template
        #[arg(short, long, default_value = "basic")]
        template: String,
    },
    /// Start development environment
    Dev {
        /// Services to start
        #[arg(short, long)]
        services: Vec<String>,
        /// Start all services
        #[arg(short, long)]
        all: bool,
    },
}

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();

    // Initialize logging
    init_logging(cli.verbose);

    // Load configuration
    let config = config::load_config(cli.config.as_deref())?;

    // Execute command
    match cli.command {
        Commands::Service { command } => {
            service::handle_command(command, &config).await?
        }
        Commands::Config { command } => {
            commands::config::handle_command(command, &config).await?
        }
        Commands::Gateway { command } => {
            gateway::handle_command(command, &config).await?
        }
        Commands::Trace { command } => {
            trace::handle_command(command, &config).await?
        }
        Commands::Health { command } => {
            health::handle_command(command, &config).await?
        }
        Commands::Init { name, template } => {
            init::handle_init(&name, &template).await?
        }
        Commands::Dev { services, all } => {
            dev::handle_dev(services, all, &config).await?
        }
    }

    Ok(())
}

fn init_logging(verbosity: u8) {
    let filter = match verbosity {
        0 => "warn",
        1 => "info",
        2 => "debug",
        _ => "trace",
    };

    tracing_subscriber::registry()
        .with(tracing_subscriber::EnvFilter::try_from_default_env()
            .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(filter)))
        .with(tracing_subscriber::fmt::layer()
            .with_target(false)
            .with_thread_ids(false))
        .init();
}