mirror of
https://github.com/goldenfishs/MRobot.git
synced 2025-05-06 01:10:55 +08:00
好用的准备发布
This commit is contained in:
parent
f67878cce7
commit
927cafca66
174
MRobot.py
174
MRobot.py
@ -8,10 +8,14 @@ import re
|
|||||||
from git import Repo
|
from git import Repo
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import csv
|
import csv
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
# 配置常量
|
# 配置常量
|
||||||
REPO_DIR = "MRobot_repo"
|
REPO_DIR = "MRobot_repo"
|
||||||
REPO_URL = "http://gitea.qutrobot.top/robofish/MRobot.git"
|
REPO_URL = "http://gitea.qutrobot.top/robofish/MRobot.git"
|
||||||
|
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
MDK_ARM_DIR = os.path.join(CURRENT_DIR, "MDK-ARM")
|
||||||
|
USER_DIR = os.path.join(CURRENT_DIR, "User")
|
||||||
|
|
||||||
class MRobotApp:
|
class MRobotApp:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -48,6 +52,123 @@ class MRobotApp:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"删除仓库目录时出错: {e}")
|
print(f"删除仓库目录时出错: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def auto_configure_environment(self):
|
||||||
|
"""自动配置环境"""
|
||||||
|
try:
|
||||||
|
self.add_groups_and_files()
|
||||||
|
self.add_include_path(r"..\User")
|
||||||
|
print("环境配置完成!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"自动配置环境时出错: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def log(self, message):
|
||||||
|
"""统一日志输出"""
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
|
||||||
|
def find_uvprojx_file(self):
|
||||||
|
"""查找 MDK-ARM 文件夹中的 .uvprojx 文件"""
|
||||||
|
if not os.path.exists(MDK_ARM_DIR):
|
||||||
|
self.log(f"未找到 MDK-ARM 文件夹:{MDK_ARM_DIR}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
uvprojx_files = [f for f in os.listdir(MDK_ARM_DIR) if f.endswith(".uvprojx")]
|
||||||
|
if not uvprojx_files:
|
||||||
|
self.log(f"在 {MDK_ARM_DIR} 中未找到任何 .uvprojx 文件!")
|
||||||
|
return None
|
||||||
|
|
||||||
|
project_file = os.path.join(MDK_ARM_DIR, uvprojx_files[0])
|
||||||
|
self.log(f"找到项目文件:{project_file}")
|
||||||
|
return project_file
|
||||||
|
|
||||||
|
|
||||||
|
def add_groups_and_files(self):
|
||||||
|
"""添加 User 文件夹中的组和文件到 Keil 项目"""
|
||||||
|
project_file = self.find_uvprojx_file()
|
||||||
|
if not project_file:
|
||||||
|
return
|
||||||
|
|
||||||
|
tree = ET.parse(project_file)
|
||||||
|
root = tree.getroot()
|
||||||
|
groups_node = root.find(".//Groups")
|
||||||
|
if groups_node is None:
|
||||||
|
self.log("未找到 Groups 节点!")
|
||||||
|
return
|
||||||
|
|
||||||
|
existing_groups = {group.find("GroupName").text for group in groups_node.findall("Group")}
|
||||||
|
existing_files = {
|
||||||
|
file.text
|
||||||
|
for group in groups_node.findall("Group")
|
||||||
|
for file in group.findall(".//FileName")
|
||||||
|
}
|
||||||
|
|
||||||
|
for folder_name in os.listdir(USER_DIR):
|
||||||
|
folder_path = os.path.join(USER_DIR, folder_name)
|
||||||
|
if not os.path.isdir(folder_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
group_name = f"User/{folder_name}"
|
||||||
|
if group_name in existing_groups:
|
||||||
|
self.log(f"组 {group_name} 已存在,跳过...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
group_node = ET.SubElement(groups_node, "Group")
|
||||||
|
ET.SubElement(group_node, "GroupName").text = group_name
|
||||||
|
files_node = ET.SubElement(group_node, "Files")
|
||||||
|
|
||||||
|
for file_name in os.listdir(folder_path):
|
||||||
|
file_path = os.path.join(folder_path, file_name)
|
||||||
|
if not os.path.isfile(file_path) or file_name in existing_files:
|
||||||
|
self.log(f"文件 {file_name} 已存在或无效,跳过...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
file_node = ET.SubElement(files_node, "File")
|
||||||
|
ET.SubElement(file_node, "FileName").text = file_name
|
||||||
|
ET.SubElement(file_node, "FileType").text = "1"
|
||||||
|
relative_path = os.path.relpath(file_path, os.path.dirname(project_file)).replace("\\", "/")
|
||||||
|
ET.SubElement(file_node, "FilePath").text = relative_path
|
||||||
|
|
||||||
|
tree.write(project_file, encoding="utf-8", xml_declaration=True)
|
||||||
|
self.log("Keil 项目文件已更新!")
|
||||||
|
|
||||||
|
def add_include_path(self, new_path):
|
||||||
|
"""添加新的 IncludePath 到 Keil 项目"""
|
||||||
|
project_file = self.find_uvprojx_file()
|
||||||
|
if not project_file:
|
||||||
|
return
|
||||||
|
|
||||||
|
tree = ET.parse(project_file)
|
||||||
|
root = tree.getroot()
|
||||||
|
include_path_nodes = root.findall(".//IncludePath")
|
||||||
|
if not include_path_nodes:
|
||||||
|
self.log("未找到任何 IncludePath 节点,无法添加路径。")
|
||||||
|
return
|
||||||
|
|
||||||
|
updated = False
|
||||||
|
for index, include_path_node in enumerate(include_path_nodes):
|
||||||
|
if index == 0:
|
||||||
|
self.log("跳过第一组 IncludePath 节点,不进行修改。")
|
||||||
|
continue
|
||||||
|
|
||||||
|
include_paths = include_path_node.text.split(";") if include_path_node.text else []
|
||||||
|
if new_path in include_paths:
|
||||||
|
self.log(f"路径 '{new_path}' 已存在于第 {index + 1} 组 IncludePath 节点中,无需重复添加。")
|
||||||
|
continue
|
||||||
|
|
||||||
|
include_paths.append(new_path)
|
||||||
|
include_path_node.text = ";".join(include_paths)
|
||||||
|
updated = True
|
||||||
|
self.log(f"路径 '{new_path}' 已成功添加到第 {index + 1} 组 IncludePath 节点中。")
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
tree.write(project_file, encoding="utf-8", xml_declaration=True)
|
||||||
|
self.log(f"项目文件已更新:{project_file}")
|
||||||
|
else:
|
||||||
|
self.log("未对项目文件进行任何修改。")
|
||||||
|
|
||||||
|
|
||||||
# 复制文件
|
# 复制文件
|
||||||
def copy_file_from_repo(self, src_path, dest_path):
|
def copy_file_from_repo(self, src_path, dest_path):
|
||||||
try:
|
try:
|
||||||
@ -184,7 +305,8 @@ class MRobotApp:
|
|||||||
root.protocol("WM_DELETE_WINDOW", lambda: self.on_closing(root))
|
root.protocol("WM_DELETE_WINDOW", lambda: self.on_closing(root))
|
||||||
|
|
||||||
# 初始化 BooleanVar
|
# 初始化 BooleanVar
|
||||||
self.add_gitignore_var = tk.BooleanVar(value=True)
|
self.add_gitignore_var = tk.BooleanVar(value=False)
|
||||||
|
self.auto_configure_var = tk.BooleanVar(value=False) # 新增复选框变量
|
||||||
|
|
||||||
# 创建主框架
|
# 创建主框架
|
||||||
main_frame = ttk.Frame(root)
|
main_frame = ttk.Frame(root)
|
||||||
@ -223,16 +345,24 @@ class MRobotApp:
|
|||||||
self.message_box = tk.Text(bottom_frame, wrap="word", state="disabled", height=5, width=60)
|
self.message_box = tk.Text(bottom_frame, wrap="word", state="disabled", height=5, width=60)
|
||||||
self.message_box.pack(side="left", fill="x", expand=True, padx=5, pady=5)
|
self.message_box.pack(side="left", fill="x", expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
# 生成按钮和 .gitignore 选项
|
# 生成按钮和复选框选项
|
||||||
button_frame = ttk.Frame(bottom_frame)
|
button_frame = ttk.Frame(bottom_frame)
|
||||||
button_frame.pack(side="right", padx=10)
|
button_frame.pack(side="right", padx=10)
|
||||||
|
|
||||||
# 添加 .gitignore 复选框
|
# 添加复选框容器(横向排列复选框)
|
||||||
ttk.Checkbutton(button_frame, text="添加 .gitignore", variable=self.add_gitignore_var).pack(side="top", pady=5)
|
checkbox_frame = ttk.Frame(button_frame)
|
||||||
|
checkbox_frame.pack(side="top", pady=5)
|
||||||
|
|
||||||
# 添加生成按钮
|
# 添加 .gitignore 复选框(左侧)
|
||||||
|
ttk.Checkbutton(checkbox_frame, text=".gitignore", variable=self.add_gitignore_var).pack(side="left", padx=5)
|
||||||
|
|
||||||
|
# 添加自动配置环境复选框(右侧)
|
||||||
|
ttk.Checkbutton(checkbox_frame, text="自动环境", variable=self.auto_configure_var).pack(side="left", padx=5)
|
||||||
|
|
||||||
|
# 添加生成按钮(竖向排列在复选框下方)
|
||||||
generate_button = ttk.Button(button_frame, text="一键生成MRobot代码", command=self.generate_action)
|
generate_button = ttk.Button(button_frame, text="一键生成MRobot代码", command=self.generate_action)
|
||||||
generate_button.pack(side="top", pady=5)
|
generate_button.pack(side="top", pady=10)
|
||||||
|
generate_button.config(width=25) # 设置按钮宽度
|
||||||
|
|
||||||
# 重定向输出到消息框
|
# 重定向输出到消息框
|
||||||
self.redirect_output()
|
self.redirect_output()
|
||||||
@ -247,7 +377,6 @@ class MRobotApp:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def redirect_output(self):
|
def redirect_output(self):
|
||||||
"""
|
"""
|
||||||
重定向标准输出到消息框
|
重定向标准输出到消息框
|
||||||
@ -594,29 +723,29 @@ class MRobotApp:
|
|||||||
def task():
|
def task():
|
||||||
# 检查并创建目录(与 FreeRTOS 状态无关的模块始终创建)
|
# 检查并创建目录(与 FreeRTOS 状态无关的模块始终创建)
|
||||||
self.create_directories()
|
self.create_directories()
|
||||||
|
|
||||||
# 复制 .gitignore 文件
|
# 复制 .gitignore 文件
|
||||||
if self.add_gitignore_var.get():
|
if self.add_gitignore_var.get():
|
||||||
self.copy_file_from_repo(".gitignore", ".gitignore")
|
self.copy_file_from_repo(".gitignore", ".gitignore")
|
||||||
|
|
||||||
# 如果启用了 FreeRTOS,复制相关文件
|
# 如果启用了 FreeRTOS,复制相关文件
|
||||||
if self.ioc_data and self.check_freertos_enabled(self.ioc_data):
|
if self.ioc_data and self.check_freertos_enabled(self.ioc_data):
|
||||||
self.copy_file_from_repo("src/freertos.c", os.path.join("Core", "Src", "freertos.c"))
|
self.copy_file_from_repo("src/freertos.c", os.path.join("Core", "Src", "freertos.c"))
|
||||||
|
|
||||||
# 定义需要处理的文件夹(与 FreeRTOS 状态无关)
|
# 定义需要处理的文件夹(与 FreeRTOS 状态无关)
|
||||||
folders = ["bsp", "component", "device", "module"]
|
folders = ["bsp", "component", "device", "module"]
|
||||||
|
|
||||||
# 遍历每个文件夹,复制选中的 .h 和 .c 文件
|
# 遍历每个文件夹,复制选中的 .h 和 .c 文件
|
||||||
for folder in folders:
|
for folder in folders:
|
||||||
folder_dir = os.path.join(REPO_DIR, "User", folder)
|
folder_dir = os.path.join(REPO_DIR, "User", folder)
|
||||||
if not os.path.exists(folder_dir):
|
if not os.path.exists(folder_dir):
|
||||||
continue # 如果文件夹不存在,跳过
|
continue # 如果文件夹不存在,跳过
|
||||||
|
|
||||||
for file_name in os.listdir(folder_dir):
|
for file_name in os.listdir(folder_dir):
|
||||||
file_base, file_ext = os.path.splitext(file_name)
|
file_base, file_ext = os.path.splitext(file_name)
|
||||||
if file_ext not in [".h", ".c"]:
|
if file_ext not in [".h", ".c"]:
|
||||||
continue # 只处理 .h 和 .c 文件
|
continue # 只处理 .h 和 .c 文件
|
||||||
|
|
||||||
# 强制复制与文件夹同名的文件
|
# 强制复制与文件夹同名的文件
|
||||||
if file_base == folder:
|
if file_base == folder:
|
||||||
src_path = os.path.join(folder_dir, file_name)
|
src_path = os.path.join(folder_dir, file_name)
|
||||||
@ -624,30 +753,35 @@ class MRobotApp:
|
|||||||
self.copy_file_from_repo(src_path, dest_path)
|
self.copy_file_from_repo(src_path, dest_path)
|
||||||
print(f"强制复制与文件夹同名的文件: {file_name}")
|
print(f"强制复制与文件夹同名的文件: {file_name}")
|
||||||
continue # 跳过后续检查,直接复制
|
continue # 跳过后续检查,直接复制
|
||||||
|
|
||||||
# 检查是否选中了对应的文件
|
# 检查是否选中了对应的文件
|
||||||
if file_base in self.header_file_vars and self.header_file_vars[file_base].get():
|
if file_base in self.header_file_vars and self.header_file_vars[file_base].get():
|
||||||
src_path = os.path.join(folder_dir, file_name)
|
src_path = os.path.join(folder_dir, file_name)
|
||||||
dest_path = os.path.join("User", folder, file_name)
|
dest_path = os.path.join("User", folder, file_name)
|
||||||
self.copy_file_from_repo(src_path, dest_path)
|
self.copy_file_from_repo(src_path, dest_path)
|
||||||
|
|
||||||
# 如果启用了 FreeRTOS,执行任务相关的生成逻辑
|
# 如果启用了 FreeRTOS,执行任务相关的生成逻辑
|
||||||
if self.ioc_data and self.check_freertos_enabled(self.ioc_data):
|
if self.ioc_data and self.check_freertos_enabled(self.ioc_data):
|
||||||
# 修改 user_task.c 文件
|
# 修改 user_task.c 文件
|
||||||
self.modify_user_task_file()
|
self.modify_user_task_file()
|
||||||
|
|
||||||
# 生成 user_task.h 文件
|
# 生成 user_task.h 文件
|
||||||
self.generate_user_task_header()
|
self.generate_user_task_header()
|
||||||
|
|
||||||
# 生成 init.c 文件
|
# 生成 init.c 文件
|
||||||
self.generate_init_file()
|
self.generate_init_file()
|
||||||
|
|
||||||
# 生成 task.c 文件
|
# 生成 task.c 文件
|
||||||
self.generate_task_files()
|
self.generate_task_files()
|
||||||
|
|
||||||
threading.Thread(target=task).start()
|
# 自动配置环境
|
||||||
|
if self.auto_configure_var.get():
|
||||||
|
|
||||||
|
self.auto_configure_environment()
|
||||||
|
|
||||||
|
|
||||||
|
threading.Thread(target=task).start()
|
||||||
|
|
||||||
# 程序关闭时清理
|
# 程序关闭时清理
|
||||||
def on_closing(self, root):
|
def on_closing(self, root):
|
||||||
self.delete_repo()
|
self.delete_repo()
|
||||||
|
Loading…
Reference in New Issue
Block a user