a2ae74d582
- Backend: auth refresh reuse, schedule/retry/sync/agent/files fixes - Frontend: push WS, files ETag browse, vite build assets - Docs: audit/changelog, production deploy gate, bug scan registry B7-77 - Deploy: deploy-production.sh, prune assets, gate logs
108 lines
2.7 KiB
Python
108 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Warn when the working tree has CR bytes but git index is LF-only.
|
|
|
|
Tarballs copied from Windows often have CRLF on disk while `git pull` on Ubuntu
|
|
deploys LF from the index. Run after unpack:
|
|
|
|
python3 scripts/check_worktree_eol.py
|
|
bash scripts/normalize_worktree_lf.sh # optional fix
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
# Same critical paths as check_text_eol.py
|
|
PATTERNS = [
|
|
"*.sh",
|
|
"server/**/*.py",
|
|
"scripts/**/*.py",
|
|
"deploy/**/*.sh",
|
|
"docker/**/*.py",
|
|
"web/agent/**/*.py",
|
|
"frontend/src/**/*.vue",
|
|
"frontend/src/**/*.ts",
|
|
".cursor/rules/**/*.mdc",
|
|
]
|
|
|
|
|
|
def git_ls_files(pattern: str) -> list[str]:
|
|
r = subprocess.run(
|
|
["git", "ls-files", pattern],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
return [p for p in r.stdout.splitlines() if p.strip()]
|
|
|
|
|
|
def index_has_cr(path: str) -> bool:
|
|
r = subprocess.run(
|
|
["git", "show", f":{path}"],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
check=False,
|
|
)
|
|
return r.returncode == 0 and b"\r" in r.stdout
|
|
|
|
|
|
def worktree_has_cr(path: str) -> bool:
|
|
full = ROOT / path
|
|
if not full.is_file():
|
|
return False
|
|
return b"\r" in full.read_bytes()
|
|
|
|
|
|
def main() -> int:
|
|
seen: set[str] = set()
|
|
mismatch: list[str] = []
|
|
worktree_only: list[str] = []
|
|
|
|
for pattern in PATTERNS:
|
|
for path in git_ls_files(pattern):
|
|
if path in seen:
|
|
continue
|
|
seen.add(path)
|
|
wt = worktree_has_cr(path)
|
|
if not wt:
|
|
continue
|
|
if index_has_cr(path):
|
|
worktree_only.append(path)
|
|
else:
|
|
mismatch.append(path)
|
|
|
|
if not mismatch and not worktree_only:
|
|
print(f"check_worktree_eol: OK ({len(seen)} paths, working tree matches LF index)")
|
|
return 0
|
|
|
|
if mismatch:
|
|
print(
|
|
f"CRLF in working tree but LF in git index ({len(mismatch)} file(s)) — "
|
|
"bash/scripts may fail on Ubuntu:",
|
|
file=sys.stderr,
|
|
)
|
|
for p in sorted(mismatch)[:50]:
|
|
print(f" {p}", file=sys.stderr)
|
|
if len(mismatch) > 50:
|
|
print(f" ... and {len(mismatch) - 50} more", file=sys.stderr)
|
|
|
|
if worktree_only:
|
|
print(f"CR in both worktree and index ({len(worktree_only)} file(s)) — run check_text_eol.py", file=sys.stderr)
|
|
|
|
print(
|
|
"\nFix tracked files:\n"
|
|
" git config core.autocrlf false\n"
|
|
" bash scripts/normalize_worktree_lf.sh",
|
|
file=sys.stderr,
|
|
)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|