1pub mod scaffolding;
2pub mod database;
3pub mod monitoring;
4pub mod builder;
5pub mod utils;
6pub mod packages;
7pub use scaffolding::*;
8pub use database::*;
9pub use monitoring::*;
10pub use builder::*;
11pub use utils::*;
12
13use std::env;
14use rustbasic_core::dotenvy::dotenv;
15use rustbasic_core::colored::*;
16use std::future::Future;
17use std::pin::Pin;
18
19pub type AsyncHook = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;
20
21pub async fn run_cli<F, G>(migrate_fn: F, seed_fn: G)
22where
23 F: Fn(String) -> Pin<Box<dyn Future<Output = Result<(), String>>>>,
24 G: Fn() -> Pin<Box<dyn Future<Output = ()>>>
25{
26 let args: Vec<String> = env::args().collect();
27
28 if args.len() < 2 {
29 print_help();
30 return;
31 }
32
33 let command = &args[1];
34
35 if command != "new" {
37 let _ = dotenv();
38 ensure_session().await;
39 }
40
41 match command.as_str() {
42 "migrate" | "migrate:refresh" | "migrate:back" | "migrate:rollback" => {
43 match migrate_fn(command.clone()).await {
44 Ok(_) => println!("\n{} Operasi '{}' berhasil.", "â
".green(), command),
45 Err(e) => eprintln!("\n{} Gagal: {}", "â".red(), e),
46 }
47 }
48 "db:seed" => {
49 println!("{}", "đą Menjalankan seeder database...".cyan());
50 seed_fn().await;
51 println!("\n{} Database seeding berhasil.", "â
".green());
52 }
53 _ => {
54 }
57 }
58}
59
60pub fn print_help() {
61 println!("Gunakan 'rustbasic' untuk melihat opsi perintah.");
62}
63
64pub async fn handle<M: rustbasic_core::MigratorTrait + Send + Sync + 'static>(args: &[String]) -> bool {
66 if args.len() < 2 {
67 return false;
68 }
69
70 let command = args[1].as_str();
71
72 let is_migration_cmd = command.starts_with("migrate") || command == "db:seed";
74 let is_storage_cmd = command == "storage:link";
75
76 if !is_migration_cmd && !is_storage_cmd {
77 return false;
78 }
79
80 ensure_session().await;
81
82 println!("{} {}", "đ ī¸ RustBasic Local CLI - Command:".magenta().bold(), command.yellow());
83
84 if is_storage_cmd {
85 handle_storage_link();
86 return true;
87 }
88
89 let db = crate::database::connect().await;
91
92 match command {
93 "migrate" => {
94 println!("đ {}", "Menjalankan migrasi database...".cyan());
95 if let Err(e) = M::up(&db, None).await {
96 println!("â {} {}", "Gagal menjalankan migrasi:".red().bold(), e);
97 } else {
98 println!("â
{}", "Migrasi selesai!".green().bold());
99 }
100 }
101 "migrate:refresh" => {
102 println!("đ {}", "Mereset dan menjalankan ulang migrasi...".cyan());
103 if let Err(e) = M::fresh(&db).await {
104 println!("â {} {}", "Gagal refresh migrasi:".red().bold(), e);
105 } else {
106 println!("â
{}", "Database berhasil di-refresh!".green().bold());
107 }
108 }
109 "migrate:back" | "migrate:rollback" => {
110 println!("âŦ
ī¸ {}", "Rollback migrasi terakhir...".cyan());
111 if let Err(e) = M::down(&db, None).await {
112 println!("â {} {}", "Gagal rollback:".red().bold(), e);
113 } else {
114 println!("â
{}", "Rollback berhasil!".green().bold());
115 }
116 }
117 "db:seed" => {
118 println!("đą {}", "Fitur db:seed membutuhkan implementasi lokal.".yellow());
119 }
120 _ => return false,
121 }
122
123 true
124}
125
126fn handle_storage_link() {
128 let target = "public/storage";
129 let source = "storage/app/public";
130
131 if let Err(e) = std::fs::create_dir_all(source) {
133 println!("â {} {}", "Gagal membuat direktori storage:".red().bold(), e);
134 return;
135 }
136
137 let path = std::path::Path::new(target);
139 if path.exists() || path.is_symlink() {
140 println!("âšī¸ {}", "Link 'public/storage' sudah ada atau berupa file/folder lain.".yellow());
141 return;
142 }
143
144 println!("đ {}", "Membuat symbolic link...".cyan());
146
147 #[cfg(unix)]
148 {
149 use std::os::unix::fs::symlink;
150 if let Err(e) = symlink("../storage/app/public", target) {
152 println!("â {} {}", "Gagal membuat symlink:".red().bold(), e);
153 } else {
154 println!("â
{} [public/storage -> storage/app/public]", "Link storage berhasil dibuat!".green().bold());
155 }
156 }
157
158 #[cfg(windows)]
159 {
160 use std::os::windows::fs::symlink_dir;
161 if let Err(e) = symlink_dir("../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}