oxidite-cli 2.0.2

CLI tool for the Oxidite v2 web framework
Documentation
use clap::{Parser, Subcommand};
use oxidite_core::{Router, Server, OxiditeRequest, OxiditeResponse, Result};
use oxidite_middleware::{ServiceBuilder, LoggerLayer};
use http_body_util::Full;
use bytes::Bytes;
mod commands;

#[derive(Parser)]
#[command(name = "oxidite")]
#[command(about = "Oxidite Framework CLI", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Start the HTTP server
    Serve {
        /// Address to bind to
        #[arg(short, long, default_value = "127.0.0.1:3000")]
        addr: String,
    },
    /// Create a new Oxidite project
    New {
        /// Project name
        name: String,
        /// Project type (api, fullstack, microservice, serverless)
        #[arg(short, long)]
        project_type: Option<String>,
    },
    /// Generate code
    Make {
        #[command(subcommand)]
        generator: Generator,
    },
    /// Database migrations
    Migrate {
        #[command(subcommand)]
        migration: MigrateCommand,
    },
    /// Database seeders
    Seed {
        #[command(subcommand)]
        seeder: SeedCommand,
    },
    /// Queue management
    Queue {
        #[command(subcommand)]
        queue: QueueCommand,
    },
    /// System health check
    Doctor,
    /// Production build
    Build {
        #[arg(short, long)]
        release: bool,
    },
    /// Start development server with hot reload
    Dev,
}

#[derive(Subcommand)]
enum Generator {
    /// Generate a model
    Model { name: String },
    /// Generate a controller
    Controller { name: String },
    /// Generate middleware
    Middleware { name: String },
}

#[derive(Subcommand)]
enum MigrateCommand {
    /// Create a new migration
    Create { name: String },
    /// Run pending migrations
    Run,
    /// Revert the last migration
    Revert,
    /// Show migration status
    Status,
}

#[derive(Subcommand)]
enum SeedCommand {
    /// Run database seeders
    Run,
    /// Create a new seeder
    Create { name: String },
}

#[derive(Subcommand)]
enum QueueCommand {
    /// Start queue worker
    Work {
        #[arg(short, long, default_value = "4")]
        workers: usize,
    },
    /// List queue statistics
    List,
    /// List dead letter queue
    Dlq,
    /// Clear all pending jobs
    Clear,
}

async fn hello(_req: OxiditeRequest) -> Result<OxiditeResponse> {
    Ok(OxiditeResponse::text("Hello, Oxidite!"))
}

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

    match cli.command {
        Commands::Serve { addr } => {
            let mut router = Router::new();
            router.get("/", hello);

            let service = ServiceBuilder::new()
                .layer(LoggerLayer)
                .service(router);

            let server = Server::new(service);
            println!("🚀 Server running on http://{}", addr);
            server.listen(addr.parse().unwrap()).await
        }
        Commands::New { name, project_type } => {
            commands::create_project(&name, project_type)
                .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
            Ok(())
        }
        Commands::Make { generator } => {
            match generator {
                Generator::Model { name } => {
                    commands::make::make_model(&name)
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                Generator::Controller { name } => {
                    commands::make::make_controller(&name)
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                Generator::Middleware { name } => {
                    commands::make::make_middleware(&name)
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
            }
            Ok(())
        }
        Commands::Migrate { migration } => {
            match migration {
                MigrateCommand::Create { name } => {
                    commands::migrate::create_migration(&name)
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                MigrateCommand::Run => {
                    commands::migrate::run_migrations()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                MigrateCommand::Revert => {
                    commands::migrate::revert_migration()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                MigrateCommand::Status => {
                    commands::migrate::migration_status()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
            }
            Ok(())
        }
        Commands::Seed { seeder } => {
            match seeder {
                SeedCommand::Run => {
                    commands::seed::run_seeders()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                SeedCommand::Create { name } => {
                    commands::seed::create_seeder(&name)
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
            }
            Ok(())
        }
        Commands::Queue { queue } => {
            match queue {
                QueueCommand::Work { workers } => {
                    commands::queue::queue_work(workers)
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                QueueCommand::List => {
                    commands::queue::queue_list()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                QueueCommand::Dlq => {
                    commands::queue::queue_dlq()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
                QueueCommand::Clear => {
                    commands::queue::queue_clear()
                        .await
                        .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
                }
            }
            Ok(())
        }
        Commands::Doctor => {
            commands::doctor::run_doctor()
                .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
            Ok(())
        }
        Commands::Build { release } => {
            println!("🔨 Building Oxidite project...");
            let mut cmd = std::process::Command::new("cargo");
            cmd.arg("build");
            if release {
                cmd.arg("--release");
                println!("📦 Building in release mode");
            }
            let status = cmd.status()
                .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
            if status.success() {
                println!("✅ Build completed successfully");
            } else {
                return Err(oxidite_core::Error::InternalServerError("Build failed".to_string()));
            }
            Ok(())
        }
        Commands::Dev => {
            commands::dev::start_dev_server()
                .map_err(|e| oxidite_core::Error::InternalServerError(e.to_string()))?;
            Ok(())
        }
    }
}