From 832cf1db97c409535ef5eaa02154a6e6f6f074f1 Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Tue, 5 Dec 2023 20:50:10 -0500 Subject: [PATCH] Initial Commit --- project-creator.py | 217 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 project-creator.py diff --git a/project-creator.py b/project-creator.py new file mode 100644 index 0000000..8a8d298 --- /dev/null +++ b/project-creator.py @@ -0,0 +1,217 @@ +#!/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 +