refactor(flash-gui): 对齐 DLPilot 重构 GUI 并内置 OpenOCD 发布链
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
组装 DAPLink Flash 发布包: exe + 内置 OpenOCD 工具链 → 文件夹 + zip(解压即用)
|
||||
================================================================
|
||||
release/ 本身就是可直接使用的完整文件夹(exe + toolchain/ + 说明),
|
||||
再原样压成 zip —— 两者内容始终一致。
|
||||
|
||||
zip 解压后根目录为 DAPLinkFlash/, 与 exe 运行目录结构一致:
|
||||
DAPLinkFlash/
|
||||
├── DAPLinkFlash.exe 主程序(先运行 build_exe.py 打包)
|
||||
├── toolchain/openocd/ 内置 OpenOCD(bin + scripts, GUI 自动定位)
|
||||
└── README.md 使用说明
|
||||
|
||||
OpenOCD 来源(--openocd-src > 环境变量 OPENOCD_SRC > 自动探测):
|
||||
1. FlashTool/toolchain/openocd (随仓库自带, 若已 vendor)
|
||||
2. D:/toolchain/openocd (开发机本机安装)
|
||||
目录布局: <src>/bin/openocd.exe + <src>/openocd/scripts/
|
||||
|
||||
用法:
|
||||
python package_release.py 版本号自动取最近 git tag(DAPLinkFlash-v*)
|
||||
python package_release.py 0.1.0 手动指定版本号
|
||||
python package_release.py 0.1.0 --openocd-src D:/toolchain/openocd
|
||||
产物: release/DAPLinkFlash-v<版本>-win64.zip(zip 不入库, 上传到 Gitea Release)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
SRC = os.path.dirname(os.path.abspath(__file__))
|
||||
BASE = os.path.dirname(SRC)
|
||||
RELEASE = os.path.join(BASE, 'release')
|
||||
APP_NAME = 'DAPLinkFlash'
|
||||
|
||||
|
||||
def detect_version():
|
||||
"""从最近的 DAPLinkFlash-v* tag 推断版本号, 无 tag 则报错提示手动指定"""
|
||||
try:
|
||||
out = subprocess.check_output(
|
||||
['git', 'describe', '--tags', '--abbrev=0', '--match', 'DAPLinkFlash-v*'],
|
||||
cwd=BASE, stderr=subprocess.DEVNULL)
|
||||
return out.decode().strip().removeprefix(APP_NAME + '-v')
|
||||
except Exception:
|
||||
sys.exit('未能从 git tag 推断版本号, 请手动指定: '
|
||||
'python package_release.py <版本号>')
|
||||
|
||||
|
||||
def resolve_openocd_src(explicit):
|
||||
"""定位 OpenOCD 工具链源目录, 校验布局并返回路径"""
|
||||
candidates = [explicit, os.environ.get('OPENOCD_SRC'),
|
||||
os.path.join(BASE, 'toolchain', 'openocd'),
|
||||
r'D:/toolchain/openocd']
|
||||
for cand in candidates:
|
||||
if not cand:
|
||||
continue
|
||||
exe = os.path.join(cand, 'bin', 'openocd.exe')
|
||||
scripts = os.path.join(cand, 'openocd', 'scripts')
|
||||
if os.path.isfile(exe) and os.path.isdir(scripts):
|
||||
print(f'OpenOCD 工具链来源: {os.path.abspath(cand)}')
|
||||
return os.path.abspath(cand)
|
||||
sys.exit('未找到 OpenOCD 工具链(需 bin/openocd.exe + openocd/scripts/):\n'
|
||||
' python package_release.py <版本> --openocd-src <toolchain/openocd 目录>\n'
|
||||
' 或设置环境变量 OPENOCD_SRC')
|
||||
|
||||
|
||||
def copy_toolchain(openocd_src):
|
||||
"""复制 bin(openocd.exe + 运行 DLL)与 openocd/scripts 到 release/toolchain/"""
|
||||
dst_root = os.path.join(RELEASE, 'toolchain', 'openocd')
|
||||
if os.path.isdir(dst_root):
|
||||
shutil.rmtree(dst_root)
|
||||
count = 0
|
||||
for sub in ('bin', os.path.join('openocd', 'scripts')):
|
||||
src = os.path.join(openocd_src, sub)
|
||||
dst = os.path.join(dst_root, sub)
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
shutil.copytree(src, dst)
|
||||
for _root, _dirs, files in os.walk(dst):
|
||||
count += len(files)
|
||||
return count
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('version', nargs='?', default=None,
|
||||
help='版本号, 默认取最近 DAPLinkFlash-v* git tag')
|
||||
ap.add_argument('--openocd-src', default=None,
|
||||
help='OpenOCD 工具链目录(含 bin/ 与 openocd/scripts/)')
|
||||
args = ap.parse_args()
|
||||
|
||||
version = (args.version or detect_version()).lstrip('v')
|
||||
exe = os.path.join(RELEASE, APP_NAME + '.exe')
|
||||
readme = os.path.join(BASE, 'README.md')
|
||||
if not os.path.exists(exe):
|
||||
sys.exit(f'缺少 release/{APP_NAME}.exe, 先运行: python build_exe.py')
|
||||
if not os.path.exists(readme):
|
||||
sys.exit(f'缺少 {readme}')
|
||||
openocd_src = resolve_openocd_src(args.openocd_src)
|
||||
|
||||
n_files = copy_toolchain(openocd_src)
|
||||
shutil.copy2(readme, os.path.join(RELEASE, 'README.md'))
|
||||
|
||||
zip_name = f'{APP_NAME}-v{version}-win64.zip'
|
||||
zip_path = os.path.join(RELEASE, zip_name)
|
||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as z:
|
||||
z.write(exe, f'{APP_NAME}/{APP_NAME}.exe')
|
||||
z.write(os.path.join(RELEASE, 'README.md'), f'{APP_NAME}/README.md')
|
||||
tool_root = os.path.join(RELEASE, 'toolchain')
|
||||
for root, _dirs, files in os.walk(tool_root):
|
||||
for f in files:
|
||||
full = os.path.join(root, f)
|
||||
z.write(full, os.path.join(APP_NAME, os.path.relpath(full, RELEASE)))
|
||||
|
||||
exe_mb = os.path.getsize(exe) / 1024 / 1024
|
||||
zip_mb = os.path.getsize(zip_path) / 1024 / 1024
|
||||
print(f'发布文件夹: {RELEASE} (exe {exe_mb:.1f} MB + 内置工具链 {n_files} 个文件, 平铺即用)')
|
||||
print(f'发布包: {zip_path} ({zip_mb:.1f} MB)')
|
||||
print('下一步上传: python publish_gitea.py', zip_name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user