# -*- coding: utf-8 -*- """仓库根目录校验工具 — 全仓共享。 所有使用相对路径(docs/、export/、.kiro/ 等)的脚本, 应在入口处调用 ensure_repo_root() 确保 cwd 正确。 用法: from neozqyy_shared.repo_root import ensure_repo_root ensure_repo_root() 行为: 1. cwd 已是仓库根 → 直接返回 2. cwd 不是根但能通过 __main__.__file__ 或调用栈推断 → 自动 chdir + 警告 3. 无法定位 → 抛出 RuntimeError """ from __future__ import annotations import os import warnings from pathlib import Path # 仓库根的标志文件组合(pyproject.toml 必须存在 + 至少一个辅助标志) _REQUIRED = "pyproject.toml" _AUX_MARKERS = ("CLAUDE.md", ".claude", ".kiro") def _is_repo_root(p: Path) -> bool: if not (p / _REQUIRED).is_file(): return False return any((p / m).exists() for m in _AUX_MARKERS) def _find_root_from_file(anchor: Path, max_depth: int = 8) -> Path | None: """从给定文件路径向上搜索仓库根。""" current = anchor.resolve().parent for _ in range(max_depth): if _is_repo_root(current): return current parent = current.parent if parent == current: break current = parent return None def ensure_repo_root() -> Path: """校验并确保 cwd 为仓库根目录。 Returns: 仓库根目录的 Path 对象。 Raises: RuntimeError: 无法定位仓库根目录。 """ cwd = Path.cwd() if _is_repo_root(cwd): return cwd # 策略 1:通过 __main__.__file__ 推断(脚本直接运行时可用) import __main__ main_file = getattr(__main__, "__file__", None) if main_file: root = _find_root_from_file(Path(main_file)) if root: os.chdir(root) warnings.warn( f"cwd 不是仓库根目录,已自动切换: {cwd} → {root}", stacklevel=2, ) return root # 策略 2:通过本文件位置推断(packages/shared/src/neozqyy_shared/repo_root.py) root = _find_root_from_file(Path(__file__)) if root: os.chdir(root) warnings.warn( f"cwd 不是仓库根目录,已自动切换: {cwd} → {root}", stacklevel=2, ) return root raise RuntimeError( f"无法定位仓库根目录。当前 cwd={cwd}。" f"请在仓库根目录下运行脚本。" )