kegani-cli 0.1.4

CLI tool for Kegani framework
Documentation
//! Kegani CLI — A developer-friendly Rust web framework
//!
//! Usage:
//!   keg init <name>           Create a new project
//!   keg gen <kind> <name>     Generate code
//!   keg run [--watch]         Run with hot reload
//!   keg build [--target TRI]  Build release binary
//!   keg docker                Generate Dockerfile + compose
//!   keg env                   Show environment info
//!   keg up                    Update Kegani
//!   keg migrate <action>      Run migrations
//!   keg clean                 Clean build artifacts

mod commands;
mod types;

use anyhow::Result;
use clap::{Parser, Subcommand};

use commands::{gen::GenKind, db::DbAction, MigrateAction};

/// Kegani CLI — Build production-ready Rust web apps with a single binary
#[derive(Parser)]
#[command(
    name = "keg",
    version,
    author = "Your Name <you@example.com>",
    about = "Kegani: a developer-friendly, ergonomic, production-ready Rust web framework",
    long_about = "Kegani — A complete Rust web framework in a single binary

Commands:
  init        Create a complete project with layered architecture
  new         Alias for init — create a new project
  gen         Generate code: api, model, service, repository, controller, middleware, migration
  list        List available project templates
  run         Run the application with hot reload (file watching)
  serve       Alias for run — starts server with hot reload
  build       Build a release binary (cross-compile supported)
  check       Run cargo check with pretty output
  test        Run tests with options
  docker      Generate Dockerfile and docker-compose.yml
  db          Database operations (create, drop, seed, psql)
  console     Start interactive Rust REPL (evcxr)
  docs        Open Kegani documentation in browser
  info        Show detailed project information
  secret      Generate secure secrets and API keys
  env         Print environment diagnostics
  up          Update Kegani framework and CLI
  migrate     Run database migrations (up, down, status, reset)
  clean       Remove build artifacts

Examples:
  keg init my-api                        Create a new project
  keg new my-api                         Same as init
  keg gen api article                    Generate full CRUD stack
  keg gen model user                     Generate entity
  keg gen migration create_users         Generate SQL migration
  keg run                               Run with hot reload
  keg build --target x86_64-unknown-linux-musl
  keg docker                            Generate Docker files
  keg secret                            Generate a secure secret key
  keg db seed                           Seed the database
  keg console                           Start Rust REPL"
)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Create a complete new project with layered architecture
    Init {
        /// Project name (creates a directory with this name)
        name: Option<String>,

        /// Project template (default: api)
        #[arg(short, long, default_value = "api")]
        template: String,

        /// Run in interactive mode
        #[arg(short, long, default_value = "false")]
        interactive: bool,
    },
    /// Alias for init — create a new project
    New {
        /// Project name (creates a directory with this name)
        name: Option<String>,

        /// Project template (default: api)
        #[arg(short, long, default_value = "api")]
        template: String,

        /// Run in interactive mode
        #[arg(short, long, default_value = "false")]
        interactive: bool,
    },
    /// Generate code (controller, model, service, repository, middleware, migration, or full api)
    Gen {
        /// What to generate
        #[arg(value_enum)]
        kind: GenKind,

        /// Name of the resource to generate
        name: String,

        /// List available generation types
        #[arg(long, default_value = "false")]
        list: bool,
    },
    /// List available project templates
    List {
        /// Show detailed template information
        #[arg(short, long, default_value = "false")]
        verbose: bool,
    },
    /// Serve (alias for `run` — starts server with hot reload)
    Serve {
        /// Port to listen on
        #[arg(short, long, default_value = "8080")]
        port: u16,

        /// Environment (dev, staging, prod)
        #[arg(short, long, default_value = "dev")]
        env: String,
    },
    Run {
        /// Port to listen on
        #[arg(short, long, default_value = "8080")]
        port: u16,

        /// Enable hot reload (watch .rs files for changes)
        #[arg(short, long, default_value = "true")]
        watch: bool,

        /// Environment (dev, staging, prod)
        #[arg(short, long, default_value = "dev")]
        env: String,
    },
    /// Build a release binary
    Build {
        /// Target triple for cross-compilation (e.g., x86_64-unknown-linux-musl)
        #[arg(short, long)]
        target: Option<String>,

        /// Strip symbols from binary
        #[arg(long, default_value = "false")]
        strip: bool,

        /// Enable verbose output
        #[arg(short, long, default_value = "false")]
        verbose: bool,

        /// Show binary size breakdown
        #[arg(long, default_value = "false")]
        size: bool,
    },
    /// Run cargo check with pretty output
    Check {
        /// Enable verbose output
        #[arg(short, long, default_value = "false")]
        verbose: bool,
    },
    /// Run tests
    Test {
        /// Test filter (substring match)
        #[arg(default_value = "")]
        filter: String,

        /// Run tests in release mode
        #[arg(long, default_value = "false")]
        release: bool,

        /// Show test output even on success
        #[arg(short, long, default_value = "false")]
        nocapture: bool,
    },
    /// Generate Dockerfile and docker-compose.yml
    Docker,
    /// Database operations
    Db {
        #[command(subcommand)]
        action: DbAction,
    },
    /// Start interactive Rust REPL (evcxr)
    Console {
        /// Package to load in REPL
        #[arg(short, long)]
        package: Option<String>,
    },
    /// Open Kegani documentation in browser
    Docs {
        /// Documentation section (api, guide, crates)
        #[arg(default_value = "guide")]
        section: String,
    },
    /// Show detailed project information
    Info {
        /// Show in JSON format
        #[arg(long, default_value = "false")]
        json: bool,
    },
    /// Generate secure secrets and API keys
    Secret {
        /// Secret type (secret, token, jwt-secret, api-key)
        #[arg(default_value = "secret")]
        kind: String,

        /// Length of the secret (default: 32)
        #[arg(short, long)]
        length: Option<usize>,
    },
    /// Print environment information and diagnostics
    Env {
        /// Show in JSON format
        #[arg(long, default_value = "false")]
        json: bool,
    },
    /// Update Kegani framework to the latest version
    Up,
    /// Run database migrations
    Migrate {
        /// Migration action
        #[arg(value_enum)]
        action: MigrateAction,
    },
    /// Clean build artifacts
    Clean {
        /// Remove all build artifacts and cache
        #[arg(short, long, default_value = "false")]
        all: bool,
    },
}

fn main() -> Result<()> {
    let cli = Cli::parse();

    match cli.command {
        // Init/New commands
        Commands::Init { name, template, interactive } => {
            let name = name.unwrap_or_else(|| {
                crate::commands::init::prompt_project_name()
            });
            commands::init::init(&name, &template, interactive)?
        }
        Commands::New { name, template, interactive } => {
            let name = name.unwrap_or_else(|| {
                crate::commands::init::prompt_project_name()
            });
            commands::init::init(&name, &template, interactive)?
        }

        // Code generation
        Commands::Gen { kind, name, list } => commands::gen::gen(kind, &name, list)?,
        Commands::List { verbose } => commands::init::list_templates(verbose)?,

        // Running
        Commands::Run { port, watch, env } => commands::run::run(port, watch, &env)?,
        Commands::Serve { port, env } => commands::run::run(port, true, &env)?,

        // Building
        Commands::Build { target, strip, verbose, size } => {
            commands::build::build(target.as_deref(), strip, verbose, size)?
        }

        // Checking and testing
        Commands::Check { verbose } => commands::build::check(verbose)?,
        Commands::Test { filter, release, nocapture } => {
            commands::build::test(&filter, release, nocapture)?
        }

        // Docker
        Commands::Docker => commands::docker::docker()?,

        // Database
        Commands::Db { action } => commands::db::run_db_action(action)?,

        // Console/REPL
        Commands::Console { package } => commands::console::console(package.as_deref())?,

        // Docs
        Commands::Docs { section } => commands::docs::open_docs(&section)?,

        // Info
        Commands::Info { json } => commands::info::info(json)?,

        // Secret generation
        Commands::Secret { kind, length } => commands::secret::generate_secret(&kind, length)?,

        // Environment
        Commands::Env { json } => commands::env::env(json)?,

        // Update
        Commands::Up => commands::update::update()?,

        // Migrations
        Commands::Migrate { action } => commands::migrate::run_migration(action)?,

        // Clean
        Commands::Clean { all } => commands::clean::clean(all)?,
    }

    Ok(())
}