фикс грапхити

This commit is contained in:
dctouch 2026-04-10 09:36:54 +03:00
parent fd6764d412
commit 19dbaff741
2 changed files with 171 additions and 0 deletions

View File

@ -0,0 +1,168 @@
from __future__ import annotations
import sys
from pathlib import Path
COLLECT_FILES_FUNCTION = """def collect_files(target: Path, *, follow_symlinks: bool = False) -> list[Path]:
if target.is_file():
return [target]
_EXTENSIONS = {
".py", ".js", ".ts", ".tsx", ".go", ".rs",
".java", ".c", ".h", ".cpp", ".cc", ".cxx", ".hpp",
".rb", ".cs", ".kt", ".kts", ".scala", ".php", ".swift",
".lua", ".toc", ".zig", ".ps1",
".m", ".mm",
}
_SKIP_DIRS = {
"venv", ".venv", "env", ".env",
"node_modules", "__pycache__", ".git",
"dist", "build", "target", "out",
"site-packages", "lib64",
".pytest_cache", ".mypy_cache", ".ruff_cache",
".tox", ".eggs",
}
def _is_noise_dir(part: str) -> bool:
if part in _SKIP_DIRS:
return True
if part.endswith("_venv") or part.endswith("_env"):
return True
if part.endswith(".egg-info"):
return True
return False
def _load_graphifyignore(root: Path) -> list[str]:
ignore_file = root / ".graphifyignore"
if not ignore_file.exists():
return []
patterns: list[str] = []
for line in ignore_file.read_text(errors="ignore").splitlines():
line = line.strip()
if line and not line.startswith("#"):
patterns.append(line)
return patterns
def _is_ignored(path: Path, root: Path, patterns: list[str]) -> bool:
if not patterns:
return False
try:
rel = str(path.relative_to(root))
except ValueError:
return False
rel = rel.replace(os.sep, "/")
parts = rel.split("/")
for pattern in patterns:
p = pattern.strip("/")
if not p:
continue
if fnmatch.fnmatch(rel, p):
return True
if fnmatch.fnmatch(path.name, p):
return True
for i, part in enumerate(parts):
if fnmatch.fnmatch(part, p):
return True
if fnmatch.fnmatch("/".join(parts[: i + 1]), p):
return True
return False
ignore_patterns = _load_graphifyignore(target)
# Walk with symlink following + cycle detection
results = []
for dirpath, dirnames, filenames in os.walk(target, followlinks=follow_symlinks):
dp = Path(dirpath)
dirnames[:] = [
d for d in dirnames
if not d.startswith(".")
and not _is_noise_dir(d)
and not _is_ignored(dp / d, target, ignore_patterns)
]
if os.path.islink(dirpath):
real = os.path.realpath(dirpath)
parent_real = os.path.realpath(os.path.dirname(dirpath))
if parent_real == real or parent_real.startswith(real + os.sep):
dirnames.clear()
continue
if any(part.startswith(".") for part in dp.parts):
continue
for fname in filenames:
p = dp / fname
if fname.startswith("."):
continue
if _is_ignored(p, target, ignore_patterns):
continue
if p.suffix.lower() in _EXTENSIONS:
results.append(p)
return sorted(results)
"""
def _patch_extract_file(path: Path) -> bool:
source = path.read_text(encoding="utf-8")
changed = False
if "import fnmatch" not in source:
marker = "from __future__ import annotations\n"
if marker in source:
source = source.replace(marker, marker + "import fnmatch\n", 1)
changed = True
else:
raise RuntimeError("Cannot patch extract.py: import marker not found.")
start = source.find("def collect_files(target: Path, *, follow_symlinks: bool = False) -> list[Path]:")
end = source.find('\n\nif __name__ == "__main__":', start)
if start == -1 or end == -1:
raise RuntimeError("Cannot patch extract.py: collect_files function block not found.")
current_block = source[start:end]
if current_block.strip() != COLLECT_FILES_FUNCTION.strip():
source = source[:start] + COLLECT_FILES_FUNCTION + source[end:]
changed = True
if changed:
path.write_text(source, encoding="utf-8")
return changed
def _patch_watch_file(path: Path) -> bool:
source = path.read_text(encoding="utf-8")
target = '(out / "GRAPH_REPORT.md").write_text(report)'
patched = '(out / "GRAPH_REPORT.md").write_text(report, encoding="utf-8")'
if target not in source:
if patched in source:
return False
raise RuntimeError("Cannot patch watch.py: write_text(report) call not found.")
source = source.replace(target, patched, 1)
path.write_text(source, encoding="utf-8")
return True
def main() -> int:
try:
import graphify # noqa: PLC0415
except Exception as exc: # pragma: no cover
print(f"[graphify-hotfix] graphify import failed: {exc}", file=sys.stderr)
return 1
package_dir = Path(graphify.__file__).resolve().parent
extract_path = package_dir / "extract.py"
watch_path = package_dir / "watch.py"
if not extract_path.exists() or not watch_path.exists():
print("[graphify-hotfix] graphify package files not found", file=sys.stderr)
return 1
changed_extract = _patch_extract_file(extract_path)
changed_watch = _patch_watch_file(watch_path)
status = []
status.append("extract.py: patched" if changed_extract else "extract.py: already patched")
status.append("watch.py: patched" if changed_watch else "watch.py: already patched")
print("[graphify-hotfix] " + " | ".join(status))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@ -14,6 +14,7 @@ if (-not $SkipPipInstall) {
py -m graphify install --platform codex py -m graphify install --platform codex
py -m graphify codex install py -m graphify codex install
py scripts/patch_graphify_hotfix.py
if ($InstallGitHooks) { if ($InstallGitHooks) {
py -m graphify hook install py -m graphify hook install
@ -24,3 +25,5 @@ Write-Host "Graphify configured for Codex in $repoRoot"
Write-Host "Use these commands inside Codex:" Write-Host "Use these commands inside Codex:"
Write-Host " `$graphify ." Write-Host " `$graphify ."
Write-Host " `$graphify . --update" Write-Host " `$graphify . --update"
Write-Host ""
Write-Host "Applied local graphify hotfix (fast collect_files + UTF-8 report write)."