use std::path::{Path, PathBuf}; use anyhow::{Result, Context, bail}; use std::fs; use colored::*; pub mod android; pub mod ftc; pub mod gradle; pub mod proxy; pub struct SdkConfig { pub ftc_sdk_path: PathBuf, pub android_sdk_path: PathBuf, pub cache_dir: PathBuf, } impl SdkConfig { pub fn new() -> Result { // Allow tests (or power users) to override the cache directory. // When WEEVIL_HOME is set, we also skip the system Android SDK // search so tests are fully isolated. let (cache_dir, android_sdk_path) = if let Ok(weevil_home) = std::env::var("WEEVIL_HOME") { let cache = PathBuf::from(weevil_home); let android = cache.join("android-sdk"); (cache, android) } else { let home = dirs::home_dir() .context("Could not determine home directory")?; let cache = home.join(".weevil"); let android = Self::find_android_sdk().unwrap_or_else(|| cache.join("android-sdk")); (cache, android) }; fs::create_dir_all(&cache_dir)?; Ok(Self { ftc_sdk_path: cache_dir.join("ftc-sdk"), android_sdk_path, cache_dir, }) } pub fn with_paths(ftc_sdk: Option<&str>, android_sdk: Option<&str>) -> Result { let mut config = Self::new()?; if let Some(path) = ftc_sdk { config.ftc_sdk_path = PathBuf::from(path); } if let Some(path) = android_sdk { config.android_sdk_path = PathBuf::from(path); } Ok(config) } fn find_android_sdk() -> Option { // Check common locations let home = dirs::home_dir()?; let candidates = vec![ home.join("Android/Sdk"), home.join(".android-sdk"), PathBuf::from("/usr/lib/android-sdk"), ]; for candidate in candidates { if candidate.join("platform-tools").exists() { return Some(candidate); } } None } #[allow(dead_code)] pub fn validate(&self) -> Result<()> { if !self.ftc_sdk_path.exists() { bail!( "FTC SDK not found at: {}\nRun: weevil sdk install", self.ftc_sdk_path.display() ); } if !self.android_sdk_path.exists() { bail!( "Android SDK not found at: {}\nRun: weevil sdk install", self.android_sdk_path.display() ); } Ok(()) } pub fn print_status(&self) { println!("{}", "SDK Configuration:".bright_yellow().bold()); println!(); self.print_sdk_status("FTC SDK", &self.ftc_sdk_path); self.print_sdk_status("Android SDK", &self.android_sdk_path); println!(); println!("{}: {}", "Cache Directory".bright_yellow(), self.cache_dir.display()); } fn print_sdk_status(&self, name: &str, path: &Path) { let status = if path.exists() { format!("{} {}", "✓".green(), path.display()) } else { format!("{} {} {}", "✗".red(), path.display(), "(not found)".red()) }; println!("{}: {}", name.bright_yellow(), status); } }