commit 8dc4632f33bcb857edfce69a1e7e4d52b0687a57 Author: admin Date: Tue May 6 21:36:49 2025 +0800 添加 McuVersionGen.py diff --git a/McuVersionGen.py b/McuVersionGen.py new file mode 100644 index 0000000..68eda64 --- /dev/null +++ b/McuVersionGen.py @@ -0,0 +1,154 @@ +import re +import subprocess +import os +import sys +import datetime +import io +import locale + +system_encoding = locale.getpreferredencoding(False) +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding=system_encoding) + +# 语义化版本 https://semver.org/lang/zh-CN/spec/v2.0.0.html +default_major_version = 0 # 主版本号 +defalut_minor_version = 1 # 次版本号 +defalut_revision_version = 0 # 修订版本号 +defalut_pre_release_version = "" # 预发行版本号 + + +def get_version_from_file(path): + """从项目根目录的version.txt文件中读取版本信息""" + version_file = os.path.join(path, "version.txt") + + # 默认版本号 + versions = { + "major_version": default_major_version, + "minor_version": defalut_minor_version, + "revision_version": defalut_revision_version, + "pre_release_version": defalut_pre_release_version + } + + # 检查文件是否存在 + if not os.path.exists(version_file): + # 创建默认version.txt文件 + try: + with open(version_file, 'w', encoding='utf-8') as f: + f.write(f"major_version={versions['major_version']}\n") + f.write(f"minor_version={versions['minor_version']}\n") + f.write(f"revision_version={versions['revision_version']}\n") + f.write( + f"pre_release_version={versions['pre_release_version']}\n") + print(f"已在项目根目录创建默认的version.txt文件") + except Exception as e: + print(f"创建version.txt文件失败: {str(e)}") + return versions + + # 读取version.txt文件 + try: + with open(version_file, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + + if key in versions: + # 处理整数类型的版本号 + if key != "pre_release_version": + try: + versions[key] = int(value) + except ValueError: + raise ValueError( + f"版本号解析错误: {key}必须是整数,当前值为'{value}'") + else: + versions[key] = value + except Exception as e: + raise Exception(f"解析version.txt文件失败: {str(e)}") + + return versions + + +def generate_version_file(name, path, file_version, file_build_time): + if not os.path.exists(f"{path}/Core/App/AutoGen/"): + os.makedirs(f"{path}/Core/App/AutoGen/", exist_ok=True) + + with open(f"{path}/Core/App/AutoGen/autogen_version.c", "w", encoding="utf-8") as f: + f.write("// 这个文件是自动生成的\n") + f.write("// 对它作任何修改都将在编译前由程序自动覆盖\n") + f.write("// 不需要修改这个文件的内容\n") + f.write("\n") + f.write(f'const char *g_name = "{name}";\n') + f.write(f'const char *g_version = "{file_version}";\n') + f.write(f'const char *g_buildTime = "{file_build_time}";\n') + + +def generate_version(path): + # 从version.txt获取版本信息 + try: + versions = get_version_from_file(path) + major_version = versions["major_version"] + minor_version = versions["minor_version"] + revision_version = versions["revision_version"] + pre_release_version = versions["pre_release_version"] + except Exception as e: + print(f"错误: {str(e)}") + sys.exit(-1) + + generated_version = f"{major_version}.{minor_version}.{revision_version}" + git_commit_id = "" + # 检查是否在Git仓库中 + git_process = subprocess.run( + ["git", "rev-parse"], capture_output=True, text=True, cwd=path) + if git_process.returncode == 0: + # 检查是否有未提交的更改 + commit_process = subprocess.run( + ["git", "status", "-s"], capture_output=True, text=True, cwd=path) + if commit_process.stdout != "": + # 有未提交的更改,获取当前commit id并加* + process = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], capture_output=True, text=True, cwd=path) + git_commit_id = process.stdout.strip() + "*" + else: + # 没有未提交的更改,直接获取当前commit id + process = subprocess.run(["git", "rev-parse", "--short=8", "HEAD"], capture_output=True, text=True, + cwd=path) + git_commit_id = process.stdout.strip() + + # 根据 pre_release_version 和 git_commit_id 更新版本号 + if pre_release_version and git_commit_id: + generated_version += f"-{pre_release_version}+{git_commit_id}" + elif pre_release_version: + generated_version += f"-{pre_release_version}" + elif git_commit_id: + generated_version += f"+{git_commit_id}" + + # https://regex101.com/r/Ly7O1x/3/ + semver_regex = ( + r"^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[" + r"a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[" + r"0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*|\*|.*\*))?$") + + if not re.match(semver_regex, generated_version): + print(f"生成的版本号 {generated_version} 不符合语义化版本规范") + + return generated_version + + +if __name__ == "__main__": + try: + name = sys.argv[1] if len(sys.argv) > 1 else 'McuProgram' + project_directory = sys.argv[2] if len(sys.argv) > 2 else '.' + if not os.path.isdir(project_directory): + raise Exception("Invalid project directory") + version = generate_version(project_directory) + build_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + generate_version_file( + name, project_directory, version, build_time) + print(f"Program name: {name}") + print(f"Version: {version}") + print(f"Build time: {build_time}") + sys.exit(0) + except Exception as e: + print(e) + sys.exit(-1)