Skip to content

Commit 4861c4d

Browse files
committed
🎨 自动删除过期备份, 优化依赖安装
1 parent 9bf447c commit 4861c4d

File tree

3 files changed

+117
-18
lines changed

3 files changed

+117
-18
lines changed

gsuid_core/buildin_plugins/core_command/core_backup/__init__.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
from gsuid_core.logger import logger
66
from gsuid_core.data_store import get_res_path
77
from gsuid_core.utils.database.base_models import DB_PATH
8-
from gsuid_core.utils.plugins_config.gs_config import backup_config
9-
from gsuid_core.utils.backup.backup_core import copy_and_rebase_paths
108
from gsuid_core.utils.backup.backup_files import clean_log, backup_file
9+
from gsuid_core.utils.plugins_config.gs_config import log_config, backup_config
10+
from gsuid_core.utils.backup.backup_core import (
11+
remove_old_backups,
12+
copy_and_rebase_paths,
13+
)
1114
from gsuid_core.utils.database.global_val_models import (
1215
CoreDataSummary,
1316
CoreDataAnalysis,
@@ -24,6 +27,7 @@
2427

2528
DB_BACKUP = get_res_path(['GsCore', 'database_backup'])
2629

30+
CLEAN_DAY: str = log_config.get_config('ScheduledCleanLogDay').data
2731
backup_time: str = backup_config.get_config('backup_time').data
2832
backup_time = backup_time.lstrip('0')
2933
backup_hour, backup_minute = backup_time.split(':')
@@ -40,9 +44,10 @@ async def backup_path_files():
4044
'''
4145
凌晨自动备份`备份管理`中的路径树
4246
'''
43-
4447
copy_and_rebase_paths()
4548
logger.success('♻️ [早柚核心] 路径已备份!')
49+
remove_old_backups(int(CLEAN_DAY))
50+
logger.success(f'♻️ [早柚核心] 已删除超过 {CLEAN_DAY} 天的备份文件!')
4651

4752

4853
@sv_core_backup.on_fullmatch('强制执行文件备份')

gsuid_core/server.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from packaging.requirements import Requirement
1919
except ImportError:
2020
print("正在安装必要依赖 'packaging'...")
21+
subprocess.check_call([sys.executable, "-m", "ensurepip"])
2122
subprocess.check_call(
2223
[sys.executable, "-m", "pip", "install", "packaging"]
2324
)
@@ -433,27 +434,53 @@ def install_packages(packages: List[str], upgrade: bool = False):
433434

434435
logger.info(f'🚀 [安装/更新依赖] 开始安装以下包: {packages}')
435436

436-
# 使用当前 Python 解释器路径,避免环境混乱
437-
cmd = [sys.executable, "-m", "pip", "install"]
437+
# 定义镜像源列表 (名称, URL)
438+
# 顺序: 字节 -> 阿里 -> 清华 -> 官方
439+
mirrors = [
440+
("字节源 (Volces)", "https://mirrors.volces.com/pypi/simple/"),
441+
("阿里源 (Aliyun)", "https://mirrors.aliyun.com/pypi/simple/"),
442+
("清华源 (Tsinghua)", "https://pypi.tuna.tsinghua.edu.cn/simple"),
443+
("官方源 (PyPI)", "https://pypi.org/simple"),
444+
]
445+
446+
# 构建基础命令
447+
base_cmd = [sys.executable, "-m", "pip", "install"]
438448
if upgrade:
439-
cmd.append("-U")
449+
base_cmd.append("-U")
440450

441-
# 将包名作为参数追加
442-
cmd.extend(packages)
451+
# 追加包名
452+
base_cmd.extend(packages)
443453

444-
# 使用国内源可选项 (建议在配置中做,这里保留原逻辑的简化版)
445-
cmd.extend(["-i", "https://pypi.org/simple"])
454+
install_success = False
446455

447-
retcode = execute_cmd(cmd)
456+
# 轮询尝试
457+
for mirror_name, mirror_url in mirrors:
458+
logger.info(f'⏳ [安装/更新依赖] 正在尝试使用 [{mirror_name}] ...')
448459

449-
if retcode != 0:
450-
logger.warning('[安装/更新依赖] 安装失败,尝试使用清华源重试...')
451-
cmd_retry = cmd[:-2] + [
452-
"-i",
453-
"https://pypi.tuna.tsinghua.edu.cn/simple",
454-
]
455-
execute_cmd(cmd_retry)
460+
# 组装完整命令,加入 -i 参数
461+
cmd = base_cmd + ["-i", mirror_url]
462+
463+
# 有些环境可能需要信任 host,防止 SSL 报错,可选添加:
464+
# host = mirror_url.split("//")[-1].split("/")[0]
465+
# cmd.extend(["--trusted-host", host])
466+
467+
retcode = execute_cmd(cmd)
468+
469+
if retcode == 0:
470+
logger.info(f'✅ [安装/更新依赖] 使用 [{mirror_name}] 安装成功!')
471+
install_success = True
472+
break # 安装成功,跳出循环
473+
else:
474+
logger.warning(
475+
f'⚠️ [安装/更新依赖] 使用 [{mirror_name}] 安装失败,准备尝试下一个源...'
476+
)
477+
478+
if not install_success:
479+
logger.error(
480+
'❌ [安装/更新依赖] 所有源均尝试失败,请检查网络或包名是否正确。'
481+
)
456482

483+
# 刷新依赖状态
457484
refresh_installed_dependencies()
458485

459486

gsuid_core/utils/backup/backup_core.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,70 @@ def copy_and_rebase_paths(
9494
return -10
9595

9696
return 0
97+
98+
99+
def remove_old_backups(days: int = 30) -> int:
100+
"""
101+
删除超过指定天数的备份文件或目录。
102+
103+
:param days: 保留的天数,默认为30天。
104+
:return: 被删除的文件/目录数量。
105+
"""
106+
if not backup_path.exists():
107+
logger.warning(f"备份目录不存在: {backup_path},跳过清理。")
108+
return 0
109+
110+
current_time = datetime.now()
111+
deleted_count = 0
112+
113+
logger.info(f"开始清理超过 {days} 天的备份文件...")
114+
115+
# 遍历备份目录下的所有项目
116+
for item in backup_path.iterdir():
117+
# 获取文件名(不含扩展名),例如 'mydata-2023-11-19'
118+
# item.stem 会自动去掉 .zip 后缀
119+
name_stem = item.stem
120+
121+
# 尝试提取日期部分
122+
# 你的命名格式是: f'{file_id}-{date_str}',date_str 是 "YYYY-MM-DD" (10个字符)
123+
# 所以我们取 stem 的最后 10 位
124+
if len(name_stem) < 10:
125+
continue
126+
127+
date_str_part = name_stem[-10:]
128+
129+
try:
130+
# 尝试将后缀解析为日期
131+
backup_date = datetime.strptime(date_str_part, "%Y-%m-%d")
132+
except ValueError:
133+
# 如果解析失败(说明不是符合该日期格式的文件),则跳过
134+
continue
135+
136+
# 计算时间差
137+
time_delta = current_time - backup_date
138+
139+
if time_delta.days > days:
140+
try:
141+
if item.is_file():
142+
item.unlink() # 删除文件 (通常是 .zip)
143+
logger.info(
144+
"🗑️ [早柚核心] 已删除过期备份文件:"
145+
f" {item.name} ({time_delta.days}天前)"
146+
)
147+
elif item.is_dir():
148+
shutil.rmtree(item) # 删除目录 (如果存在未压缩的残留目录)
149+
logger.info(
150+
"🗑️ [早柚核心] 已删除过期备份目录:"
151+
f" {item.name} ({time_delta.days}天前)"
152+
)
153+
154+
deleted_count += 1
155+
except Exception as e:
156+
logger.warning(f"❌ 删除 {item.name} 失败: {e}")
157+
158+
if deleted_count > 0:
159+
logger.success(f"✅ 清理完成,共删除 {deleted_count} 个过期备份。")
160+
else:
161+
logger.info("✨ 没有发现需要删除的过期备份。")
162+
163+
return deleted_count

0 commit comments

Comments
 (0)