220 lines
8.4 KiB
Python
220 lines
8.4 KiB
Python
#!/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 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 and cpp projects and all projects team number config
|
|
|
|
### TODO Opening and closing build.gradle is unnecessarily repetitive,
|
|
### Might be better to lose the with calls and manually open/close the files?
|
|
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)
|
|
|
|
with open(os.path.join(new_project_path, "build.gradle"), "w") as gradle_build_file:
|
|
gradle_build_file.write(gradle_build_content)
|
|
|
|
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("###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/example 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|examples)\.[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
|
|
|