Skip to main content

rustbasic_core/cli/
mod.rs

1use std::env;
2use dotenvy::dotenv;
3use colored::*;
4use std::future::Future;
5use std::pin::Pin;
6
7pub mod scaffolding;
8pub mod database;
9pub mod monitoring;
10pub mod builder;
11pub mod utils;
12pub mod auth;
13
14pub type AsyncHook = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
15
16pub async fn run_cli<F, G>(migrate_fn: F, seed_fn: G) 
17where 
18    F: Fn(String) -> Pin<Box<dyn Future<Output = Result<(), String>>>>,
19    G: Fn() -> Pin<Box<dyn Future<Output = ()>>>
20{
21    dotenv().expect("āŒ Error: File .env tidak ditemukan! Silakan salin .env.example menjadi .env sebelum menggunakan CLI.");
22    let args: Vec<String> = env::args().collect();
23
24    if args.len() < 2 {
25        print_help();
26        return;
27    }
28
29    let command = &args[1];
30
31    match command.as_str() {
32         "serve" => {
33            println!("\n   {} {}", "šŸš€".bold(), "Menjalankan server RustBasic dengan Auto-Reload...".magenta().bold());
34            let status = std::process::Command::new("cargo")
35                .args(["watch", "-c", "-q", "--no-ignore", "-i", "target", "-w", "src", "-w", ".env", "-w", "src/resources", "-x", "run"])
36                .status()
37                .expect("āŒ Gagal menjalankan cargo watch. Pastikan cargo-watch sudah terinstall: cargo install cargo-watch");
38            
39            if !status.success() {
40                std::process::exit(status.code().unwrap_or(1));
41            }
42        },
43        "make:model" => {
44            if args.len() < 3 {
45                println!("{}", "āŒ Error: Nama model tidak ditentukan.".red().bold());
46                return;
47            }
48            let model_name = &args[2];
49            let with_migration = args.contains(&"-m".to_string());
50            
51            scaffolding::make_model(model_name);
52            if with_migration {
53                scaffolding::make_rust_migration(model_name);
54            }
55        }
56        "make:migration" => {
57            if args.len() < 3 {
58                println!("{}", "āŒ Error: Nama migration tidak ditentukan.".red().bold());
59                return;
60            }
61            scaffolding::make_rust_migration(&args[2]);
62        }
63        "make:controller" => {
64            if args.len() < 3 {
65                println!("{}", "āŒ Error: Nama controller tidak ditentukan.".red().bold());
66                return;
67            }
68            scaffolding::make_controller(&args[2]);
69        }
70        "make:middleware" => {
71            if args.len() < 3 {
72                println!("{}", "āŒ Error: Nama middleware tidak ditentukan.".red().bold());
73                return;
74            }
75            scaffolding::make_middleware(&args[2]);
76        }
77        "migrate" | "migrate:refresh" | "migrate:back" | "migrate:rollback" => {
78            if command == "migrate:refresh" {
79                println!("{}", "šŸ”„ Menyegarkan database (Refresh Migration)...".yellow());
80            } else if command == "migrate:back" || command == "migrate:rollback" {
81                println!("{}", "āŖ Membatalkan migrasi terakhir (Rollback 1 step)...".yellow());
82            }
83            
84            if let Err(e) = migrate_fn(command.clone()).await {
85                eprintln!("\n{} {}", "āŒ Error:".red().bold(), "Gagal menjalankan operasi database.".bold());
86                eprintln!("{} {}", "šŸ“ Detail:".yellow(), e);
87                eprintln!("\nšŸ’” {}", "Tips:".cyan().bold());
88                eprintln!("   Jika muncul error 'Migration file ... is missing', itu berarti database mencatat");
89                eprintln!("   migrasi yang sudah dijalankan, tapi file migrasinya sudah dihapus atau diubah.");
90                eprintln!("\nšŸ› ļø  {}", "Solusi:".cyan().bold());
91                eprintln!("   Hapus file database: 'rm database/rustbasic.sqlite' lalu jalankan migrasi lagi.");
92                std::process::exit(1);
93            }
94        }
95        "route:list" => {
96            monitoring::list_routes();
97        }
98        "build" => {
99            builder::build_project();
100        }
101        "cache:clear" => {
102            database::clear_cache().await;
103        }
104        "check:update" => {
105            monitoring::check_updates();
106        }
107        "check:security" => {
108            monitoring::check_security();
109        }
110        "key:generate" => {
111            database::generate_app_key();
112        }
113        "make:auth" | "auth" => {
114            if args.len() >= 3 && args[2] == "back" {
115                auth::remove_auth().await;
116            } else {
117                auth::make_auth().await;
118            }
119        }
120        "db:seed" => {
121            seed_fn().await;
122        }
123        "make:seeder" => {
124            if args.len() < 3 {
125                println!("{}", "āŒ Error: Nama seeder tidak ditentukan.".red().bold());
126                return;
127            }
128            scaffolding::make_seeder(&args[2]);
129        }
130        "auth:back" => {
131            auth::remove_auth().await;
132        }
133       
134        _ => {
135            println!("{} {}", "āŒ Error: Perintah tidak dikenal:".red().bold(), command.yellow());
136            print_help();
137        }
138    }
139}
140
141fn print_help() {
142    println!("\n{}", "šŸ› ļø  RustBasic CLI".magenta().bold());
143    println!("{}", "=================".magenta());
144    println!("{}", "Penggunaan:".bold());
145    println!("  {} {} <Nama> [-m]   {}", "cargo rustbasic".blue(), "make:model".green(), "Membuat model Sea-ORM (dan migration Rust)".dimmed());
146    println!("  {} {} <Nama>    {}", "cargo rustbasic".blue(), "make:migration".green(), "Membuat file migration Rust".dimmed());
147    println!("  {} {} <Nama>  {}", "cargo rustbasic".blue(), "make:controller".green(), "Membuat controller Axum".dimmed());
148    println!("  {} {} <Nama>  {}", "cargo rustbasic".blue(), "make:middleware".green(), "Membuat middleware Axum".dimmed());
149    println!("  {} {}                  {}", "cargo rustbasic".blue(), "migrate".green(), "Menjalankan migrasi database (Sea-ORM)".dimmed());
150    println!("  {} {}          {}", "cargo rustbasic".blue(), "migrate:refresh".green(), "Rollback semua dan jalankan kembali migrasi".dimmed());
151    println!("  {} {}             {}", "cargo rustbasic".blue(), "migrate:back".green(), "Membatalkan migrasi terakhir (Rollback)".dimmed());
152    println!("  {} {}               {}", "cargo rustbasic".blue(), "route:list".green(), "Menampilkan daftar route".dimmed());
153    println!("  {} {}                    {}", "cargo rustbasic".blue(), "build".green(), "Membangun project dengan pilihan".dimmed());
154    println!("  {} {}             {}", "cargo rustbasic".blue(), "check:update".green(), "Cek versi terbaru paket (dependencies)".dimmed());
155    println!("  {} {}           {}", "cargo rustbasic".blue(), "check:security".green(), "Audit keamanan aplikasi".dimmed());
156    println!("  {} {}               {}", "cargo rustbasic".blue(), "cache:clear".green(), "Membersihkan logs dan database sessions".dimmed());
157    println!("  {} {}             {}", "cargo rustbasic".blue(), "key:generate".green(), "Membuat APP_KEY baru di file .env".dimmed());
158    println!("  {} {}                   {}", "cargo rustbasic".blue(), "make:auth".green(), "Scaffold autentikasi (Login/Register)".dimmed());
159    println!("  {} {}                   {}", "cargo rustbasic".blue(), "auth:back".red(), "Menghapus semua scaffolding autentikasi".dimmed());
160    println!("  {} {}                  {}", "cargo rustbasic".blue(), "db:seed".green(), "Menjalankan seeder database".dimmed());
161    println!("  {} {} <Nama>    {}", "cargo rustbasic".blue(), "make:seeder".green(), "Membuat file seeder baru".dimmed());
162    println!("  {} {}                    {}", "cargo rustbasic".blue(), "serve".green(), "Menjalankan server dengan Auto-Reload".dimmed());
163    println!("  {}                       {}", "cargo serve".blue(), "(Shortcut) Lebih cepat untuk menjalankan server".dimmed());
164
165    println!();
166}