#!/usr/bin/env python3 # -*- coding: utf-8 -*- """从 backup 拷贝还原根目录散落 + 旧汇总夹;一文一夹保留不动。 策略(按用户要求): - 原有位置(根目录 / 汇总夹)应保留原文 → 从 backup **copy** 回来 - 一文一夹是**新增**逻辑,里面的是拷贝,不是 move 产物 - 若一文一夹比还原后的根文件更新(整理后的编辑),再把更新同步回根目录 - 仅存在于一文一夹的新文(如完整案例)→ 同时拷一份到根目录 """ from __future__ import annotations import shutil from pathlib import Path ROOT = Path(r"D:\workbuddy\192.168.110.207") MD = ROOT / "docs" / "md_cursor" HTML = ROOT / "docs" / "html_cursor" AGGREGATE_DIR_NAMES = { "00_索引与总纲", "01_Dify部署与排障", "02_Langfuse可观测", "03_LiteLLM与模型网关", "04_Higress总入口", "05_监控与SLA", "06_基础设施_K8s_GPU_Harbor_GitLab_ArgoCD", "07_实战作业", "08_架构培训与成长", "专题", "作业", "手册教程", "索引总纲", } def copy_file(src: Path, dest: Path) -> None: dest.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src, dest) print("restore-file", dest.relative_to(ROOT).as_posix()) def copy_tree(src: Path, dest: Path) -> None: if dest.exists(): # 合并:逐文件拷,不整夹删 for p in src.rglob("*"): if p.is_file(): rel = p.relative_to(src) copy_file(p, dest / rel) else: shutil.copytree(src, dest) print("restore-tree", dest.relative_to(ROOT).as_posix()) def find_stamp_with(base: Path, sub: str) -> Path | None: backup = base / "backup" if not backup.is_dir(): return None candidates = [] for stamp in backup.iterdir(): if stamp.is_dir() and stamp.name.startswith("整理_"): target = stamp / sub if target.exists(): candidates.append(stamp) if not candidates: return None return sorted(candidates, key=lambda p: p.name)[-1] def restore_scatter_and_aggregates() -> None: # MD md_stamp = find_stamp_with(MD, "根目录散落_md") or find_stamp_with(MD, "旧汇总夹_md") if md_stamp: scatter = md_stamp / "根目录散落_md" if scatter.is_dir(): for p in scatter.glob("*_cursor.md"): copy_file(p, MD / p.name) agg = md_stamp / "旧汇总夹_md" if agg.is_dir(): for name in AGGREGATE_DIR_NAMES: src = agg / name if src.is_dir(): copy_tree(src, MD / name) # HTML(根散落可能在较早 stamp,汇总夹在较晚 stamp) html_scatter_stamp = find_stamp_with(HTML, "根目录散落_html") if html_scatter_stamp: scatter = html_scatter_stamp / "根目录散落_html" # 合并两个 stamp 的根散落(093942 只有 1 个,094021 有一批) for stamp in sorted((HTML / "backup").glob("整理_*")): s = stamp / "根目录散落_html" if s.is_dir(): for p in s.glob("*_cursor.html"): copy_file(p, HTML / p.name) html_agg_stamp = find_stamp_with(HTML, "旧汇总夹_html") if html_agg_stamp: agg = html_agg_stamp / "旧汇总夹_html" if agg.is_dir(): for name in AGGREGATE_DIR_NAMES: src = agg / name if src.is_dir(): copy_tree(src, HTML / name) def sync_onedoc_newer_to_root() -> None: """一文一夹若更新(或根缺失)→ 拷回根目录,保持「根=原件可编辑」。""" for base, suffix in ((MD, "_cursor.md"), (HTML, "_cursor.html")): for folder in sorted(base.iterdir()): if not folder.is_dir() or folder.name in ("assets", "backup") or folder.name in AGGREGATE_DIR_NAMES: continue src = folder / f"{folder.name}{suffix}" if not src.is_file(): continue dest = base / f"{folder.name}{suffix}" if not dest.exists() or src.stat().st_mtime > dest.stat().st_mtime: copy_file(src, dest) print("sync-onedoc→root", dest.name) def main() -> int: restore_scatter_and_aggregates() sync_onedoc_newer_to_root() print("[PASS] restored originals by copy; one-doc folders kept") return 0 if __name__ == "__main__": raise SystemExit(main())