179 lines
4.5 KiB
Python
179 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
前端应用部署脚本 - 将构建好的文件上传到服务器
|
|
使用方法: python deploy.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
# 服务器配置
|
|
SERVER_IP = "101.200.208.45"
|
|
USERNAME = "root"
|
|
REMOTE_PATH = "/data/www/emotion-museum"
|
|
|
|
# 本地路径
|
|
SCRIPT_DIR = Path(__file__).parent.absolute()
|
|
DIST_DIR = SCRIPT_DIR / "dist"
|
|
|
|
|
|
class Colors:
|
|
"""终端颜色"""
|
|
GREEN = '\033[32m'
|
|
RED = '\033[31m'
|
|
RESET = '\033[0m'
|
|
|
|
|
|
def log_info(msg):
|
|
"""打印信息日志"""
|
|
print(f"{Colors.GREEN}✅{Colors.RESET} {msg}")
|
|
|
|
|
|
def log_error(msg):
|
|
"""打印错误日志"""
|
|
print(f"{Colors.RED}❌{Colors.RESET} {msg}")
|
|
|
|
|
|
def log_step(msg):
|
|
"""打印步骤日志"""
|
|
print(f"📦 {msg}")
|
|
|
|
|
|
def run_command(cmd, cwd=None, shell=True, capture=True, timeout=None):
|
|
"""执行本地命令"""
|
|
try:
|
|
if capture:
|
|
result = subprocess.run(
|
|
cmd, cwd=cwd, shell=shell,
|
|
capture_output=True, text=True, timeout=timeout
|
|
)
|
|
return result.returncode == 0, result.stdout, result.stderr
|
|
else:
|
|
result = subprocess.run(cmd, cwd=cwd, shell=shell, timeout=timeout)
|
|
return result.returncode == 0, "", ""
|
|
except subprocess.TimeoutExpired:
|
|
return False, "", "命令执行超时"
|
|
except Exception as e:
|
|
return False, "", str(e)
|
|
|
|
|
|
def scp_upload(local_path, remote_path, recursive=False):
|
|
"""通过SCP上传文件或目录"""
|
|
r_flag = "-r" if recursive else ""
|
|
scp_cmd = f'scp -o ConnectTimeout=10 -o BatchMode=yes {r_flag} "{local_path}" {USERNAME}@{SERVER_IP}:{remote_path}'
|
|
try:
|
|
result = subprocess.run(
|
|
scp_cmd, shell=True, capture_output=True, text=True, timeout=120
|
|
)
|
|
if result.returncode != 0:
|
|
log_error(f"SCP上传失败: {result.stderr}")
|
|
return False
|
|
return True
|
|
except subprocess.TimeoutExpired:
|
|
log_error("SCP上传超时")
|
|
return False
|
|
except Exception as e:
|
|
log_error(f"SCP上传异常: {e}")
|
|
return False
|
|
|
|
|
|
def check_npm():
|
|
"""检查npm是否安装"""
|
|
success, _, _ = run_command("npm --version")
|
|
if not success:
|
|
log_error("错误: 未找到npm命令,请先安装Node.js")
|
|
sys.exit(1)
|
|
|
|
|
|
def build_project():
|
|
"""构建项目"""
|
|
log_step("开始构建前端项目...")
|
|
|
|
os.chdir(SCRIPT_DIR)
|
|
|
|
success, _, _ = run_command("npm run build", capture=False)
|
|
if not success:
|
|
log_error("前端项目构建失败,请检查代码")
|
|
sys.exit(1)
|
|
|
|
log_info("前端项目构建成功")
|
|
|
|
|
|
def verify_dist():
|
|
"""验证dist目录是否存在"""
|
|
if not DIST_DIR.exists():
|
|
log_error("错误: 构建后dist目录仍不存在,请检查构建配置")
|
|
sys.exit(1)
|
|
|
|
index_file = DIST_DIR / "index.html"
|
|
assets_dir = DIST_DIR / "assets"
|
|
|
|
if not index_file.exists():
|
|
log_error("错误: dist/index.html 不存在")
|
|
sys.exit(1)
|
|
|
|
if not assets_dir.exists():
|
|
log_error("错误: dist/assets 目录不存在")
|
|
sys.exit(1)
|
|
|
|
|
|
def upload_files():
|
|
"""上传文件到服务器"""
|
|
print(f"正在上传文件到服务器 {SERVER_IP}...")
|
|
|
|
# 上传 index.html
|
|
index_file = DIST_DIR / "index.html"
|
|
if not scp_upload(index_file, f"{REMOTE_PATH}/"):
|
|
return False
|
|
|
|
# 上传 assets 目录
|
|
assets_dir = DIST_DIR / "assets"
|
|
if not scp_upload(assets_dir, f"{REMOTE_PATH}/", recursive=True):
|
|
return False
|
|
|
|
# 上传测试文件(如果存在)
|
|
test_file = DIST_DIR / "test-login-redirect.html"
|
|
if test_file.exists():
|
|
# 上传所有 test-*.html 文件
|
|
for f in DIST_DIR.glob("test-*.html"):
|
|
scp_upload(f, f"{REMOTE_PATH}/")
|
|
|
|
return True
|
|
|
|
|
|
def deploy():
|
|
"""执行部署"""
|
|
print("开始部署前端应用到服务器...")
|
|
|
|
# 检查npm
|
|
check_npm()
|
|
|
|
# 构建项目
|
|
build_project()
|
|
|
|
# 验证构建结果
|
|
verify_dist()
|
|
|
|
# 上传文件
|
|
if upload_files():
|
|
log_info("部署完成!")
|
|
print(f"📱 访问地址: http://{SERVER_IP}/emotion-museum/")
|
|
else:
|
|
log_error("部署失败,请检查:")
|
|
print("1. 服务器IP地址是否正确")
|
|
print("2. SSH密钥是否配置正确")
|
|
print("3. 服务器目录权限是否正确")
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
"""主函数"""
|
|
deploy()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|