фикс грапхити
This commit is contained in:
parent
fd6764d412
commit
19dbaff741
|
|
@ -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())
|
||||||
|
|
@ -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)."
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue