1pub mod scaffolding;
2pub mod database;
3pub mod monitoring;
4pub mod builder;
5pub mod utils;
6pub mod packages;
7pub mod publisher;
8pub use scaffolding::*;
9pub use database::*;
10pub use monitoring::*;
11pub use builder::*;
12pub use utils::*;
13
14use std::env;
15use rustbasic_core::dotenvy::dotenv;
16use rustbasic_core::colored::*;
17use std::future::Future;
18use std::pin::Pin;
19
20pub type AsyncHook = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
21
22pub async fn run_cli<F, G>(migrate_fn: F, seed_fn: G)
23where
24 F: Fn(String) -> Pin<Box<dyn Future<Output = Result<(), String>>>>,
25 G: Fn() -> Pin<Box<dyn Future<Output = ()>>>
26{
27 let args: Vec<String> = env::args().collect();
28
29 if args.len() < 2 {
30 print_help();
31 return;
32 }
33
34 let command = &args[1];
35
36 if command != "new" {
38 let _ = dotenv();
39 ensure_session().await;
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!("Gunakan 'rustbasic' untuk melihat opsi perintah.");
63}
64
65pub async fn handle<M: rustbasic_core::MigratorTrait + Send + Sync + 'static>(args: &[String]) -> bool {
67 if args.len() < 2 {
68 return false;
69 }
70
71 let command = args[1].as_str();
72
73 let is_migration_cmd = command.starts_with("migrate") || command == "db:seed";
75 let is_storage_cmd = command == "storage:link";
76 let is_build_cmd = command == "build";
77 let is_server_cmd = command == "server" || command == "serve";
78
79 if is_server_cmd {
81 let run_android = args.iter().any(|arg| arg == "--android");
82 let run_desktop = args.iter().any(|arg| arg == "--desktop");
83 if run_android || run_desktop {
84 builder::run_native(run_android, run_desktop);
85 return true;
86 }
87 return false; }
89
90 if !is_migration_cmd && !is_storage_cmd && !is_build_cmd {
91 return false;
92 }
93
94 println!("đ ī¸ RustBasic Local CLI - Command: {}", command);
96
97 if is_build_cmd {
98 builder::build_interactive(args);
99 return true;
100 }
101
102 if is_storage_cmd {
103 handle_storage_link();
104 return true;
105 }
106
107 ensure_session().await;
108
109 let db = crate::database::connect().await;
111
112 match command {
113 "migrate" => {
114 println!("đ {}", "Menjalankan migrasi database...".cyan());
115 if let Err(e) = M::up(&db, None).await {
116 println!("â {} {}", "Gagal menjalankan migrasi:".red().bold(), e);
117 } else {
118 println!("â
{}", "Migrasi selesai!".green().bold());
119 }
120 }
121 "migrate:refresh" => {
122 println!("đ {}", "Mereset dan menjalankan ulang migrasi...".cyan());
123 if let Err(e) = M::fresh(&db).await {
124 println!("â {} {}", "Gagal refresh migrasi:".red().bold(), e);
125 } else {
126 println!("â
{}", "Database berhasil di-refresh!".green().bold());
127 }
128 }
129 "migrate:back" | "migrate:rollback" => {
130 println!("âŦ
ī¸ {}", "Rollback migrasi terakhir...".cyan());
131 if let Err(e) = M::down(&db, None).await {
132 println!("â {} {}", "Gagal rollback:".red().bold(), e);
133 } else {
134 println!("â
{}", "Rollback berhasil!".green().bold());
135 }
136 }
137 "db:seed" => {
138 println!("đą {}", "Fitur db:seed membutuhkan implementasi lokal.".yellow());
139 }
140 _ => return false,
141 }
142
143 true
144}
145
146fn handle_storage_link() {
148 let target = "public/storage";
149 let source = "storage/app/public";
150
151 if let Err(e) = std::fs::create_dir_all(source) {
153 println!("â {} {}", "Gagal membuat direktori storage:".red().bold(), e);
154 return;
155 }
156
157 let path = std::path::Path::new(target);
159 if path.exists() || path.is_symlink() {
160 println!("âšī¸ {}", "Link 'public/storage' sudah ada atau berupa file/folder lain.".yellow());
161 return;
162 }
163
164 println!("đ {}", "Membuat symbolic link...".cyan());
166
167 #[cfg(unix)]
168 {
169 use std::os::unix::fs::symlink;
170 if let Err(e) = symlink("../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
178 #[cfg(windows)]
179 {
180 use std::os::windows::fs::symlink_dir;
181 if let Err(e) = symlink_dir("../storage/app/public", target) {
182 println!("â {} {}", "Gagal membuat symlink:".red().bold(), e);
183 } else {
184 println!("â
{} [public/storage -> storage/app/public]", "Link storage berhasil dibuat!".green().bold());
185 }
186 }
187}