feat: Weevil v1.0.0-beta1 - FTC Project Generator
Cross-platform tool for generating clean, testable FTC robot projects without editing the SDK installation. Features: - Standalone project generation with proper separation from SDK - Per-project SDK configuration via .weevil.toml - Local unit testing support (no robot required) - Cross-platform build/deploy scripts (Linux/macOS/Windows) - Project upgrade system preserving user code - Configuration management commands - Comprehensive test suite (11 passing tests) - Zero-warning builds Architecture: - Pure Rust implementation with embedded Gradle wrapper - Projects use deployToSDK task to copy code to FTC SDK TeamCode - Git-ready projects with automatic initialization - USB and WiFi deployment with auto-detection Commands: - weevil new <name> - Create new project - weevil upgrade <path> - Update project infrastructure - weevil config <path> - View/modify project configuration - weevil sdk status/install/update - Manage SDKs Addresses the core problem: FTC's SDK structure forces students to edit framework internals instead of separating concerns like industry standard practices. Weevil enables proper software engineering workflows for robotics education.
This commit is contained in:
103
src/sdk/mod.rs
Normal file
103
src/sdk/mod.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
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 struct SdkConfig {
|
||||
pub ftc_sdk_path: PathBuf,
|
||||
pub android_sdk_path: PathBuf,
|
||||
pub cache_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl SdkConfig {
|
||||
pub fn new() -> Result<Self> {
|
||||
let home = dirs::home_dir()
|
||||
.context("Could not determine home directory")?;
|
||||
|
||||
let cache_dir = home.join(".weevil");
|
||||
fs::create_dir_all(&cache_dir)?;
|
||||
|
||||
Ok(Self {
|
||||
ftc_sdk_path: cache_dir.join("ftc-sdk"),
|
||||
android_sdk_path: Self::find_android_sdk().unwrap_or_else(|| cache_dir.join("android-sdk")),
|
||||
cache_dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_paths(ftc_sdk: Option<&str>, android_sdk: Option<&str>) -> Result<Self> {
|
||||
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<PathBuf> {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user