1pub mod scaffolding;
2pub mod database;
3pub mod monitoring;
4pub mod builder;
5pub mod utils;
6pub mod auth;
7
8pub use scaffolding::*;
9pub use database::*;
10pub use monitoring::*;
11pub use builder::*;
12pub use utils::*;
13pub use auth::*;
14
15use std::env;
16use dotenvy::dotenv;
17use colored::*;
18use std::future::Future;
19use std::pin::Pin;
20
21pub type AsyncHook = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
22
23pub async fn run_cli<F, G>(migrate_fn: F, seed_fn: G)
24where
25 F: Fn(String) -> Pin<Box<dyn Future<Output = Result<(), String>>>>,
26 G: Fn() -> Pin<Box<dyn Future<Output = ()>>>
27{
28 let args: Vec<String> = env::args().collect();
29
30 if args.len() < 2 {
31 print_help();
32 return;
33 }
34
35 let command = &args[1];
36
37 if command != "new" {
39 let _ = dotenv();
40 }
41
42 match command.as_str() {
43 "migrate" | "migrate:refresh" | "migrate:back" | "migrate:rollback" => {
44 match migrate_fn(command.clone()).await {
45 Ok(_) => println!("\n{} Operasi '{}' berhasil.", "ā
".green(), command),
46 Err(e) => eprintln!("\n{} Gagal: {}", "ā".red(), e),
47 }
48 }
49 "db:seed" => {
50 println!("{}", "š± Menjalankan seeder database...".cyan());
51 seed_fn().await;
52 println!("\n{} Database seeding berhasil.", "ā
".green());
53 }
54 _ => {
55 }
58 }
59}
60
61pub fn print_help() {
62 println!("\n{}", "š ļø RustBasic CLI".magenta().bold());
63 println!("{}", "=================".magenta());
64 println!("{}", "Penggunaan:".bold());
65 println!(" {} {} <Nama> {}", "rustbasic".blue(), "new".green(), "Membuat project RustBasic baru".dimmed());
66 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:controller".green(), "Membuat controller baru".dimmed());
67 println!(" {} {} <Nama> [-m] {}", "rustbasic".blue(), "make:model".green(), "Membuat model & migration".dimmed());
68 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:migration".green(), "Membuat file migrasi (Create)".dimmed());
69 println!(" {} {} <Kolom> <Tabel> {}", "rustbasic".blue(), "make:migration:add".green(), "Membuat file migrasi (Add Column)".dimmed());
70 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:middleware".green(), "Membuat middleware baru".dimmed());
71 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:seeder".green(), "Membuat seeder baru".dimmed());
72 println!(" {} {} {}", "rustbasic".blue(), "migrate".green(), "Menjalankan migrasi database".dimmed());
73 println!(" {} {} {}", "rustbasic".blue(), "storage:link".green(), "Menghubungkan public/storage ke storage/app/public".dimmed());
74 println!(" {} {} {}", "rustbasic".blue(), "serve".green(), "Menjalankan server (Auto-Reload)".dimmed());
75 println!(" {} {} {}", "rustbasic".blue(), "version".green(), "Menampilkan versi CLI".dimmed());
76 println!("\nš” Gunakan 'rustbasic version' untuk informasi lebih lanjut.");
77}
78
79pub async fn handle<M: sea_orm_migration::MigratorTrait>(cfg: &rustbasic_core::Config, args: &[String]) -> bool {
81 if args.len() < 2 {
82 return false;
83 }
84
85 let command = args[1].as_str();
86
87 let is_migration_cmd = command.starts_with("migrate") || command == "db:seed";
89 let is_storage_cmd = command == "storage:link";
90
91 if !is_migration_cmd && !is_storage_cmd {
92 return false;
93 }
94
95 println!("{} {}", "š ļø RustBasic Local CLI - Command:".magenta().bold(), command.yellow());
96
97 if is_storage_cmd {
98 handle_storage_link();
99 return true;
100 }
101
102 let db = rustbasic_core::database::connect(cfg).await;
104
105 match command {
106 "migrate" => {
107 println!("š {}", "Menjalankan migrasi database...".cyan());
108 if let Err(e) = M::up(&db, None).await {
109 println!("ā {} {}", "Gagal menjalankan migrasi:".red().bold(), e);
110 } else {
111 println!("ā
{}", "Migrasi selesai!".green().bold());
112 }
113 }
114 "migrate:refresh" => {
115 println!("š {}", "Mereset dan menjalankan ulang migrasi...".cyan());
116 if let Err(e) = M::fresh(&db).await {
117 println!("ā {} {}", "Gagal refresh migrasi:".red().bold(), e);
118 } else {
119 println!("ā
{}", "Database berhasil di-refresh!".green().bold());
120 }
121 }
122 "migrate:back" | "migrate:rollback" => {
123 println!("ā¬
ļø {}", "Rollback migrasi terakhir...".cyan());
124 if let Err(e) = M::down(&db, None).await {
125 println!("ā {} {}", "Gagal rollback:".red().bold(), e);
126 } else {
127 println!("ā
{}", "Rollback berhasil!".green().bold());
128 }
129 }
130 "db:seed" => {
131 println!("š± {}", "Fitur db:seed membutuhkan implementasi lokal.".yellow());
132 }
133 _ => return false,
134 }
135
136 true
137}
138
139fn handle_storage_link() {
141 let target = "public/storage";
142 let source = "storage/app/public";
143
144 if let Err(e) = std::fs::create_dir_all(source) {
146 println!("ā {} {}", "Gagal membuat direktori storage:".red().bold(), e);
147 return;
148 }
149
150 let path = std::path::Path::new(target);
152 if path.exists() || path.is_symlink() {
153 println!("ā¹ļø {}", "Link 'public/storage' sudah ada atau berupa file/folder lain.".yellow());
154 return;
155 }
156
157 println!("š {}", "Membuat symbolic link...".cyan());
159
160 #[cfg(unix)]
161 {
162 use std::os::unix::fs::symlink;
163 if let Err(e) = symlink("../storage/app/public", target) {
165 println!("ā {} {}", "Gagal membuat symlink:".red().bold(), e);
166 } else {
167 println!("ā
{} [public/storage -> storage/app/public]", "Link storage berhasil dibuat!".green().bold());
168 }
169 }
170
171 #[cfg(windows)]
172 {
173 use std::os::windows::fs::symlink_dir;
174 if let Err(e) = symlink_dir("../storage/app/public", target) {
175 println!("ā {} {}", "Gagal membuat symlink:".red().bold(), e);
176 } else {
177 println!("ā
{} [public/storage -> storage/app/public]", "Link storage berhasil dibuat!".green().bold());
178 }
179 }
180}