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() -> Pin<Box<dyn Future<Output = ()>>>,
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" => {
78 migrate_fn().await;
79 }
80 "migrate:refresh" => {
81 println!("{}", "⚠️ Fitur migrate:refresh menggunakan hook aplikasi.".dimmed());
85 migrate_fn().await;
86 }
87 "migrate:back" | "migrate:rollback" => {
88 println!("{}", "⚠️ Fitur rollback menggunakan hook aplikasi.".dimmed());
89 migrate_fn().await;
90 }
91 "route:list" => {
92 monitoring::list_routes();
93 }
94 "build" => {
95 builder::build_project();
96 }
97 "cache:clear" => {
98 database::clear_cache().await;
99 }
100 "check:update" => {
101 monitoring::check_updates();
102 }
103 "check:security" => {
104 monitoring::check_security();
105 }
106 "key:generate" => {
107 database::generate_app_key();
108 }
109 "make:auth" | "auth" => {
110 if args.len() >= 3 && args[2] == "back" {
111 auth::remove_auth().await;
112 } else {
113 auth::make_auth().await;
114 }
115 }
116 "db:seed" => {
117 seed_fn().await;
118 }
119 "make:seeder" => {
120 if args.len() < 3 {
121 println!("{}", "❌ Error: Nama seeder tidak ditentukan.".red().bold());
122 return;
123 }
124 scaffolding::make_seeder(&args[2]);
125 }
126 "auth:back" => {
127 auth::remove_auth().await;
128 }
129
130 _ => {
131 println!("{} {}", "❌ Error: Perintah tidak dikenal:".red().bold(), command.yellow());
132 print_help();
133 }
134 }
135}
136
137fn print_help() {
138 println!("\n{}", "🛠️ RustBasic CLI".magenta().bold());
139 println!("{}", "=================".magenta());
140 println!("{}", "Penggunaan:".bold());
141 println!(" {} {} <Nama> [-m] {}", "cargo rustbasic".blue(), "make:model".green(), "Membuat model Sea-ORM (dan migration Rust)".dimmed());
142 println!(" {} {} <Nama> {}", "cargo rustbasic".blue(), "make:migration".green(), "Membuat file migration Rust".dimmed());
143 println!(" {} {} <Nama> {}", "cargo rustbasic".blue(), "make:controller".green(), "Membuat controller Axum".dimmed());
144 println!(" {} {} <Nama> {}", "cargo rustbasic".blue(), "make:middleware".green(), "Membuat middleware Axum".dimmed());
145 println!(" {} {} {}", "cargo rustbasic".blue(), "migrate".green(), "Menjalankan migrasi database (Sea-ORM)".dimmed());
146 println!(" {} {} {}", "cargo rustbasic".blue(), "migrate:refresh".green(), "Rollback semua dan jalankan kembali migrasi".dimmed());
147 println!(" {} {} {}", "cargo rustbasic".blue(), "migrate:back".green(), "Membatalkan migrasi terakhir (Rollback)".dimmed());
148 println!(" {} {} {}", "cargo rustbasic".blue(), "route:list".green(), "Menampilkan daftar route".dimmed());
149 println!(" {} {} {}", "cargo rustbasic".blue(), "build".green(), "Membangun project dengan pilihan".dimmed());
150 println!(" {} {} {}", "cargo rustbasic".blue(), "check:update".green(), "Cek versi terbaru paket (dependencies)".dimmed());
151 println!(" {} {} {}", "cargo rustbasic".blue(), "check:security".green(), "Audit keamanan aplikasi".dimmed());
152 println!(" {} {} {}", "cargo rustbasic".blue(), "cache:clear".green(), "Membersihkan logs dan database sessions".dimmed());
153 println!(" {} {} {}", "cargo rustbasic".blue(), "key:generate".green(), "Membuat APP_KEY baru di file .env".dimmed());
154 println!(" {} {} {}", "cargo rustbasic".blue(), "make:auth".green(), "Scaffold autentikasi (Login/Register)".dimmed());
155 println!(" {} {} {}", "cargo rustbasic".blue(), "auth:back".red(), "Menghapus semua scaffolding autentikasi".dimmed());
156 println!(" {} {} {}", "cargo rustbasic".blue(), "db:seed".green(), "Menjalankan seeder database".dimmed());
157 println!(" {} {} <Nama> {}", "cargo rustbasic".blue(), "make:seeder".green(), "Membuat file seeder baru".dimmed());
158 println!(" {} {} {}", "cargo rustbasic".blue(), "serve".green(), "Menjalankan server dengan Auto-Reload".dimmed());
159 println!(" {} {}", "cargo serve".blue(), "(Shortcut) Lebih cepat untuk menjalankan server".dimmed());
160
161 println!();
162}