diff --git a/cli/cli/src/commands/run.rs b/cli/cli/src/commands/run.rs index 965fcad20..520f30a69 100644 --- a/cli/cli/src/commands/run.rs +++ b/cli/cli/src/commands/run.rs @@ -4,8 +4,8 @@ use std::process::{Command, Stdio}; use crate::error::BusterError; use indicatif::{ProgressBar, ProgressStyle}; use std::time::Duration; -use tempfile::TempDir; use rust_embed::RustEmbed; +use dirs; #[derive(RustEmbed)] #[folder = "../../"] @@ -18,16 +18,24 @@ use rust_embed::RustEmbed; #[exclude = "supabase/docker-compose.override.yml"] struct StaticAssets; -async fn setup_temporary_compose_environment() -> Result { - let temp_dir = TempDir::new().map_err(|e| { - BusterError::CommandError(format!("Failed to create temporary directory: {}", e)) +async fn setup_persistent_app_environment() -> Result { + let home_dir = dirs::home_dir() + .ok_or_else(|| BusterError::CommandError("Failed to get home directory. Cannot set up persistent app path.".to_string()))?; + let app_base_dir = home_dir.join(".buster"); + + fs::create_dir_all(&app_base_dir).map_err(|e| { + BusterError::CommandError(format!( + "Failed to create persistent app directory at {}: {}", + app_base_dir.display(), + e + )) })?; - let base_path = temp_dir.path(); for filename_cow in StaticAssets::iter() { let filename = filename_cow.as_ref(); - let asset = StaticAssets::get(filename).ok_or_else(|| BusterError::CommandError(format!("Failed to get embedded asset: {}", filename)))?; - let target_file_path = base_path.join(filename); + let asset = StaticAssets::get(filename) + .ok_or_else(|| BusterError::CommandError(format!("Failed to get embedded asset: {}", filename)))?; + let target_file_path = app_base_dir.join(filename); if let Some(parent) = target_file_path.parent() { fs::create_dir_all(parent).map_err(|e| { @@ -49,12 +57,12 @@ async fn setup_temporary_compose_environment() -> Result { })?; } - let supabase_volumes_path = base_path.join("supabase/volumes"); - fs::create_dir_all(supabase_volumes_path.join("functions")).map_err(|e| BusterError::CommandError(format!("Failed to create supabase/volumes/functions: {}", e)))?; + let supabase_volumes_functions_path = app_base_dir.join("supabase/volumes/functions"); + fs::create_dir_all(supabase_volumes_functions_path).map_err(|e| BusterError::CommandError(format!("Failed to create supabase/volumes/functions in persistent app dir: {}", e)))?; let local_dotenv_path = PathBuf::from("/Users/dallin/buster/buster/.env"); if local_dotenv_path.exists() { - let target_dotenv_path = base_path.join(".env"); + let target_dotenv_path = app_base_dir.join(".env"); fs::copy(&local_dotenv_path, &target_dotenv_path).map_err(|e| { BusterError::CommandError(format!( "Failed to copy local .env from {} to {}: {}", @@ -67,20 +75,19 @@ async fn setup_temporary_compose_environment() -> Result { println!("Warning: Specified .env file not found at {}. Services might not configure correctly if .env is required by docker-compose.yml.", local_dotenv_path.display()); } - Ok(temp_dir) + Ok(app_base_dir) } async fn run_docker_compose_command(args: &[&str], operation_name: &str) -> Result<(), BusterError> { - let temp_dir = setup_temporary_compose_environment().await?; - let temp_dir_path = temp_dir.path(); + let persistent_app_dir = setup_persistent_app_environment().await?; - let persistent_project_path = PathBuf::from("/Users/dallin/buster/buster"); + let data_db_path = persistent_app_dir.join("supabase/volumes/db/data"); + fs::create_dir_all(&data_db_path) + .map_err(|e| BusterError::CommandError(format!("Failed to create persistent data directory at {}: {}", data_db_path.display(), e)))?; - let supabase_volumes_persistent_path = persistent_project_path.join("supabase/volumes"); - fs::create_dir_all(supabase_volumes_persistent_path.join("db/data")) - .map_err(|e| BusterError::CommandError(format!("Failed to create persistent supabase/volumes/db/data: {}", e)))?; - fs::create_dir_all(supabase_volumes_persistent_path.join("storage")) - .map_err(|e| BusterError::CommandError(format!("Failed to create persistent supabase/volumes/storage: {}", e)))?; + let data_storage_path = persistent_app_dir.join("supabase/volumes/storage"); + fs::create_dir_all(&data_storage_path) + .map_err(|e| BusterError::CommandError(format!("Failed to create persistent data directory at {}: {}", data_storage_path.display(), e)))?; let pb = ProgressBar::new_spinner(); pb.enable_steady_tick(Duration::from_millis(120)); @@ -97,43 +104,36 @@ async fn run_docker_compose_command(args: &[&str], operation_name: &str) -> Resu } let mut cmd = Command::new("docker"); + cmd.current_dir(&persistent_app_dir); cmd.arg("compose") .arg("-p") .arg("buster") - .arg("--project-directory") - .arg(persistent_project_path) - .arg("-f") - .arg(temp_dir_path.join("docker-compose.yml")) - .args(args) - .stdout(Stdio::null()) - .stderr(Stdio::null()); + .arg("-f") + .arg("docker-compose.yml") + .args(args); - let status_result = cmd.status(); + let output = cmd.output().map_err(|e| { + BusterError::CommandError(format!("Failed to execute docker compose {}: {}", args.join(" "), e)) + })?; - match status_result { - Ok(status) => { - if status.success() { - pb.finish_with_message(format!( - "Buster services {} successfully.", - operation_name.to_lowercase() - )); - Ok(()) - } else { - let err_msg = format!( - "docker compose {} failed (status: {}). Check Docker logs for details (context: {}).", - args.join(" "), - status, - temp_dir_path.display() - ); - pb.abandon_with_message(format!("Error: {}", err_msg)); - Err(BusterError::CommandError(err_msg)) - } - } - Err(e) => { - let err_msg = format!("Failed to execute docker compose {}: {}", args.join(" "), e); - pb.abandon_with_message(format!("Error: {}", err_msg)); - Err(BusterError::CommandError(err_msg)) - } + if output.status.success() { + pb.finish_with_message(format!( + "Buster services {} successfully.", + operation_name.to_lowercase() + )); + Ok(()) + } else { + let err_msg = format!( + "docker compose {} failed (status: {}). Logs:\nWorking directory: {}\nStdout:\n{}\nStderr:\n{}", + args.join(" "), + output.status, + persistent_app_dir.display(), + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + pb.abandon_with_message(format!("Error: docker compose {} failed. See console for details.", args.join(" "))); + println!("\nDocker Compose Error Details:\n{}", err_msg); + Err(BusterError::CommandError(err_msg)) } }