use anyhow::{Context, Result};
use console::{style, Emoji};
use std::path::PathBuf;
use std::process::Command;
pub fn build(target: Option<&str>, strip: bool, verbose: bool, size: bool) -> Result<()> {
let project_dir = std::env::current_dir().context("Failed to get current directory")?;
println!();
println!("{} {}", Emoji("๐๏ธ", ""), style("Building release binary").bold());
println!();
let mut args = vec!["build", "--release"];
if let Some(t) = target {
args.push("--target");
args.push(t);
println!(" {} {}", style("Target:").dim(), style(t).cyan());
}
if strip {
args.push("--bin");
args.push("--strip");
println!(" {} {}", style("Strip:").dim(), style("enabled").cyan());
}
println!(" {} {}", style("Mode:").dim(), style("release (opt-level=3, lto=true)").cyan());
if verbose {
args.push("--verbose");
}
println!();
let start = std::time::Instant::now();
let status = Command::new("cargo")
.args(&args)
.current_dir(&project_dir)
.status()
.context("Failed to run cargo build")?;
let elapsed = start.elapsed();
if !status.success() {
anyhow::bail!("Build failed with exit code: {:?}", status.code());
}
let package_name = project_dir
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| "app".to_string());
let binary_path = if target.is_some() {
PathBuf::from("target")
.join(target.unwrap())
.join("release")
.join(&package_name)
} else {
PathBuf::from("target")
.join("release")
.join(&package_name)
};
let full_path = project_dir.join(&binary_path);
println!();
println!("{} {}", Emoji("โ
", ""), style("Build successful!").green());
println!(" {} ({} ms)", style("Time:").dim(), elapsed.as_millis());
if full_path.exists() {
let size_bytes = std::fs::metadata(&full_path)
.map(|m| m.len())
.unwrap_or(0);
let size_kb = size_bytes / 1024;
let size_mb = size_bytes / (1024 * 1024);
println!(" {} {} ({} KB / {} MB)", style("Binary:").dim(), full_path.display(), size_kb, size_mb);
if size {
println!();
println!("{} Binary size breakdown:", style("๐").cyan());
println!(" {} {:.2} KB (binary)", style("โ").dim(), size_kb as f64);
}
} else {
println!(" {} (in {})", style("Binary:").dim(), binary_path.display());
}
println!();
Ok(())
}
pub fn check(verbose: bool) -> Result<()> {
let project_dir = std::env::current_dir().context("Failed to get current directory")?;
println!();
println!("{} {}", Emoji("๐", ""), style("Running cargo check").bold());
println!();
let mut args = vec!["check"];
if verbose {
args.push("--verbose");
}
let start = std::time::Instant::now();
let output = Command::new("cargo")
.args(&args)
.current_dir(&project_dir)
.output()
.context("Failed to run cargo check")?;
let elapsed = start.elapsed();
if output.status.success() {
println!();
println!("{} {}", Emoji("โ
", ""), style("Check passed!").green());
println!(" {} ({} ms)", style("Time:").dim(), elapsed.as_millis());
} else {
println!();
println!("{} {}", style("โ").red(), style("Check failed:").red().bold());
println!("{}", String::from_utf8_lossy(&output.stderr));
anyhow::bail!("cargo check failed");
}
Ok(())
}
pub fn test(filter: &str, release: bool, nocapture: bool) -> Result<()> {
let project_dir = std::env::current_dir().context("Failed to get current directory")?;
println!();
println!("{} {}", Emoji("๐งช", ""), style("Running tests").bold());
println!();
let mut args = vec!["test"];
if !filter.is_empty() {
args.push(filter);
}
if release {
args.push("--release");
println!(" {} {}", style("Mode:").dim(), style("release").cyan());
}
if nocapture {
args.push("--nocapture");
}
println!(" {} {}", style("Command:").dim(), format!("cargo {}", args.join(" ")));
println!();
let start = std::time::Instant::now();
let output = Command::new("cargo")
.args(&args)
.current_dir(&project_dir)
.output()
.context("Failed to run cargo test")?;
let elapsed = start.elapsed();
println!("{}", String::from_utf8_lossy(&output.stdout));
if output.status.success() {
println!();
println!("{} {}", Emoji("โ
", ""), style("All tests passed!").green());
println!(" {} ({} ms)", style("Time:").dim(), elapsed.as_millis());
} else {
println!();
println!("{} {}", style("โ").red(), style("Some tests failed:").red().bold());
anyhow::bail!("cargo test failed");
}
Ok(())
}