use clap::{Parser, Subcommand}; use colored::*; use anyhow::Result; use weevil::version::WEEVIL_VERSION; // Import ProxyConfig through our own `mod sdk`, not through the `weevil` // library crate. Both re-export the same source, but Rust treats // `weevil::sdk::proxy::ProxyConfig` and `sdk::proxy::ProxyConfig` as // distinct types when a binary and its lib are compiled together. // The command modules already see the local-mod version, so main must match. mod commands; mod sdk; mod project; mod templates; use sdk::proxy::ProxyConfig; #[derive(Parser)] #[command(name = "weevil")] #[command(author = "Eric Ratliff ")] #[command(version = WEEVIL_VERSION)] #[command( about = "FTC robotics project generator - bores into complexity, emerges with clean code", long_about = None )] struct Cli { /// Use this HTTP/HTTPS proxy for all downloads #[arg(long, value_name = "URL", global = true)] proxy: Option, /// Skip proxy entirely — go direct even if HTTPS_PROXY is set #[arg(long, global = true)] no_proxy: bool, #[command(subcommand)] command: Commands, } #[derive(Subcommand)] enum Commands { /// Create a new FTC robot project New { /// Name of the robot project name: String, /// Path to FTC SDK (optional, will auto-detect or download) #[arg(long)] ftc_sdk: Option, /// Path to Android SDK (optional, will auto-detect or download) #[arg(long)] android_sdk: Option, }, /// Check system health and diagnose issues Doctor, /// Setup development environment (system or project) Setup { /// Path to project directory (optional - without it, sets up system) path: Option, }, /// Remove Weevil-installed SDKs and dependencies Uninstall { /// Show what would be removed without actually removing anything #[arg(long)] dry_run: bool, /// Remove only specific items by number (use --dry-run first to see the list) #[arg(long, value_name = "NUM", num_args = 1..)] only: Option>, }, /// Upgrade an existing project to the latest generator version Upgrade { /// Path to the project directory path: String, }, /// Build and deploy project to Control Hub Deploy { /// Path to the project directory path: String, /// Force USB connection #[arg(long)] usb: bool, /// Force WiFi connection #[arg(long)] wifi: bool, /// Custom IP address #[arg(short, long)] ip: Option, }, /// Manage SDKs (FTC and Android) Sdk { #[command(subcommand)] command: SdkCommands, }, /// Show or update project configuration Config { /// Path to the project directory path: String, /// Set FTC SDK path for this project #[arg(long, value_name = "PATH")] set_sdk: Option, }, } #[derive(Subcommand)] enum SdkCommands { /// Install required SDKs Install, /// Show SDK status and locations Status, /// Update SDKs to latest versions Update, } fn main() -> Result<()> { // Enable colors on Windows #[cfg(windows)] colored::control::set_virtual_terminal(true).ok(); let cli = Cli::parse(); print_banner(); // Resolve proxy once at the top — every network-touching command uses it. let proxy = ProxyConfig::resolve(cli.proxy.as_deref(), cli.no_proxy)?; match cli.command { Commands::New { name, ftc_sdk, android_sdk } => { commands::new::create_project(&name, ftc_sdk.as_deref(), android_sdk.as_deref(), &proxy) } Commands::Doctor => { commands::doctor::run_diagnostics() } Commands::Setup { path } => { commands::setup::setup_environment(path.as_deref(), &proxy) } Commands::Uninstall { dry_run, only } => { commands::uninstall::uninstall_dependencies(dry_run, only) } Commands::Upgrade { path } => { commands::upgrade::upgrade_project(&path) } Commands::Deploy { path, usb, wifi, ip } => { commands::deploy::deploy_project(&path, usb, wifi, ip.as_deref()) } Commands::Sdk { command } => match command { SdkCommands::Install => commands::sdk::install_sdks(&proxy), SdkCommands::Status => commands::sdk::show_status(), SdkCommands::Update => commands::sdk::update_sdks(&proxy), }, Commands::Config { path, set_sdk } => { if let Some(sdk_path) = set_sdk { commands::config::set_sdk(&path, &sdk_path) } else { commands::config::show_config(&path) } } } } fn print_banner() { println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan()); println!( "{}", format!(" 🪲 Weevil - FTC Project Generator v{}", WEEVIL_VERSION) .bright_cyan() .bold() ); println!("{}", " Nexus Workshops LLC".bright_cyan()); println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan()); println!(); }