mirror of
https://github.com/Dev-Wiki/HarmonyDevTools.git
synced 2025-08-30 01:14:44 +08:00
324 lines
11 KiB
Python
324 lines
11 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
HarmonyDevTools Python版本打包脚本
|
||
用于将Python项目打包为exe文件
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import subprocess
|
||
import shutil
|
||
import re
|
||
import zipfile
|
||
from pathlib import Path
|
||
|
||
def check_pyinstaller():
|
||
"""检查PyInstaller是否已安装"""
|
||
try:
|
||
import PyInstaller
|
||
return True
|
||
except ImportError:
|
||
return False
|
||
|
||
def install_pyinstaller():
|
||
"""安装PyInstaller"""
|
||
print("正在安装PyInstaller...")
|
||
try:
|
||
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
|
||
print("PyInstaller安装成功!")
|
||
return True
|
||
except subprocess.CalledProcessError:
|
||
print("PyInstaller安装失败!")
|
||
return False
|
||
|
||
def get_version_from_version_info():
|
||
"""从version_info.txt文件中获取版本号"""
|
||
if not os.path.exists("version_info.txt"):
|
||
return "1.0.0"
|
||
|
||
try:
|
||
with open("version_info.txt", 'r', encoding='utf-8') as f:
|
||
content = f.read()
|
||
match = re.search(r"StringStruct\(u'FileVersion', u'([^']+)'\)", content)
|
||
if match:
|
||
return match.group(1)
|
||
except Exception as e:
|
||
print(f"读取version_info.txt版本信息失败: {e}")
|
||
|
||
return "1.0.0"
|
||
|
||
def build_with_version(main_file, exe_name, version):
|
||
"""使用指定版本号构建exe文件"""
|
||
# 构建命令
|
||
cmd = [
|
||
"pyinstaller",
|
||
"--onefile", # 打包为单个文件
|
||
"--windowed", # 无控制台窗口
|
||
f"--name={exe_name}", # 输出文件名
|
||
"--icon=icon.ico", # 图标文件(如果存在)
|
||
"--version-file=version_info.txt", # 版本信息文件
|
||
"--add-data=toolchains;toolchains", # 包含toolchains目录
|
||
main_file
|
||
]
|
||
|
||
# 如果图标文件不存在,移除图标参数
|
||
if not os.path.exists("icon.ico"):
|
||
cmd = [arg for arg in cmd if not arg.startswith("--icon")]
|
||
|
||
# 如果版本信息文件不存在,移除版本信息参数
|
||
if not os.path.exists("version_info.txt"):
|
||
cmd = [arg for arg in cmd if not arg.startswith("--version-file")]
|
||
|
||
return cmd
|
||
|
||
def get_version_for_filename(version):
|
||
"""将版本号转换为文件名格式(只取前三位)"""
|
||
parts = version.split('.')
|
||
if len(parts) >= 3:
|
||
return f"{parts[0]}.{parts[1]}.{parts[2]}"
|
||
return version
|
||
|
||
def build_exe():
|
||
"""构建exe文件"""
|
||
print("开始构建exe文件...")
|
||
|
||
# 检查主程序文件是否存在
|
||
if not os.path.exists("main.py"):
|
||
print("错误:找不到main.py文件!")
|
||
return False
|
||
|
||
# 从version_info.txt获取版本号
|
||
version = get_version_from_version_info()
|
||
version_for_filename = get_version_for_filename(version)
|
||
main_file = "main.py"
|
||
exe_name = f"HarmonyDevTools_v{version_for_filename}"
|
||
print(f"构建HarmonyDevTools v{version}...")
|
||
|
||
# 检查toolchains目录是否存在
|
||
if not os.path.exists("toolchains"):
|
||
print("警告:找不到toolchains目录,请确保包含hdc.exe文件")
|
||
|
||
# 构建命令
|
||
cmd = build_with_version(main_file, exe_name, version_for_filename)
|
||
|
||
try:
|
||
subprocess.check_call(cmd)
|
||
print("构建成功!")
|
||
return exe_name
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"构建失败:{e}")
|
||
return False
|
||
|
||
def create_distribution(exe_name="HarmonyDevTools"):
|
||
"""创建发布包"""
|
||
print("创建发布包...")
|
||
|
||
# 直接使用dist目录作为发布目录
|
||
dist_dir = "dist"
|
||
if not os.path.exists(dist_dir):
|
||
os.makedirs(dist_dir)
|
||
|
||
# 复制toolchains目录到dist
|
||
if os.path.exists("toolchains"):
|
||
toolchains_dest = os.path.join(dist_dir, "toolchains")
|
||
if os.path.exists(toolchains_dest):
|
||
shutil.rmtree(toolchains_dest)
|
||
shutil.copytree("toolchains", toolchains_dest)
|
||
print("已复制toolchains目录到dist")
|
||
|
||
# 创建适合exe发布包的README
|
||
create_release_readme(dist_dir)
|
||
|
||
print(f"发布包已创建:{dist_dir}")
|
||
print("发布包包含:")
|
||
print(f"- {exe_name}.exe")
|
||
print("- toolchains/目录")
|
||
print("- README.md")
|
||
return True
|
||
|
||
def create_release_readme(dist_dir):
|
||
"""创建发布版README文件"""
|
||
# 获取当前版本号
|
||
version = get_version_from_version_info()
|
||
version_for_filename = get_version_for_filename(version)
|
||
version_underscore = version_for_filename.replace('.', '_')
|
||
|
||
readme_content = f"""# HarmonyDevTools
|
||
|
||
HarmonyOS/OpenHarmony开发工具,提供图形化界面操作HDC工具。
|
||
|
||
## 功能特性
|
||
|
||
- **设备管理**: 列举设备、连接设备、重启HDC服务
|
||
- **应用管理**: 安装/卸载HarmonyOS应用包
|
||
- **文件操作**: 导出设备照片、导出应用日志
|
||
- **系统信息**: 获取设备UDID、查看版本信息
|
||
- **命令执行**: 支持执行任意HDC命令
|
||
|
||
## 使用方法
|
||
|
||
1. **启动程序**: 双击 `HarmonyDevTools_v{version_underscore}.exe` 启动程序
|
||
2. **连接设备**: 点击"列举设备"查看可用设备,输入connect key后点击"连接设备"
|
||
3. **安装应用**: 选择hap文件,设置安装选项后点击"安装hap"
|
||
4. **导出文件**: 点击"导出照片"或"导出日志"从设备导出文件
|
||
|
||
## 系统要求
|
||
|
||
- Windows 10/11
|
||
- 无需安装Python或其他依赖
|
||
- 需要HarmonyOS/OpenHarmony设备
|
||
|
||
## 注意事项
|
||
|
||
- 首次使用前请确保设备已开启开发者模式
|
||
- 确保toolchains目录包含hdc.exe文件
|
||
- 导出文件会自动创建时间戳目录并打开文件夹
|
||
|
||
## 故障排除
|
||
|
||
1. **无法连接设备**: 检查设备是否开启USB调试,尝试重启HDC服务
|
||
2. **安装失败**: 检查hap文件是否有效,确认设备存储空间充足
|
||
3. **导出失败**: 确认设备路径正确,检查文件权限
|
||
|
||
---
|
||
基于原C# WPF项目转换的Python Tkinter版本
|
||
版本: {version}
|
||
"""
|
||
|
||
readme_path = os.path.join(dist_dir, "README.md")
|
||
with open(readme_path, "w", encoding="utf-8") as f:
|
||
f.write(readme_content)
|
||
print("已创建发布版README.md")
|
||
|
||
def create_zip_package(exe_name, dist_dir):
|
||
"""创建zip压缩包"""
|
||
print("创建zip压缩包...")
|
||
|
||
# 获取版本号用于zip文件名
|
||
version = get_version_from_version_info()
|
||
version_for_filename = get_version_for_filename(version)
|
||
zip_filename = f"HarmonyDevTools_v{version_for_filename}.zip"
|
||
zip_path = os.path.join(dist_dir, zip_filename)
|
||
|
||
# 创建zip文件
|
||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||
# 添加exe文件到HarmonyDevTools_v1.4.0目录下
|
||
exe_path = os.path.join(dist_dir, f"{exe_name}.exe")
|
||
if os.path.exists(exe_path):
|
||
zipf.write(exe_path, f"HarmonyDevTools_v{version_for_filename}/{exe_name}.exe")
|
||
print(f"已添加 {exe_name}.exe 到压缩包")
|
||
|
||
# 添加toolchains目录下的文件到HarmonyDevTools_v1.4.0/toolchains目录
|
||
toolchains_dir = os.path.join(dist_dir, "toolchains")
|
||
if os.path.exists(toolchains_dir):
|
||
for root, dirs, files in os.walk(toolchains_dir):
|
||
for file in files:
|
||
file_path = os.path.join(root, file)
|
||
# 计算相对路径,去掉dist前缀
|
||
rel_path = os.path.relpath(file_path, dist_dir)
|
||
# 在zip中创建toolchains子目录
|
||
arcname = f"HarmonyDevTools_v{version_for_filename}/{rel_path}"
|
||
zipf.write(file_path, arcname)
|
||
print(f"已添加 {arcname} 到压缩包")
|
||
|
||
# 添加README.md到HarmonyDevTools_v1.4.0目录下
|
||
readme_path = os.path.join(dist_dir, "README.md")
|
||
if os.path.exists(readme_path):
|
||
zipf.write(readme_path, f"HarmonyDevTools_v{version_for_filename}/README.md")
|
||
print("已添加 README.md 到压缩包")
|
||
|
||
print(f"zip压缩包创建成功:{zip_path}")
|
||
return zip_filename
|
||
|
||
|
||
def clean_build_files():
|
||
"""清理构建文件"""
|
||
print("清理构建文件...")
|
||
|
||
# 清理所有构建相关的临时文件
|
||
dirs_to_clean = ["build", "__pycache__"]
|
||
files_to_clean = ["HarmonyDevTools.spec", "HarmonyDevTools_Enhanced.spec"]
|
||
|
||
for dir_name in dirs_to_clean:
|
||
if os.path.exists(dir_name):
|
||
shutil.rmtree(dir_name)
|
||
print(f"已删除目录:{dir_name}")
|
||
|
||
for file_name in files_to_clean:
|
||
if os.path.exists(file_name):
|
||
os.remove(file_name)
|
||
print(f"已删除文件:{file_name}")
|
||
|
||
print("清理完成")
|
||
|
||
def clean_after_build(exe_name):
|
||
"""构建完成后清理临时文件"""
|
||
print("清理构建临时文件...")
|
||
|
||
# 清理build目录
|
||
if os.path.exists("build"):
|
||
shutil.rmtree("build")
|
||
print("已删除build目录")
|
||
|
||
# 清理spec文件
|
||
spec_files = [f"{exe_name}.spec"]
|
||
for spec_file in spec_files:
|
||
if os.path.exists(spec_file):
|
||
os.remove(spec_file)
|
||
print(f"已删除文件:{spec_file}")
|
||
|
||
print("构建后清理完成")
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("=" * 50)
|
||
print("HarmonyDevTools Python版本打包工具")
|
||
print("=" * 50)
|
||
|
||
# 检查Python版本
|
||
if sys.version_info < (3, 7):
|
||
print("错误:需要Python 3.7或更高版本!")
|
||
return
|
||
|
||
print(f"Python版本:{sys.version}")
|
||
|
||
# 检查PyInstaller
|
||
if not check_pyinstaller():
|
||
print("PyInstaller未安装")
|
||
choice = input("是否自动安装PyInstaller?(y/n): ").lower()
|
||
if choice == 'y':
|
||
if not install_pyinstaller():
|
||
return
|
||
else:
|
||
print("请手动安装PyInstaller:pip install pyinstaller")
|
||
return
|
||
|
||
# 自动清理之前的构建文件
|
||
if os.path.exists("build") or os.path.exists("dist"):
|
||
print("清理之前的构建文件...")
|
||
clean_build_files()
|
||
|
||
# 构建exe文件
|
||
exe_name = build_exe()
|
||
if exe_name:
|
||
# 自动创建发布包
|
||
create_distribution(exe_name)
|
||
|
||
# 创建zip压缩包
|
||
zip_filename = create_zip_package(exe_name, "dist")
|
||
|
||
# 构建完成后清理临时文件
|
||
clean_after_build(exe_name)
|
||
|
||
print("\n构建完成!")
|
||
print(f"exe文件位置:dist/{exe_name}.exe")
|
||
print(f"zip压缩包:{zip_filename}")
|
||
print("发布包位置:dist/目录")
|
||
print("可以直接分发dist目录或zip压缩包作为完整的发布包")
|
||
else:
|
||
print("构建失败!")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|