add banbanmini backend
This commit is contained in:
112
talkingq-url/scripts/restore_db.py
Normal file
112
talkingq-url/scripts/restore_db.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import os
|
||||
import sys
|
||||
import asyncio
|
||||
import subprocess
|
||||
import gzip
|
||||
import tempfile
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from config import settings
|
||||
from scripts.backup_db import list_backups, BACKUP_DIR
|
||||
|
||||
async def restore_database(backup_file):
|
||||
"""从备份文件恢复数据库"""
|
||||
file_path = backup_file
|
||||
if not os.path.isabs(backup_file):
|
||||
file_path = os.path.join(BACKUP_DIR, backup_file)
|
||||
|
||||
if not os.path.exists(file_path):
|
||||
print(f"错误: 备份文件 '{file_path}' 不存在")
|
||||
return False
|
||||
|
||||
confirm = input(f"警告: 这将覆盖当前数据库的所有数据。确定要继续吗? (y/N): ")
|
||||
if confirm.lower() != 'y':
|
||||
print("操作已取消")
|
||||
return False
|
||||
|
||||
temp_file = None
|
||||
sql_file = file_path
|
||||
|
||||
try:
|
||||
if file_path.endswith('.gz'):
|
||||
print("解压备份文件...")
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.sql')
|
||||
temp_file.close()
|
||||
|
||||
with gzip.open(file_path, 'rb') as f_in:
|
||||
with open(temp_file.name, 'wb') as f_out:
|
||||
shutil.copyfileobj(f_in, f_out)
|
||||
|
||||
sql_file = temp_file.name
|
||||
|
||||
cmd = [
|
||||
"mysql",
|
||||
"-h", settings.db_host,
|
||||
"-P", str(settings.db_port),
|
||||
"-u", settings.db_user,
|
||||
f"-p{settings.db_password}",
|
||||
settings.db_name
|
||||
]
|
||||
|
||||
print(f"开始恢复数据库...")
|
||||
with open(sql_file, 'r') as f:
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=f,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
stdout, stderr = process.communicate()
|
||||
|
||||
if process.returncode != 0:
|
||||
print(f"恢复失败: {stderr.decode()}")
|
||||
return False
|
||||
|
||||
print("数据库恢复成功!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"恢复过程中出错: {e}")
|
||||
return False
|
||||
|
||||
finally:
|
||||
if temp_file and os.path.exists(temp_file.name):
|
||||
os.unlink(temp_file.name)
|
||||
|
||||
async def interactive_restore():
|
||||
"""交互式选择要恢复的备份文件"""
|
||||
backups = await list_backups()
|
||||
|
||||
if not backups:
|
||||
print("没有找到可用的备份文件")
|
||||
return False
|
||||
|
||||
print("\n可用的备份文件:")
|
||||
for i, backup in enumerate(backups):
|
||||
file_path = os.path.join(BACKUP_DIR, backup)
|
||||
size = os.path.getsize(file_path) / (1024 * 1024) # 转换为MB
|
||||
print(f"{i+1}. {backup} ({size:.2f} MB)")
|
||||
|
||||
try:
|
||||
choice = int(input("\n请选择要恢复的备份文件 (输入序号): "))
|
||||
if 1 <= choice <= len(backups):
|
||||
selected_backup = backups[choice-1]
|
||||
return await restore_database(selected_backup)
|
||||
else:
|
||||
print("无效的选择")
|
||||
return False
|
||||
except ValueError:
|
||||
print("无效的输入")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
if len(sys.argv) > 1:
|
||||
await restore_database(sys.argv[1])
|
||||
else:
|
||||
await interactive_restore()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user