1pub mod scaffolding;
2pub mod database;
3pub mod monitoring;
4pub mod builder;
5pub mod utils;
6pub use scaffolding::*;
7pub use database::*;
8pub use monitoring::*;
9pub use builder::*;
10pub use utils::*;
11
12use std::env;
13use dotenvy::dotenv;
14use colored::*;
15use std::future::Future;
16use std::pin::Pin;
17
18pub type AsyncHook = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
19
20pub async fn run_cli<F, G>(migrate_fn: F, seed_fn: G)
21where
22 F: Fn(String) -> Pin<Box<dyn Future<Output = Result<(), String>>>>,
23 G: Fn() -> Pin<Box<dyn Future<Output = ()>>>
24{
25 let args: Vec<String> = env::args().collect();
26
27 if args.len() < 2 {
28 print_help();
29 return;
30 }
31
32 let command = &args[1];
33
34 if command != "new" {
36 let _ = dotenv();
37 ensure_session().await;
38 }
39
40 match command.as_str() {
41 "migrate" | "migrate:refresh" | "migrate:back" | "migrate:rollback" => {
42 match migrate_fn(command.clone()).await {
43 Ok(_) => println!("\n{} Operasi '{}' berhasil.", "ā
".green(), command),
44 Err(e) => eprintln!("\n{} Gagal: {}", "ā".red(), e),
45 }
46 }
47 "db:seed" => {
48 println!("{}", "š± Menjalankan seeder database...".cyan());
49 seed_fn().await;
50 println!("\n{} Database seeding berhasil.", "ā
".green());
51 }
52 _ => {
53 }
56 }
57}
58
59pub fn print_help() {
60 println!("\n{}", "š ļø RustBasic CLI".magenta().bold());
61 println!("{}", "=================".magenta());
62 println!("{}", "Penggunaan:".bold());
63 println!(" {} {} <Nama> {}", "rustbasic".blue(), "new".green(), "Membuat project RustBasic baru".dimmed());
64 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:controller".green(), "Membuat controller baru".dimmed());
65 println!(" {} {} <Nama> [-m] {}", "rustbasic".blue(), "make:model".green(), "Membuat model & migration".dimmed());
66 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:migration".green(), "Membuat file migrasi (Create)".dimmed());
67 println!(" {} {} <Kolom> <Tabel> {}", "rustbasic".blue(), "make:migration:add".green(), "Membuat file migrasi (Add Column)".dimmed());
68 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:middleware".green(), "Membuat middleware baru".dimmed());
69 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:seeder".green(), "Membuat seeder baru".dimmed());
70 println!(" {} {} {}", "rustbasic".blue(), "migrate".green(), "Menjalankan migrasi database".dimmed());
71 println!(" {} {} {}", "rustbasic".blue(), "storage:link".green(), "Menghubungkan public/storage ke storage/app/public".dimmed());
72 println!(" {} {} {}", "rustbasic".blue(), "serve".green(), "Menjalankan server (Auto-Reload)".dimmed());
73 println!(" {} {} {}", "rustbasic".blue(), "version".green(), "Menampilkan versi CLI".dimmed());
74 println!("\nš” Gunakan 'rustbasic version' untuk informasi lebih lanjut.");
75}
76
77pub async fn handle<M: sea_orm_migration::MigratorTrait>(cfg: &rustbasic_core::Config, args: &[String]) -> bool {
79 if args.len() < 2 {
80 return false;
81 }
82
83 let command = args[1].as_str();
84
85 let is_migration_cmd = command.starts_with("migrate") || command == "db:seed";
87 let is_storage_cmd = command == "storage:link";
88
89 if !is_migration_cmd && !is_storage_cmd {
90 return false;
91 }
92
93 ensure_session().await;
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}