#!/usr/bin/env python import os import json import platform import sys import shutil import glob import re def padded_print(to_print, end, minimum_length): pad_length = minimum_length - len(to_print) + 2 print(to_print + ' ' * pad_length, end=end) def show_options(option_list, columns): longest_option = max([len(option) + 4 for option in option_list]) for x in range(0, len(option_list), columns): for y in range(x, min(len(option_list), x + columns), 1): padded_print("[{opnum}] {option}".format(opnum=y, option=option_list[y]),'', longest_option) print("") #def show_options(option_list, columns): # for x in range(0, len(option_list), columns): # for y in range(x, min(len(option_list), x + columns), 1): # print("[{opnum}] {option}".format(opnum=y, option=option_list[y]), end=' ') # # print("") def get_selection(option_list, columns, prompt): selection = "" while True: show_options(option_list, columns) selection = input(prompt) if (selection == ""): print("You need to actually specify a number") else: try: int_form = int(selection) if (int_form >= 0 and int_form < len(option_list)): return option_list[int_form] else: print("You need to specify your selection as one of the numbers listed") except: print("You need to specify your selection as one of the numbers listed") ### BEGIN Ask the user where there WPILIB folder is if (platform.system() == "Windows"): wpilib_folder = input("Path to WPILIB Folder (or leave blank for C:\\Users\\Public\\wpilib): ") else: wpilib_folder = input("Path to WPILIB Folder (or leave blank for ~/wpilib): ") print() # For spacing wpilib_folder = wpilib_folder if wpilib_folder != "" else "C:\\Users\\Public\\wpilib" if platform.system() == "Windows" else os.path.expanduser("~/wpilib") ### END Ask the user where there WPILIB folder is ### BEGIN Determine the most current WPILIB folder field that is available year = "0" for folder in os.listdir(wpilib_folder): joined = os.path.join(wpilib_folder, folder) if (os.path.isdir(joined)): try: if (max(int(year), int(folder)) != int(year)): year = folder except: pass # Don't care about this, just means it's not a year folder, and I don't want the script to die if (year == "0"): print("It doesn't look like WPILIB is installed in the appropriate location") sys.exit(1) wpilib_folder = os.path.join(wpilib_folder, year) ### END Determine the most current WPILIB folder field that is available ### BEGIN Determine project language and type project_language = get_selection(["Java", "C++"], 1, "Select your language: ").lower().replace('+', 'p') print("") # For spacing project_type = get_selection(["Template", "Example"], 1, "Select your project type: ").lower() + "s" print("") # For spacing ### END Determine project language and type ### BEGIN Set common directories and variables for source project files project_app = os.path.join(wpilib_folder, "utility", "resources", "app") project_resources = os.path.join(project_app, "resources") gradle_shared = os.path.join(project_resources, "gradle", "shared") vendordeps = os.path.join(project_resources, "vendordeps") language_source = os.path.join(project_resources, project_language, "src", project_type) # Is this the right way to get this value? From the electron apps package.json? with open(os.path.join(project_app, "package.json")) as json_file: wpilib_version = json.loads(json_file.read())["version"] with open(os.path.join(language_source, project_type + ".json")) as json_file: json_data = json.loads(json_file.read()) ### END Set common directories and variables for source project files ### BEGIN Identify which example/template to use and set relevant variables all_named_options = [element["name"] for element in json_data] name_selected = get_selection(all_named_options, 3, "Select from the above to build your project from: ") print("") # For spacing project_json = [element for element in json_data if element["name"] == name_selected][0] project_main_folder = os.path.join(language_source, project_json["foldername"]) project_gradle_folder = os.path.join(project_resources, "gradle", project_json["gradlebase"]) ### END Identify which example/template to use and set relevant variables ### BEGIN Determine user project directory and name and set relevant variables project_directory = os.path.expanduser(input("Enter the project directory: ")) project_name = input("Enter the name of your project folder (or leave blank to put project in the project directory): ") if project_name == "": new_project_path = project_directory else: new_project_path = os.path.join(project_directory, project_name) new_project_path_src = os.path.join(new_project_path, "src", "main") ### END Determine user project directory and name and set relevant variables ### BEGIN Generate project directories and fill them with the appropriate files os.makedirs(os.path.join(new_project_path_src, "deploy"), exist_ok=True) if project_language == "java": os.makedirs(os.path.join(new_project_path_src, "java", "frc", "robot"), exist_ok=True) if project_language == "java": shutil.copytree(project_main_folder, os.path.join(new_project_path_src, "java", "frc", "robot"), dirs_exist_ok=True) else: shutil.copytree(project_main_folder, new_project_path_src, dirs_exist_ok=True) shutil.copytree(project_gradle_folder, new_project_path, dirs_exist_ok=True) shutil.copytree(gradle_shared, new_project_path, dirs_exist_ok=True) shutil.copytree(vendordeps, os.path.join(new_project_path, "vendordeps"), dirs_exist_ok=True) ### END Generate project directories and fill them with the appropriate files ### BEGIN Do find and replace work for java projects and all projects team number config if project_language == "java": ### BEGIN Gradle build file changes for Java with open(os.path.join(new_project_path, "build.gradle"), "r") as gradle_build_file: gradle_build_content = gradle_build_file.read() gradle_build_content = gradle_build_content.replace("###GRADLERIOREPLACE###", wpilib_version) gradle_build_content = gradle_build_content.replace("###ROBOTCLASSREPLACE###", "frc.robot.Main") with open(os.path.join(new_project_path, "build.gradle"), "w") as gradle_build_file: gradle_build_file.write(gradle_build_content) ### END Gradle build file changes for Java ### BEGIN *.java find and replace template package in all files # This regular expression trickery needs to be HEAVILY tested. # I don't think it's going to hold up everywhere... # This is NOT a good regex for general use, but because we aren't # validating package names, just trying to nuke the generic # template packages, it's probably fine. # Note that because the last [option]* list doesn't include period, this # SHOULD ignore any continuing package structures after what we want to replace, # this is necessary as to not break command based templates template_regex = re.compile(r'edu\.wpi\.first\.wpilibj\.templates\.[a-zA-Z0-9]*') for file in glob.glob(os.path.join(new_project_path_src, "**", "*.java"), recursive=True): with open(file, "r") as java_file: java_file_content = java_file.read() java_file_content = template_regex.sub('frc.robot', java_file_content) with open(file, "w") as java_file: java_file.write(java_file_content) ### END *.java find and replace template package in all files with open(os.path.join(new_project_path, ".wpilib", "wpilib_preferences.json"), "r") as wpilib_pref_file: wpilib_pref_json = json.loads(wpilib_pref_file.read()) while wpilib_pref_json["teamNumber"] == -1: new_number = input("Enter your team number: ") try: wpilib_pref_json["teamNumber"] = int(new_number) except: print("Not a valid team number") wpilib_pref_json["teamNumber"] = -1 with open(os.path.join(new_project_path, ".wpilib", "wpilib_preferences.json"), "w") as wpilib_pref_file: wpilib_pref_file.write(json.dumps(wpilib_pref_json, indent=4)) ### END Do find and replace work for java projects and all projects team number config