use std::env;
use std::path::Path;
use std::process::Command;
fn load_dotenv() {
let env_path = Path::new(".env");
if env_path.exists() {
let _ = dotenv::from_path(env_path);
return;
}
if let Ok(current) = std::env::current_dir() {
let mut dir = current;
while let Some(parent) = dir.parent() {
let potential_env = parent.join(".env");
if potential_env.exists() {
let _ = dotenv::from_path(&potential_env);
return;
}
dir = parent.to_path_buf();
}
}
let _ = dotenv::dotenv();
}
fn find_project_root() -> Option<std::path::PathBuf> {
let mut current = std::env::current_dir().ok()?;
loop {
if current.join("Cargo.toml").exists() || current.join("oxidite.toml").exists() {
return Some(current);
}
if !current.pop() {
return None;
}
}
}
pub fn run_doctor() -> Result<(), Box<dyn std::error::Error>> {
load_dotenv();
println!("đĨ Oxidite Health Check\n");
let mut all_ok = true;
print!("Checking Rust installation... ");
match Command::new("rustc").arg("--version").output() {
Ok(output) => {
let version = String::from_utf8_lossy(&output.stdout);
println!("â
{}", version.trim());
}
Err(_) => {
println!("â Rust not found");
all_ok = false;
}
}
print!("Checking Cargo... ");
match Command::new("cargo").arg("--version").output() {
Ok(output) => {
let version = String::from_utf8_lossy(&output.stdout);
println!("â
{}", version.trim());
}
Err(_) => {
println!("â Cargo not found");
all_ok = false;
}
}
print!("Checking project structure... ");
if let Some(_root) = find_project_root() {
println!("â
Cargo.toml found");
} else {
println!("â ī¸ Not in a Cargo project directory");
}
print!("Checking configuration... ");
if let Some(root) = find_project_root() {
if root.join("oxidite.toml").exists() {
println!("â
oxidite.toml found");
} else if root.join("config.toml").exists() {
println!("â
config.toml found");
} else {
println!("â ī¸ No configuration file found (optional)");
}
} else {
println!("â ī¸ No configuration file found (optional)");
}
print!("Checking migrations... ");
if let Some(root) = find_project_root() {
let migrations_dir = root.join("migrations");
if migrations_dir.exists() {
let count = std::fs::read_dir(&migrations_dir)?.count();
println!("â
Found {} migration(s)", count);
} else {
println!("âšī¸ No migrations directory");
}
} else {
println!("âšī¸ No migrations directory");
}
println!("\nChecking environment variables:");
check_env_var("DATABASE_URL");
check_env_var("REDIS_URL");
check_env_var("JWT_SECRET");
println!();
if all_ok {
println!("â
All critical checks passed!");
} else {
println!("â ī¸ Some checks failed. See above for details.");
}
Ok(())
}
fn check_env_var(name: &str) {
print!(" {}: ", name);
match env::var(name) {
Ok(value) => {
let masked = if name.contains("SECRET") || name.contains("PASSWORD") {
"***"
} else if value.len() > 30 {
&format!("{}...", &value[..27])
} else {
&value
};
println!("â
{}", masked);
}
Err(_) => println!("â ī¸ Not set"),
}
}