use super::islands::{generate_islands_registry, generate_vite_config, has_island_components};
use super::style;
use colored::Colorize;
use std::path::Path;
use std::process::{Command, Stdio};
fn run_bun_command(args: &[&str]) -> std::io::Result<std::process::ExitStatus> {
Command::new("bun")
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
}
pub fn build_command(release: bool) {
style::print_banner();
let mode = if release { "release" } else { "debug" };
println!("\n {}\n", format!("Building for {}...", mode).dimmed());
let client_dir = Path::new("client");
let has_client = client_dir.exists();
let has_islands = has_island_components();
let total_steps = if !has_client {
1
} else if has_islands {
4
} else {
3
};
let mut step = 1;
if has_client {
if !Path::new("node_modules").exists() {
style::print_step(step, total_steps, "Installing dependencies...");
let status = run_bun_command(&["install"]);
if status.is_err() || !status.unwrap().success() {
style::print_error("Failed to run bun install");
std::process::exit(1);
}
} else {
style::print_step(step, total_steps, "Dependencies already installed");
}
step += 1;
if has_islands {
style::print_step(step, total_steps, "Generating islands registry...");
generate_islands_registry();
step += 1;
}
generate_vite_config(has_islands);
style::print_step(step, total_steps, "Building client assets...");
let vite_status = Command::new("bun")
.args(["run", "build"])
.stdout(Stdio::null())
.stderr(Stdio::inherit())
.status();
if vite_status.is_err() || !vite_status.unwrap().success() {
style::print_error("Failed to build client assets");
std::process::exit(1);
}
step += 1;
}
let build_msg = if release {
"Building Rust binary (release)..."
} else {
"Building Rust binary (debug)..."
};
style::print_step(step, total_steps, build_msg);
let mut cargo_args = vec!["build"];
if release {
cargo_args.push("--release");
}
let cargo_status = Command::new("cargo")
.args(&cargo_args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status();
if cargo_status.is_err() || !cargo_status.unwrap().success() {
style::print_error("Failed to build Rust binary");
std::process::exit(1);
}
println!();
style::print_success(&format!("Build complete! ({})", mode));
if release {
print_deployment_info(has_client);
}
}
fn print_deployment_info(_has_client: bool) {
let binary_name = get_project_name().unwrap_or_else(|| "your-app".to_string());
println!();
println!("{}", " To run:".white().bold());
println!(" ./target/release/{}", binary_name);
println!();
println!(
" {}",
"Or clone this repo on your server and run the binary from the project root.".dimmed()
);
}
fn get_project_name() -> Option<String> {
let cargo_toml = std::fs::read_to_string("Cargo.toml").ok()?;
for line in cargo_toml.lines() {
if line.starts_with("name") {
let parts: Vec<&str> = line.split('=').collect();
if parts.len() == 2 {
return Some(
parts[1]
.trim()
.trim_matches('"')
.trim_matches('\'')
.to_string(),
);
}
}
}
None
}