update
This commit is contained in:
192
build.py
Normal file
192
build.py
Normal file
@@ -0,0 +1,192 @@
|
||||
import os
|
||||
import shutil # 新增导入shutil用于文件复制
|
||||
import yaml
|
||||
import subprocess
|
||||
from typing import Dict, Any
|
||||
|
||||
def run_shell_command(command: str, cwd: str = None) -> bool:
|
||||
"""执行shell命令并返回执行结果"""
|
||||
try:
|
||||
print(f"执行命令: {command} (工作目录: {cwd or os.getcwd()})")
|
||||
result = subprocess.run(
|
||||
command,
|
||||
cwd=cwd,
|
||||
shell=True,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
print(f"命令输出: {result.stdout}")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"命令执行失败: {e.stderr}")
|
||||
return False
|
||||
|
||||
def cleanup_dangling_images() -> bool:
|
||||
"""清除docker虚悬镜像(dangling images)"""
|
||||
print("开始清除虚悬镜像...")
|
||||
# 清除所有<none>:<none>的虚悬镜像,xargs -r确保无镜像时不执行删除命令
|
||||
return run_shell_command('sudo docker images -f "dangling=true" -q | xargs -r sudo docker rmi')
|
||||
|
||||
def execute_release_scripts(root_dir: str) -> bool:
|
||||
"""遍历所有api_目录并执行release.sh脚本(排除api_template)"""
|
||||
print("开始执行所有api_目录下的release.sh脚本...")
|
||||
|
||||
# 定义目标镜像目录
|
||||
images_dir = os.path.join(root_dir, 'deploy', 'images')
|
||||
# 确保目标目录存在
|
||||
os.makedirs(images_dir, exist_ok=True)
|
||||
|
||||
for dir_name in os.listdir(root_dir):
|
||||
# 排除api_template文件夹
|
||||
if dir_name == "api_template":
|
||||
print(f"跳过模板目录: {dir_name}")
|
||||
continue
|
||||
|
||||
dir_path = os.path.join(root_dir, dir_name)
|
||||
if os.path.isdir(dir_path) and dir_name.startswith('api_'):
|
||||
release_script = os.path.join(dir_path, 'release.sh')
|
||||
if os.path.exists(release_script):
|
||||
print(f"处理目录: {dir_path}")
|
||||
|
||||
# 添加执行权限
|
||||
if not run_shell_command(f"chmod +x {release_script}", dir_path):
|
||||
print(f"为 {release_script} 添加权限失败,跳过执行")
|
||||
continue
|
||||
|
||||
# 执行release.sh
|
||||
if not run_shell_command(f"./release.sh", dir_path):
|
||||
print(f"{release_script} 执行失败,跳过后续步骤")
|
||||
return False
|
||||
|
||||
# 复制目录下的.tar文件到根目录的deploy/images下(替换方式)
|
||||
for file in os.listdir(dir_path):
|
||||
if file.endswith('.tar'):
|
||||
src_path = os.path.join(dir_path, file)
|
||||
dest_path = os.path.join(images_dir, file)
|
||||
# 如果目标文件存在则先删除
|
||||
if os.path.exists(dest_path):
|
||||
os.remove(dest_path)
|
||||
# 复制文件
|
||||
shutil.copy2(src_path, dest_path)
|
||||
print(f"已将 {src_path} 替换复制到 {dest_path}")
|
||||
else:
|
||||
print(f"{dir_path} 中未找到release.sh,跳过")
|
||||
|
||||
print("所有release.sh脚本执行完成")
|
||||
return True
|
||||
|
||||
def merge_yaml_files(root_dir: str) -> Dict[str, Any]:
|
||||
"""合并所有 docker-compose 相关 YAML 文件内容(排除api_template)"""
|
||||
merged = {
|
||||
'version': '3.8', # 默认使用 3.8 版本
|
||||
'services': {},
|
||||
'networks': {},
|
||||
'volumes': {}
|
||||
}
|
||||
|
||||
# 查找所有 docker-compose 相关 YAML 文件
|
||||
yaml_files = []
|
||||
# 1. 根目录下的 docker-compose.*.yaml
|
||||
for file in os.listdir(root_dir):
|
||||
if file.startswith('docker-compose.') and file.endswith('.yaml'):
|
||||
if file == 'docker-compose.yaml': # 跳过目标文件本身
|
||||
continue
|
||||
yaml_files.append(os.path.join(root_dir, file))
|
||||
|
||||
# 2. api_ 目录下的 docker-compose.*.yaml(排除api_template)
|
||||
for dir_name in os.listdir(root_dir):
|
||||
# 排除api_template文件夹
|
||||
if dir_name == "api_template":
|
||||
print(f"跳过模板目录的yaml文件: {dir_name}")
|
||||
continue
|
||||
|
||||
dir_path = os.path.join(root_dir, dir_name)
|
||||
if os.path.isdir(dir_path) and dir_name.startswith('api_'):
|
||||
for file in os.listdir(dir_path):
|
||||
if file.startswith('docker-compose.') and file.endswith('.yaml'):
|
||||
yaml_files.append(os.path.join(dir_path, file))
|
||||
|
||||
# 合并所有 YAML 文件内容
|
||||
for file_path in yaml_files:
|
||||
print(f"合并文件: {file_path}")
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
try:
|
||||
data = yaml.safe_load(f)
|
||||
if not data:
|
||||
continue
|
||||
|
||||
# 合并 services
|
||||
if 'services' in data:
|
||||
merged['services'].update(data['services'])
|
||||
|
||||
# 合并 networks
|
||||
if 'networks' in data:
|
||||
merged['networks'].update(data['networks'])
|
||||
|
||||
# 合并 volumes
|
||||
if 'volumes' in data:
|
||||
merged['volumes'].update(data['volumes'])
|
||||
|
||||
# 保留最高版本号
|
||||
if 'version' in data and data['version'] > merged['version']:
|
||||
merged['version'] = data['version']
|
||||
|
||||
except yaml.YAMLError as e:
|
||||
print(f"解析 {file_path} 失败: {e}")
|
||||
continue
|
||||
|
||||
return merged
|
||||
|
||||
def main():
|
||||
# 先执行清除虚悬镜像操作
|
||||
print("部署流程开始,先执行清除虚悬镜像操作...")
|
||||
if not cleanup_dangling_images():
|
||||
print("清除虚悬镜像失败(非致命错误,继续部署流程)")
|
||||
else:
|
||||
print("虚悬镜像清除完成")
|
||||
|
||||
# 获取项目根目录(deploy.py 所在目录)
|
||||
root_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
print(f"项目根目录: {root_dir}")
|
||||
|
||||
# 1. 执行所有api_目录下的release.sh脚本
|
||||
if not execute_release_scripts(root_dir):
|
||||
print("执行release脚本失败,终止部署流程")
|
||||
return
|
||||
|
||||
# 2. 合并所有YAML文件
|
||||
merged_data = merge_yaml_files(root_dir)
|
||||
|
||||
# 输出到根目录的docker-compose.yaml
|
||||
output_path = os.path.join(root_dir, 'docker-compose.yaml')
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(
|
||||
merged_data,
|
||||
f,
|
||||
sort_keys=False, # 保持键的顺序
|
||||
allow_unicode=True, # 支持中文
|
||||
default_flow_style=False # 使用块样式
|
||||
)
|
||||
print(f"已生成合并后的 docker-compose.yaml: {output_path}")
|
||||
|
||||
# 将新的docker-compose.yaml以替换方式复制到根目录的deploy/下
|
||||
deploy_dir = os.path.join(root_dir, 'deploy')
|
||||
os.makedirs(deploy_dir, exist_ok=True) # 确保deploy目录存在
|
||||
dest_compose_path = os.path.join(deploy_dir, 'docker-compose.yaml')
|
||||
# 替换方式复制:若目标存在则先删除
|
||||
if os.path.exists(dest_compose_path):
|
||||
os.remove(dest_compose_path)
|
||||
shutil.copy2(output_path, dest_compose_path)
|
||||
print(f"已将 {output_path} 替换复制到 {dest_compose_path}")
|
||||
|
||||
print("\n===== 清理虚悬镜像 =====")
|
||||
if not cleanup_dangling_images():
|
||||
print("清除虚悬镜像失败(非致命错误,继续部署流程)")
|
||||
else:
|
||||
print("虚悬镜像清除完成")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 需要安装 pyyaml 库: pip install pyyaml
|
||||
main()
|
Reference in New Issue
Block a user