- archive/hermes-dead-tools-20260820/: hermes独有不在cron不被import的111个一次性排查/测试工具 - archive/hermes-dead-tools-20260820/: 4个废弃scanner(btd1_v3/market_scanner/market_thermometer已废弃/s2v2) - archive/legacy-cleanup-20260820/: MoFin根2旧版(mo_models/technical_analysis)+/home/hmo/scripts无引用旧项目+MoFin/scripts重复prepare_report_data - 删除MoFin根mo_models.py(根旧版,deploy/profile-scripts权威保留) - 保留: mofin_db.py/mo_data.py硬链接(server.py多层sys.path需各目录访问同一inode,非冗余) - fix_gateway.py保留(Gateway看门狗fix_gateway_port.py的活跃依赖,勿误删) - 验证: cron所有脚本引用无缺失, key模块import正常 - hermes独有从116收敛到5核心(alert_logger/market_screener/prepare_report_data/self_todo_executor_v2/xmpp_zhiwei_bot)
84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""audit_duplication.py — 扫描 MoFin 相关目录的文件重复情况"""
|
|
import os, hashlib, json
|
|
from collections import defaultdict
|
|
|
|
LOCATIONS = [
|
|
'/home/hmo/MoFin',
|
|
'/home/hmo/MoFin/scripts',
|
|
'/home/hmo/MoFin/deploy/profile-scripts',
|
|
'/home/hmo/MoFin/deploy/bot',
|
|
'/home/hmo/.hermes/profiles/position-analyst/scripts',
|
|
'/home/hmo/.hermes/scripts',
|
|
'/home/hmo/web-dashboard',
|
|
]
|
|
|
|
def md5(p):
|
|
try:
|
|
with open(p, 'rb') as f:
|
|
return hashlib.md5(f.read()).hexdigest()[:10]
|
|
except Exception:
|
|
return 'ERR'
|
|
|
|
def ino(p):
|
|
try:
|
|
return os.stat(p).st_ino
|
|
except Exception:
|
|
return 0
|
|
|
|
# 收集所有 .py 文件
|
|
files = defaultdict(list) # name -> [(loc, path, md5, inode, is_link)]
|
|
for loc in LOCATIONS:
|
|
if not os.path.isdir(loc):
|
|
continue
|
|
for f in os.listdir(loc):
|
|
if not f.endswith('.py'):
|
|
continue
|
|
p = os.path.join(loc, f)
|
|
if not os.path.isfile(p):
|
|
continue
|
|
files[f].append({
|
|
'loc': loc, 'path': p, 'md5': md5(p), 'inode': ino(p),
|
|
'is_link': os.path.islink(p),
|
|
'size': os.path.getsize(p),
|
|
'mtime': int(os.path.getmtime(p)),
|
|
})
|
|
|
|
print("=== 重复文件(同名出现在2+位置)===")
|
|
dups = {k: v for k, v in files.items() if len(v) > 1}
|
|
identical = 0
|
|
hardlinked = 0
|
|
diverged = 0
|
|
for name in sorted(dups):
|
|
entries = dups[name]
|
|
md5s = set(e['md5'] for e in entries)
|
|
inodes = set(e['inode'] for e in entries)
|
|
if len(inodes) == 1:
|
|
status = 'HARDLINK(同一文件)'
|
|
hardlinked += 1
|
|
elif len(md5s) == 1:
|
|
status = 'COPY(内容相同,多份独立)'
|
|
identical += 1
|
|
else:
|
|
status = 'DIVERGED(内容不同!)'
|
|
diverged += 1
|
|
print(f"{status} {name}")
|
|
for e in entries:
|
|
print(f" {e['path']} md5={e['md5']} ino={e['inode']} size={e['size']}")
|
|
|
|
print(f"\n汇总: {len(dups)} 个重复文件名 | hardlink={hardlinked} 内容相同副本={identical} 内容分叉={diverged}")
|
|
|
|
print("\n=== deploy/profile-scripts 中有但 position-analyst/scripts 中缺失的 ===")
|
|
pa_dir = '/home/hmo/.hermes/profiles/position-analyst/scripts'
|
|
deploy_dir = '/home/hmo/MoFin/deploy/profile-scripts'
|
|
pa_files = set(os.listdir(pa_dir)) if os.path.isdir(pa_dir) else set()
|
|
for f in sorted(os.listdir(deploy_dir)):
|
|
if f.endswith('.py') and f not in pa_files:
|
|
print(f" {f}")
|
|
|
|
print("\n=== position-analyst/scripts 中有但 deploy 中没有的(可能孤儿)===")
|
|
deploy_files = set(os.listdir(deploy_dir))
|
|
for f in sorted(pa_files):
|
|
if f.endswith('.py') and f not in deploy_files:
|
|
p = os.path.join(pa_dir, f)
|
|
print(f" {f} size={os.path.getsize(p)}") |