orc-order-v2/build_exe.py

336 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
OCR订单处理系统 - EXE打包脚本
============================
自动化打包脚本,包含所有必要的资源文件和配置
"""
import os
import sys
import shutil
import subprocess
from pathlib import Path
def clean_build():
"""清理之前的构建文件"""
print("清理构建目录...")
dirs_to_clean = ['build', 'dist', '__pycache__']
for dir_name in dirs_to_clean:
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
print(f"已删除: {dir_name}")
# 删除spec文件
spec_files = [f for f in os.listdir('.') if f.endswith('.spec')]
for spec_file in spec_files:
os.remove(spec_file)
print(f"已删除: {spec_file}")
def create_spec_file():
"""创建PyInstaller spec文件"""
spec_content = '''
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# 需要包含的数据文件
added_files = [
('config.ini', '.'),
('config/barcode_mappings.json', 'config/'),
('config/config.ini', 'config/'),
('templates/银豹-采购单模板.xls', 'templates/'),
('app', 'app'),
]
# 需要隐式导入的模块
hidden_imports = [
'tkinter',
'tkinter.ttk',
'tkinter.filedialog',
'tkinter.messagebox',
'tkinter.scrolledtext',
'pandas',
'numpy',
'openpyxl',
'xlrd',
'xlwt',
'xlutils',
'requests',
'configparser',
'threading',
'datetime',
'json',
're',
'subprocess',
'shutil',
'app.config.settings',
'app.services.ocr_service',
'app.services.order_service',
'app.services.tobacco_service',
'app.core.utils.dialog_utils',
'app.core.excel.converter',
]
a = Analysis(
['启动器.py'],
pathex=[],
binaries=[],
datas=added_files,
hiddenimports=hidden_imports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='OCR订单处理系统',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
'''
with open('OCR订单处理系统.spec', 'w', encoding='utf-8') as f:
f.write(spec_content)
print("已创建spec文件: OCR订单处理系统.spec")
def build_exe():
"""构建EXE文件"""
print("开始构建EXE文件...")
try:
# 注入版本信息到根config.ini
try:
root_cfg = Path('config.ini')
from datetime import datetime
version_str = datetime.now().strftime('%Y.%m.%d.%H%M')
if root_cfg.exists():
lines = root_cfg.read_text(encoding='utf-8').splitlines()
has_app = any(l.strip().lower() == '[app]' for l in lines)
if not has_app:
lines.append('[App]')
lines.append(f'version = {version_str}')
else:
# 更新或追加version
new_lines = []
in_app = False
app_written = False
for l in lines:
if l.strip().lower() == '[app]':
in_app = True
new_lines.append(l)
continue
if in_app and l.strip().lower().startswith('version'):
new_lines.append(f'version = {version_str}')
app_written = True
in_app = True
continue
new_lines.append(l)
if not app_written:
new_lines.append('version = ' + version_str)
lines = new_lines
root_cfg.write_text('\n'.join(lines), encoding='utf-8')
print(f"已写入版本号: {version_str}")
except Exception as e:
print(f"版本信息注入失败: {e}")
result = subprocess.run([
'pyinstaller',
'OCR订单处理系统.spec'
], check=True, capture_output=True, text=True)
print("构建成功!")
print(result.stdout)
# 构建完成后复制完整的配置文件到dist目录
dist_dir = Path('dist')
# 复制包含API密钥的配置文件
config_file = Path('config/config.ini')
if config_file.exists():
# 确保config目录存在
(dist_dir / 'config').mkdir(exist_ok=True)
shutil.copy2(config_file, dist_dir / 'config')
print(f"已复制配置文件到dist: {config_file} -> {dist_dir / 'config'}")
# 复制完整的条码映射文件
barcode_mapping_file = Path('config/barcode_mappings.json')
if barcode_mapping_file.exists():
shutil.copy2(barcode_mapping_file, dist_dir / 'config')
print(f"已复制条码映射文件到dist: {barcode_mapping_file} -> {dist_dir / 'config'}")
# 复制根目录的config.ini文件覆盖空的配置文件
root_config_file = Path('config.ini')
if root_config_file.exists():
shutil.copy2(root_config_file, dist_dir)
print(f"已复制根配置文件到dist: {root_config_file} -> {dist_dir}")
else:
print("警告: 根配置文件不存在,将创建缺省版本")
(dist_dir / 'config.ini').write_text('[App]\nversion = dev\n', encoding='utf-8')
except subprocess.CalledProcessError as e:
print(f"构建失败: {e}")
print(f"错误输出: {e.stderr}")
return False
return True
def create_portable_package():
"""创建便携版打包"""
print("创建便携版打包...")
# 创建发布目录
release_dir = Path('release')
if release_dir.exists():
try:
shutil.rmtree(release_dir)
except Exception as e:
print(f"警告: 无法完全清理发布目录 (可能文件被占用): {e}")
# 如果目录还在,尝试清理能清理的部分
for item in release_dir.iterdir():
try:
if item.is_dir(): shutil.rmtree(item)
else: item.unlink()
except Exception: pass
release_dir.mkdir(exist_ok=True)
# 复制exe文件
exe_file = Path('dist/OCR订单处理系统.exe')
if exe_file.exists():
shutil.copy2(exe_file, release_dir)
print(f"已复制: {exe_file} -> {release_dir}")
# 创建必要的目录结构
dirs_to_create = ['data/input', 'data/output', 'logs', 'templates', 'config']
for dir_path in dirs_to_create:
(release_dir / dir_path).mkdir(parents=True, exist_ok=True)
print(f"已创建目录: {dir_path}")
# 复制配置文件包含API密钥
config_file = Path('config/config.ini')
if config_file.exists():
shutil.copy2(config_file, release_dir / 'config')
print(f"已复制配置文件: {config_file} -> {release_dir / 'config'}")
else:
print(f"警告: 配置文件不存在: {config_file}")
# 复制完整的条码映射文件
barcode_mapping_file = Path('config/barcode_mappings.json')
if barcode_mapping_file.exists():
shutil.copy2(barcode_mapping_file, release_dir / 'config')
print(f"已复制条码映射文件: {barcode_mapping_file} -> {release_dir / 'config'}")
else:
print(f"警告: 条码映射文件不存在: {barcode_mapping_file}")
# 复制根目录的config.ini文件
root_config_file = Path('config.ini')
if root_config_file.exists():
shutil.copy2(root_config_file, release_dir)
print(f"已复制根配置文件: {root_config_file} -> {release_dir}")
else:
print(f"警告: 根配置文件不存在: {root_config_file}")
# 复制模板文件
template_file = Path('templates/银豹-采购单模板.xls')
if template_file.exists():
shutil.copy2(template_file, release_dir / 'templates')
print(f"已复制模板文件: {template_file} -> {release_dir / 'templates'}")
else:
print(f"警告: 模板文件不存在: {template_file}")
item_file = Path('templates/商品资料.xlsx')
if item_file.exists():
try:
(Path('dist') / 'templates').mkdir(exist_ok=True)
shutil.copy2(item_file, Path('dist') / 'templates')
except Exception:
pass
shutil.copy2(item_file, release_dir / 'templates')
print(f"已复制商品资料: {item_file} -> {release_dir / 'templates'}")
else:
print(f"警告: 商品资料文件不存在: {item_file}")
# 创建README文件
readme_content = '''
# OCR订单处理系统 - 便携版
## 使用说明
1. 双击 "OCR订单处理系统.exe" 启动程序
2. 将需要处理的图片文件放入 data/input 目录
3. 处理结果将保存在 data/output 目录
4. 日志文件保存在 logs 目录
## 注意事项
- 首次运行时需要配置百度OCR API密钥
- 支持的图片格式jpg, jpeg, png, bmp
- 单个文件大小不超过4MB
## 目录结构
- OCR订单处理系统.exe - 主程序
- data/input/ - 输入图片目录
- data/output/ - 输出结果目录
- logs/ - 日志目录
'''
with open(release_dir / 'README.txt', 'w', encoding='utf-8') as f:
f.write(readme_content)
print("已创建README.txt")
print(f"便携版打包完成,位置: {release_dir.absolute()}")
def main():
"""主函数"""
print("=" * 50)
print("OCR订单处理系统 - EXE打包工具")
print("=" * 50)
# 检查是否安装了PyInstaller
try:
subprocess.run(['pyinstaller', '--version'], check=True, capture_output=True)
except (subprocess.CalledProcessError, FileNotFoundError):
print("错误: 未安装PyInstaller")
print("请运行: pip install pyinstaller")
return 1
# 清理构建目录
clean_build()
# 创建spec文件
create_spec_file()
# 构建EXE
if not build_exe():
return 1
# 创建便携版打包
create_portable_package()
print("\n" + "=" * 50)
print("打包完成!")
print("EXE文件位置: dist/OCR订单处理系统.exe")
print("便携版位置: release/")
print("=" * 50)
return 0
if __name__ == '__main__':
sys.exit(main())