diff --git a/src/commands/upgrade.rs b/src/commands/upgrade.rs index 328b4ae..c4bea1d 100644 --- a/src/commands/upgrade.rs +++ b/src/commands/upgrade.rs @@ -52,6 +52,19 @@ pub fn upgrade_project(path: &str) -> Result<()> { "gradle/wrapper/gradle-wrapper.properties", "gradle/wrapper/gradle-wrapper.jar", ".gitignore", + // Android Studio integration — regenerated so run configs stay in + // sync if deploy.sh flags or script names ever change. + ".idea/workspace.xml", + ".idea/runConfigurations/Build.xml", + ".idea/runConfigurations/Build (Windows).xml", + ".idea/runConfigurations/Deploy (auto).xml", + ".idea/runConfigurations/Deploy (auto) (Windows).xml", + ".idea/runConfigurations/Deploy (USB).xml", + ".idea/runConfigurations/Deploy (USB) (Windows).xml", + ".idea/runConfigurations/Deploy (WiFi).xml", + ".idea/runConfigurations/Deploy (WiFi) (Windows).xml", + ".idea/runConfigurations/Test.xml", + ".idea/runConfigurations/Test (Windows).xml", ]; println!("{}", "Updating infrastructure files...".bright_yellow()); diff --git a/src/project/mod.rs b/src/project/mod.rs index 983341c..692d83d 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -55,6 +55,7 @@ impl ProjectBuilder { "src/test/java/robot", "src/test/java/robot/subsystems", "gradle/wrapper", + ".idea/runConfigurations", ]; for dir in dirs { @@ -416,9 +417,307 @@ class BasicTest { test_file )?; + // Android Studio integration: .idea/ files + self.generate_idea_files(project_path)?; + Ok(()) } + /// Generate .idea/ files for Android Studio integration. + /// + /// The goal is for students to open the project in Android Studio and see + /// a clean file tree (just src/ and the scripts) with Run configurations + /// that invoke Weevil's shell scripts directly. All the internal plumbing + /// (sdk/, .gradle/, build/) is hidden from the IDE view. + /// + /// Android Studio uses IntelliJ's run configuration XML format. The + /// ShellScript type invokes a script relative to the project root — exactly + /// what we want since deploy.sh and build.sh already live there. + fn generate_idea_files(&self, project_path: &Path) -> Result<()> { + // workspace.xml — controls the file-tree view and hides internals. + // We use a ProjectViewPane exclude pattern list rather than touching + // the module's source roots, so this works regardless of whether the + // student has opened the project before. + let workspace_xml = r#" + + + + + + + + + + + + + + + + + + + + + + + + +"#; + fs::write(project_path.join(".idea/workspace.xml"), workspace_xml)?; + + // Run configurations. Each is a ShellScript type that invokes one of + // Weevil's scripts. Android Studio shows these in the Run dropdown + // at the top of the IDE — no configuration needed by the student. + // + // We generate both Unix (.sh, ./gradlew) and Windows (.bat, gradlew.bat) + // variants. Android Studio automatically hides configs whose script files + // don't exist, so only the platform-appropriate ones appear in the dropdown. + + // Build (Unix) — just builds the APK without deploying + let build_unix_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Build.xml"), + build_unix_xml, + )?; + + // Build (Windows) — same, but calls build.bat + let build_windows_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Build (Windows).xml"), + build_windows_xml, + )?; + + // Deploy (auto) — no flags, deploy.sh auto-detects USB vs WiFi + let deploy_auto_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Deploy (auto).xml"), + deploy_auto_xml, + )?; + + // Deploy (auto) (Windows) + let deploy_auto_windows_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Deploy (auto) (Windows).xml"), + deploy_auto_windows_xml, + )?; + + // Deploy (USB) — forces USB connection + let deploy_usb_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Deploy (USB).xml"), + deploy_usb_xml, + )?; + + // Deploy (USB) (Windows) + let deploy_usb_windows_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Deploy (USB) (Windows).xml"), + deploy_usb_windows_xml, + )?; + + // Deploy (WiFi) — forces WiFi connection to default 192.168.43.1 + let deploy_wifi_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Deploy (WiFi).xml"), + deploy_wifi_xml, + )?; + + // Deploy (WiFi) (Windows) + let deploy_wifi_windows_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Deploy (WiFi) (Windows).xml"), + deploy_wifi_windows_xml, + )?; + + // Test — runs the unit test suite via Gradle + let test_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Test.xml"), + test_xml, + )?; + + // Test (Windows) + let test_windows_xml = r#" + + + +"#; + fs::write( + project_path.join(".idea/runConfigurations/Test (Windows).xml"), + test_windows_xml, + )?; + + + Ok(()) + } + fn setup_gradle(&self, project_path: &Path) -> Result<()> { println!("Setting up Gradle wrapper..."); crate::sdk::gradle::setup_wrapper(project_path)?;