#!/bin/bash # FTC Project Generator - Shared Library Functions # Copyright (c) 2026 Nexus Workshops LLC # Licensed under MIT License # Get the directory where this script lives get_script_dir() { echo "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" } # Get generator version get_generator_version() { local script_dir="$(get_script_dir)" local version_file="$script_dir/../VERSION" if [ -f "$version_file" ]; then cat "$version_file" | tr -d '\n\r' else echo "unknown" fi } # Process template file, replacing placeholders process_template() { local input="$1" local output="$2" sed -e "s|{{PROJECT_NAME}}|${PROJECT_NAME}|g" \ -e "s|{{SDK_DIR}}|${FTC_SDK_DIR}|g" \ -e "s|{{FTC_VERSION}}|${FTC_VERSION}|g" \ -e "s|{{GENERATOR_VERSION}}|${GENERATOR_VERSION}|g" \ "$input" > "$output" } # Copy template file copy_template() { local src="$1" local dest="$2" cp "$src" "$dest" } # Create project structure create_project_structure() { local project_dir="$1" mkdir -p "$project_dir" cd "$project_dir" mkdir -p src/main/java/robot/subsystems mkdir -p src/main/java/robot/hardware mkdir -p src/main/java/robot/opmodes mkdir -p src/test/java/robot/subsystems mkdir -p src/test/java/robot/hardware mkdir -p gradle/wrapper } # Install all project templates install_templates() { local project_dir="$1" local template_dir="$2" cd "$project_dir" copy_template "$template_dir/Pose2d.java" "src/main/java/robot/Pose2d.java" copy_template "$template_dir/Drive.java" "src/main/java/robot/subsystems/Drive.java" copy_template "$template_dir/MecanumDrive.java" "src/main/java/robot/hardware/MecanumDrive.java" copy_template "$template_dir/TeleOp.java" "src/main/java/robot/opmodes/TeleOp.java" copy_template "$template_dir/DriveTest.java" "src/test/java/robot/subsystems/DriveTest.java" copy_template "$template_dir/build.gradle.kts" "build.gradle.kts" process_template "$template_dir/settings.gradle.kts.template" "settings.gradle.kts" process_template "$template_dir/gitignore.template" ".gitignore" process_template "$template_dir/README.md.template" "README.md" copy_template "$template_dir/build.sh" "build.sh" chmod +x "build.sh" create_deploy_script "$project_dir" echo "${GENERATOR_VERSION}" > ".ftc-generator-version" } # Create deploy script create_deploy_script() { local project_dir="$1" cat > "$project_dir/deploy-to-robot.sh" <<'ENDSCRIPT' #!/bin/bash set -e CONTROL_HUB_IP="${CONTROL_HUB_IP:-192.168.43.1}" CONTROL_HUB_PORT="5555" while [[ $# -gt 0 ]]; do case $1 in -h|--help) echo "Deploy to Control Hub"; echo "Usage: $0 [--usb|--wifi] [-i IP]"; exit 0 ;; -i|--ip) CONTROL_HUB_IP="$2"; shift 2 ;; *) shift ;; esac done echo "Deploying to SDK..." ./gradlew deployToSDK || exit 1 echo "Building APK..." cd "${HOME}/ftc-sdk" && ./gradlew build || exit 1 APK_PATH="${HOME}/ftc-sdk/FtcRobotController/build/outputs/apk/debug/FtcRobotController-debug.apk" [ -f "$APK_PATH" ] || { echo "APK not found"; exit 1; } echo "Installing..." if adb devices | grep -q device; then adb install -r "$APK_PATH" && echo "✓ Deployed!" || exit 1 else adb connect "$CONTROL_HUB_IP:$CONTROL_HUB_PORT" && sleep 2 adb install -r "$APK_PATH" && echo "✓ Deployed!" || exit 1 fi ENDSCRIPT chmod +x "$project_dir/deploy-to-robot.sh" } # Setup Gradle wrapper setup_gradle_wrapper() { local project_dir="$1" cd "$project_dir" # Create gradle wrapper properties mkdir -p gradle/wrapper cat > gradle/wrapper/gradle-wrapper.properties < /dev/null; then echo "Error: gradle command not found" echo "Gradle must be installed to generate wrapper scripts" echo "" echo "Install:" echo " Ubuntu/Debian: sudo apt install gradle" echo " macOS: brew install gradle" return 1 fi echo "Generating Gradle wrapper..." # Try with system gradle first if gradle wrapper --gradle-version 8.9 --no-daemon 2>/dev/null; then echo "✓ Gradle wrapper created" else echo "" echo "System Gradle failed. Using fallback method..." # Download wrapper jar directly local wrapper_jar_url="https://raw.githubusercontent.com/gradle/gradle/v8.9.0/gradle/wrapper/gradle-wrapper.jar" if command -v curl &> /dev/null; then curl -sL "$wrapper_jar_url" -o gradle/wrapper/gradle-wrapper.jar 2>/dev/null elif command -v wget &> /dev/null; then wget -q "$wrapper_jar_url" -O gradle/wrapper/gradle-wrapper.jar 2>/dev/null else echo "Error: Need curl or wget to download wrapper jar" return 1 fi if [ ! -f "gradle/wrapper/gradle-wrapper.jar" ]; then echo "Error: Failed to download gradle-wrapper.jar" return 1 fi # Create proper gradlew script cat > gradlew <<'GRADLEW_END' #!/bin/sh APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_BASE_NAME=${0##*/} # Determine the Java command if [ -n "$JAVA_HOME" ] ; then JAVACMD=$JAVA_HOME/bin/java else JAVACMD=java fi # Check if Java is available if ! "$JAVACMD" -version > /dev/null 2>&1; then echo "ERROR: JAVA_HOME is not set and no 'java' command could be found" exit 1 fi # Execute Gradle exec "$JAVACMD" -Xmx64m -Xms64m -Dorg.gradle.appname="$APP_BASE_NAME" -classpath "$(dirname "$0")/gradle/wrapper/gradle-wrapper.jar" org.gradle.wrapper.GradleWrapperMain "$@" GRADLEW_END chmod +x gradlew # Create Windows batch file cat > gradlew.bat <<'GRADLEWBAT_END' @if "%DEBUG%" == "" @echo off setlocal enabledelayedexpansion set DIRNAME=%~dp0 set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% set CLASSPATH=%APP_HOME%gradle\wrapper\gradle-wrapper.jar if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe goto execute :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%\bin\java.exe :execute "%JAVA_EXE%" -Xmx64m -Xms64m -Dorg.gradle.appname="%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end GRADLEWBAT_END echo "✓ Gradle wrapper created (via fallback)" fi # Verify wrapper was created if [ ! -f "gradlew" ]; then echo "Error: gradlew script not created" return 1 fi } # Check if project is a generator project is_generator_project() { local project_dir="$1" [ -f "$project_dir/.ftc-generator-version" ] } # Get project generator version get_project_generator_version() { local project_dir="$1" if [ -f "$project_dir/.ftc-generator-version" ]; then cat "$project_dir/.ftc-generator-version" | tr -d '\n\r' else echo "unknown" fi } # Upgrade project upgrade_project() { local project_dir="$1" local template_dir="$2" local old_version=$(get_project_generator_version "$project_dir") echo "Upgrading project from $old_version to ${GENERATOR_VERSION}..." cd "$project_dir" copy_template "$template_dir/build.gradle.kts" "build.gradle.kts" process_template "$template_dir/settings.gradle.kts.template" "settings.gradle.kts" process_template "$template_dir/gitignore.template" ".gitignore" copy_template "$template_dir/build.sh" "build.sh" chmod +x "build.sh" create_deploy_script "$project_dir" echo "${GENERATOR_VERSION}" > ".ftc-generator-version" echo "✓ Upgrade complete" } # Initialize git repo init_git_repo() { local project_dir="$1" cd "$project_dir" if [ ! -d ".git" ]; then git init > /dev/null 2>&1 git add . > /dev/null 2>&1 git commit -m "Initial commit from FTC Project Generator v${GENERATOR_VERSION}" > /dev/null 2>&1 echo "✓ Git repository initialized" fi } # Check prerequisites check_prerequisites() { local missing=() command -v git &> /dev/null || missing+=("git") command -v java &> /dev/null || missing+=("java") command -v gradle &> /dev/null || missing+=("gradle") if [ "${#missing[@]}" -gt 0 ]; then echo "Error: Missing tools: ${missing[*]}" echo "Install: sudo apt install ${missing[*]}" return 1 fi echo "✓ All prerequisites satisfied" return 0 }