From 64826e2ce2809c0a672356ecd81aecc271186686 Mon Sep 17 00:00:00 2001 From: Eric Ratliff Date: Sun, 25 Jan 2026 18:53:16 -0600 Subject: [PATCH] fix: Complete Windows deployment pipeline Fixes critical bugs in Windows APK deployment workflow including APK path resolution, adb integration, and config file parsing. Changes: - Fix APK search to look for TeamCode-debug.apk instead of *app-debug.apk - Strip both single and double quotes from batch file path parsing - Add android_sdk_path to project configuration (.weevil.toml) - Resolve adb.exe from Android SDK platform-tools directory - Check adb install exit code and report deployment failures correctly - Add migration support for old .weevil.toml files missing android_sdk_path - Update all tests to use new ProjectConfig::new() signature The deployment workflow now properly finds the generated APK, locates adb, and reports success/failure accurately on Windows. --- README.md | 7 ++++-- src/commands/upgrade.rs | 2 +- src/project/config.rs | 18 ++++++++++++-- src/project/mod.rs | 48 ++++++++++++++++++++++++++++++-------- tests/project_lifecycle.rs | 9 +++++-- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ea3ba19..43eab54 100644 --- a/README.md +++ b/README.md @@ -511,7 +511,7 @@ Built with frustration at unnecessarily complex robotics frameworks, and hope th ## Project Status -**Current Version:** 1.0.0-beta2 +**Current Version:** 1.0.0-rc1 **What Works:** - ✅ Project generation @@ -532,4 +532,7 @@ Built with frustration at unnecessarily complex robotics frameworks, and hope th **Questions? Issues? Suggestions?** -Open an issue on NXGit or reach out to the FTC community. Let's make robot programming accessible for everyone! 🚀 \ No newline at end of file +📧 Email: [eric@nxws.dev](mailto:eric@nxws.dev) +🐛 Issues: Open an issue on the repository + +Building better tools so you can build better robots. 🤖 diff --git a/src/commands/upgrade.rs b/src/commands/upgrade.rs index e31c1e2..328b4ae 100644 --- a/src/commands/upgrade.rs +++ b/src/commands/upgrade.rs @@ -32,7 +32,7 @@ pub fn upgrade_project(path: &str) -> Result<()> { let project_name = project_path.file_name() .and_then(|n| n.to_str()) .unwrap_or("unknown"); - crate::project::ProjectConfig::new(project_name, sdk_config.ftc_sdk_path.clone())? + crate::project::ProjectConfig::new(project_name, sdk_config.ftc_sdk_path.clone(), sdk_config.android_sdk_path.clone())? }; println!("Current SDK: {}", project_config.ftc_sdk_path.display()); diff --git a/src/project/config.rs b/src/project/config.rs index af609dc..ea5038b 100644 --- a/src/project/config.rs +++ b/src/project/config.rs @@ -9,10 +9,16 @@ pub struct ProjectConfig { pub weevil_version: String, pub ftc_sdk_path: PathBuf, pub ftc_sdk_version: String, + #[serde(default = "default_android_sdk_path")] + pub android_sdk_path: PathBuf, +} + +fn default_android_sdk_path() -> PathBuf { + PathBuf::new() } impl ProjectConfig { - pub fn new(project_name: &str, ftc_sdk_path: PathBuf) -> Result { + pub fn new(project_name: &str, ftc_sdk_path: PathBuf, android_sdk_path: PathBuf) -> Result { let ftc_sdk_version = crate::sdk::ftc::get_version(&ftc_sdk_path) .unwrap_or_else(|_| "unknown".to_string()); @@ -21,6 +27,7 @@ impl ProjectConfig { weevil_version: "1.0.0".to_string(), ftc_sdk_path, ftc_sdk_version, + android_sdk_path, }) } @@ -34,9 +41,15 @@ impl ProjectConfig { let contents = fs::read_to_string(&config_path) .context("Failed to read .weevil.toml")?; - let config: ProjectConfig = toml::from_str(&contents) + let mut config: ProjectConfig = toml::from_str(&contents) .context("Failed to parse .weevil.toml")?; + // Migrate old configs that don't have android_sdk_path + if config.android_sdk_path.as_os_str().is_empty() { + let sdk_config = crate::sdk::SdkConfig::new()?; + config.android_sdk_path = sdk_config.android_sdk_path; + } + Ok(config) } @@ -77,6 +90,7 @@ impl ProjectConfig { println!(); println!("{:.<20} {}", "FTC SDK Path", self.ftc_sdk_path.display().to_string().bright_white()); println!("{:.<20} {}", "FTC SDK Version", self.ftc_sdk_version.bright_white()); + println!("{:.<20} {}", "Android SDK Path", self.android_sdk_path.display().to_string().bright_white()); println!(); } } \ No newline at end of file diff --git a/src/project/mod.rs b/src/project/mod.rs index cf45c24..dc4120d 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -77,7 +77,7 @@ impl ProjectBuilder { fn create_project_files(&self, project_path: &Path, sdk_config: &SdkConfig) -> Result<()> { // Create .weevil.toml config - let project_config = ProjectConfig::new(&self.name, sdk_config.ftc_sdk_path.clone())?; + let project_config = ProjectConfig::new(&self.name, sdk_config.ftc_sdk_path.clone(), sdk_config.android_sdk_path.clone())?; project_config.save(project_path)?; // README.md @@ -334,34 +334,62 @@ echo "✓ Deployed!" let deploy_bat = r#"@echo off setlocal enabledelayedexpansion -REM Read SDK path from config -for /f "tokens=2 delims==" %%a in ('findstr /c:"ftc_sdk_path" .weevil.toml') do ( - set SDK_DIR=%%a - set SDK_DIR=!SDK_DIR:"=! - set SDK_DIR=!SDK_DIR: =! -) +REM Read SDK paths from config +for /f "tokens=2 delims==" %%a in ('findstr /c:"ftc_sdk_path" .weevil.toml') do set SDK_DIR=%%a +for /f "tokens=2 delims==" %%a in ('findstr /c:"android_sdk_path" .weevil.toml') do set ANDROID_SDK=%%a + +REM Strip all quotes (both single and double) +set SDK_DIR=%SDK_DIR:"=% +set SDK_DIR=%SDK_DIR:'=% +set SDK_DIR=%SDK_DIR: =% +set ANDROID_SDK=%ANDROID_SDK:"=% +set ANDROID_SDK=%ANDROID_SDK:'=% +set ANDROID_SDK=%ANDROID_SDK: =% if not defined SDK_DIR ( echo Error: Could not read FTC SDK path from .weevil.toml exit /b 1 ) +if not defined ANDROID_SDK ( + echo Error: Could not read Android SDK path from .weevil.toml + exit /b 1 +) + +REM Set ADB path +set ADB_PATH=%ANDROID_SDK%\platform-tools\adb.exe + echo Building APK... call gradlew.bat buildApk echo. echo Deploying to Control Hub... -REM Find APK -for /f "delims=" %%i in ('dir /s /b "%SDK_DIR%\*app-debug.apk" 2^>nul') do set APK=%%i +REM Find APK - look for TeamCode-debug.apk +for /f "delims=" %%i in ('dir /s /b "%SDK_DIR%\TeamCode-debug.apk" 2^>nul') do set APK=%%i if not defined APK ( echo Error: APK not found exit /b 1 ) +echo Found APK: %APK% + +REM Check for adb +if not exist "%ADB_PATH%" ( + echo Error: adb not found at %ADB_PATH% + echo Run: weevil sdk install + exit /b 1 +) + echo Installing: %APK% -adb install -r "%APK%" +"%ADB_PATH%" install -r "%APK%" + +if errorlevel 1 ( + echo. + echo Deployment failed! + exit /b 1 +) echo. echo Deployed! diff --git a/tests/project_lifecycle.rs b/tests/project_lifecycle.rs index 0780f08..1e98c75 100644 --- a/tests/project_lifecycle.rs +++ b/tests/project_lifecycle.rs @@ -13,6 +13,7 @@ use weevil::sdk::SdkConfig; fn test_config_create_and_save() { let temp_dir = TempDir::new().unwrap(); let sdk_path = temp_dir.path().join("mock-sdk"); + let android_sdk_path = temp_dir.path().join("android-sdk"); // Create minimal SDK structure fs::create_dir_all(sdk_path.join("TeamCode/src/main/java")).unwrap(); @@ -20,10 +21,11 @@ fn test_config_create_and_save() { fs::write(sdk_path.join("build.gradle"), "// test").unwrap(); fs::write(sdk_path.join(".version"), "v10.1.1").unwrap(); - let config = ProjectConfig::new("test-robot", sdk_path.clone()).unwrap(); + let config = ProjectConfig::new("test-robot", sdk_path.clone(), android_sdk_path.clone()).unwrap(); assert_eq!(config.project_name, "test-robot"); assert_eq!(config.ftc_sdk_path, sdk_path); + assert_eq!(config.android_sdk_path, android_sdk_path); assert_eq!(config.weevil_version, "1.0.0"); // Save and reload @@ -34,12 +36,14 @@ fn test_config_create_and_save() { let loaded = ProjectConfig::load(&project_path).unwrap(); assert_eq!(loaded.project_name, config.project_name); assert_eq!(loaded.ftc_sdk_path, config.ftc_sdk_path); + assert_eq!(loaded.android_sdk_path, config.android_sdk_path); } #[test] fn test_config_toml_format() { let temp_dir = TempDir::new().unwrap(); let sdk_path = temp_dir.path().join("sdk"); + let android_sdk_path = temp_dir.path().join("android-sdk"); // Create minimal SDK fs::create_dir_all(sdk_path.join("TeamCode/src/main/java")).unwrap(); @@ -47,7 +51,7 @@ fn test_config_toml_format() { fs::write(sdk_path.join("build.gradle"), "// test").unwrap(); fs::write(sdk_path.join(".version"), "v10.1.1").unwrap(); - let config = ProjectConfig::new("my-robot", sdk_path).unwrap(); + let config = ProjectConfig::new("my-robot", sdk_path, android_sdk_path).unwrap(); let project_path = temp_dir.path().join("project"); fs::create_dir_all(&project_path).unwrap(); @@ -59,6 +63,7 @@ fn test_config_toml_format() { assert!(content.contains("weevil_version = \"1.0.0\"")); assert!(content.contains("ftc_sdk_path")); assert!(content.contains("ftc_sdk_version")); + assert!(content.contains("android_sdk_path")); } #[test]