200 lines
4.8 KiB
Python
200 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
应用打包脚本 - 将Python应用打包为可执行文件
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
def check_dependencies():
|
|
"""检查必要的依赖"""
|
|
try:
|
|
import PyInstaller
|
|
print("OK PyInstaller 已安装")
|
|
except ImportError:
|
|
print("正在安装 PyInstaller...")
|
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
|
|
print("OK PyInstaller 安装完成")
|
|
|
|
def create_spec_file():
|
|
"""创建 PyInstaller spec 文件"""
|
|
spec_content = '''
|
|
# -*- mode: python ; coding: utf-8 -*-
|
|
|
|
block_cipher = None
|
|
|
|
a = Analysis(
|
|
['main.py'],
|
|
pathex=[],
|
|
binaries=[],
|
|
datas=[
|
|
('app', 'app'),
|
|
('uploads', 'uploads'),
|
|
('logs', 'logs'),
|
|
],
|
|
hiddenimports=[
|
|
'uvicorn',
|
|
'fastapi',
|
|
'sqlalchemy',
|
|
'pymysql',
|
|
'pydantic',
|
|
'pydantic_settings',
|
|
'redis',
|
|
'passlib',
|
|
'python_jose',
|
|
'uvicorn.protocols.http.httptools_impl',
|
|
],
|
|
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='cloud-drive-server',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=True,
|
|
upx_exclude=[],
|
|
runtime_tmpdir=None,
|
|
console=True,
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
icon=None
|
|
)
|
|
'''
|
|
|
|
with open('cloud-drive-server.spec', 'w', encoding='utf-8') as f:
|
|
f.write(spec_content)
|
|
print("OK 创建了 cloud-drive-server.spec 文件")
|
|
|
|
def build_executable():
|
|
"""构建可执行文件"""
|
|
print("开始构建可执行文件...")
|
|
|
|
try:
|
|
# 使用 PyInstaller 构建
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'PyInstaller',
|
|
'--clean',
|
|
'--noconfirm',
|
|
'cloud-drive-server.spec'
|
|
], capture_output=True, text=True)
|
|
|
|
if result.returncode == 0:
|
|
print("OK 可执行文件构建成功")
|
|
print("输出目录: dist/")
|
|
return True
|
|
else:
|
|
print("ERROR 构建失败:")
|
|
print(result.stdout)
|
|
print(result.stderr)
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"ERROR 构建过程中出现错误: {e}")
|
|
return False
|
|
|
|
def create_dockerfile_for_executable():
|
|
"""为可执行文件创建最小化的 Dockerfile"""
|
|
dockerfile_content = '''# 最小化运行环境 - 使用可执行文件
|
|
FROM alpine:latest
|
|
|
|
# 安装运行时依赖
|
|
RUN apk add --no-cache \\
|
|
curl \\
|
|
tzdata \\
|
|
ca-certificates \\
|
|
&& rm -rf /var/cache/apk/*
|
|
|
|
# 设置时区
|
|
ENV TZ=Asia/Shanghai
|
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
|
|
|
# 创建应用用户
|
|
RUN adduser -D -s /bin/sh app
|
|
|
|
# 设置工作目录
|
|
WORKDIR /app
|
|
|
|
# 复制可执行文件
|
|
COPY dist/cloud-drive-server /app/cloud-drive-server
|
|
|
|
# 创建必要的目录
|
|
RUN mkdir -p /app/uploads /app/logs \\
|
|
&& chown -R app:app /app
|
|
|
|
# 切换到非root用户
|
|
USER app
|
|
|
|
# 暴露端口
|
|
EXPOSE 8002
|
|
|
|
# 健康检查
|
|
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \\
|
|
CMD curl -f http://localhost:8002/api/v1/health || exit 1
|
|
|
|
# 启动命令
|
|
CMD ["./cloud-drive-server"]
|
|
'''
|
|
|
|
with open('Dockerfile.executable', 'w', encoding='utf-8') as f:
|
|
f.write(dockerfile_content)
|
|
print("OK 创建了 Dockerfile.executable 文件")
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("=== 云盘应用打包工具 ===")
|
|
print("正在将应用打包为Docker镜像...")
|
|
|
|
# 检查当前目录
|
|
if not Path('main.py').exists():
|
|
print("ERROR 错误: 在当前目录未找到 main.py 文件")
|
|
print("请在 backend 目录中运行此脚本")
|
|
return False
|
|
|
|
# 检查依赖
|
|
check_dependencies()
|
|
|
|
# 创建 spec 文件
|
|
create_spec_file()
|
|
|
|
# 构建可执行文件
|
|
if not build_executable():
|
|
return False
|
|
|
|
# 创建可执行文件的 Dockerfile
|
|
create_dockerfile_for_executable()
|
|
|
|
print("\n=== 打包完成 ===")
|
|
print("OK 应用已成功打包")
|
|
print("OK 可执行文件位于: dist/cloud-drive-server")
|
|
print("OK Dockerfile: Dockerfile.executable")
|
|
print("\n下一步命令:")
|
|
print(" docker build -f Dockerfile.executable -t cloud-drive-backend:latest .")
|
|
print(" docker run -d -p 8002:8002 --name cloud-drive-backend cloud-drive-backend:latest")
|
|
|
|
return True
|
|
|
|
if __name__ == "__main__":
|
|
success = main()
|
|
sys.exit(0 if success else 1) |