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 }
38
39 match command.as_str() {
40 "migrate" | "migrate:refresh" | "migrate:back" | "migrate:rollback" => {
41 match migrate_fn(command.clone()).await {
42 Ok(_) => println!("\n{} Operasi '{}' berhasil.", "ā
".green(), command),
43 Err(e) => eprintln!("\n{} Gagal: {}", "ā".red(), e),
44 }
45 }
46 "db:seed" => {
47 println!("{}", "š± Menjalankan seeder database...".cyan());
48 seed_fn().await;
49 println!("\n{} Database seeding berhasil.", "ā
".green());
50 }
51 _ => {
52 }
55 }
56}
57
58pub fn print_help() {
59 println!("\n{}", "š ļø RustBasic CLI".magenta().bold());
60 println!("{}", "=================".magenta());
61 println!("{}", "Penggunaan:".bold());
62 println!(" {} {} <Nama> {}", "rustbasic".blue(), "new".green(), "Membuat project RustBasic baru".dimmed());
63 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:controller".green(), "Membuat controller baru".dimmed());
64 println!(" {} {} <Nama> [-m] {}", "rustbasic".blue(), "make:model".green(), "Membuat model & migration".dimmed());
65 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:migration".green(), "Membuat file migrasi (Create)".dimmed());
66 println!(" {} {} <Kolom> <Tabel> {}", "rustbasic".blue(), "make:migration:add".green(), "Membuat file migrasi (Add Column)".dimmed());
67 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:middleware".green(), "Membuat middleware baru".dimmed());
68 println!(" {} {} <Nama> {}", "rustbasic".blue(), "make:seeder".green(), "Membuat seeder baru".dimmed());
69 println!(" {} {} {}", "rustbasic".blue(), "migrate".green(), "Menjalankan migrasi database".dimmed());
70 println!(" {} {} {}", "rustbasic".blue(), "storage:link".green(), "Menghubungkan public/storage ke storage/app/public".dimmed());
71 println!(" {} {} {}", "rustbasic".blue(), "serve".green(), "Menjalankan server (Auto-Reload)".dimmed());
72 println!(" {} {} {}", "rustbasic".blue(), "version".green(), "Menampilkan versi CLI".dimmed());
73 println!("\nš” Gunakan 'rustbasic version' untuk informasi lebih lanjut.");
74}
75
76pub async fn handle<M: sea_orm_migration::MigratorTrait>(cfg: &rustbasic_core::Config, args: &[String]) -> bool {
78 if args.len() < 2 {
79 return false;
80 }
81
82 let command = args[1].as_str();
83
84 let is_migration_cmd = command.starts_with("migrate") || command == "db:seed";
86 let is_storage_cmd = command == "storage:link";
87
88 if !is_migration_cmd && !is_storage_cmd {
89 return false;
90 }
91
92 println!("{} {}", "š ļø RustBasic Local CLI - Command:".magenta().bold(), command.yellow());
93
94 if is_storage_cmd {
95 handle_storage_link();
96 return true;
97 }
98
99 let db = rustbasic_core::database::connect(cfg).await;
101
102 match command {
103 "migrate" => {
104 println!("š {}", "Menjalankan migrasi database...".cyan());
105 if let Err(e) = M::up(&db, None).await {
106 println!("ā {} {}", "Gagal menjalankan migrasi:".red().bold(), e);
107 } else {
108 println!("ā
{}", "Migrasi selesai!".green().bold());
109 }
110 }
111 "migrate:refresh" => {
112 println!("š {}", "Mereset dan menjalankan ulang migrasi...".cyan());
113 if let Err(e) = M::fresh(&db).await {
114 println!("ā {} {}", "Gagal refresh migrasi:".red().bold(), e);
115 } else {
116 println!("ā
{}", "Database berhasil di-refresh!".green().bold());
117 }
118 }
119 "migrate:back" | "migrate:rollback" => {
120 println!("ā¬
ļø {}", "Rollback migrasi terakhir...".cyan());
121 if let Err(e) = M::down(&db, None).await {
122 println!("ā {} {}", "Gagal rollback:".red().bold(), e);
123 } else {
124 println!("ā
{}", "Rollback berhasil!".green().bold());
125 }
126 }
127 "db:seed" => {
128 println!("š± {}", "Fitur db:seed membutuhkan implementasi lokal.".yellow());
129 }
130 _ => return false,
131 }
132
133 true
134}
135
136fn handle_storage_link() {
138 let target = "public/storage";
139 let source = "storage/app/public";
140
141 if let Err(e) = std::fs::create_dir_all(source) {
143 println!("ā {} {}", "Gagal membuat direktori storage:".red().bold(), e);
144 return;
145 }
146
147 let path = std::path::Path::new(target);
149 if path.exists() || path.is_symlink() {
150 println!("ā¹ļø {}", "Link 'public/storage' sudah ada atau berupa file/folder lain.".yellow());
151 return;
152 }
153
154 println!("š {}", "Membuat symbolic link...".cyan());
156
157 #[cfg(unix)]
158 {
159 use std::os::unix::fs::symlink;
160 if let Err(e) = symlink("../storage/app/public", target) {
162 println!("ā {} {}", "Gagal membuat symlink:".red().bold(), e);
163 } else {
164 println!("ā
{} [public/storage -> storage/app/public]", "Link storage berhasil dibuat!".green().bold());
165 }
166 }
167
168 #[cfg(windows)]
169 {
170 use std::os::windows::fs::symlink_dir;
171 if let Err(e) = symlink_dir("../storage/app/public", target) {
172 println!("ā {} {}", "Gagal membuat symlink:".red().bold(), e);
173 } else {
174 println!("ā
{} [public/storage -> storage/app/public]", "Link storage berhasil dibuat!".green().bold());
175 }
176 }
177}