-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpre-commit
More file actions
executable file
·144 lines (127 loc) · 5.09 KB
/
Copy pathpre-commit
File metadata and controls
executable file
·144 lines (127 loc) · 5.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env bash
# Codechu shared pre-commit hook — Python AST tabanlı i18n leak guard +
# conflict marker + large-file warn + .mo sync hint.
#
# Kurulum (her ürün repo'sunda):
# cp /path/to/codechu-org/hooks/pre-commit .git/hooks/pre-commit
# chmod +x .git/hooks/pre-commit
#
# Atlama: git commit --no-verify (sadece acil)
set -e
FAILED=0
# ─── 1. i18n leak guard (Python AST) ─────────────────────────────────
# Source kodda Türkçe-spesifik karakter içeren string literal varsa,
# docstring değilse, _()-wrapped değilse fail.
# Bilinen kasıtlı literal'lar exemption list'inde.
SRC_DIR=${SRC_DIR:-}
if [ -z "$SRC_DIR" ]; then
for candidate in disk_cleaner src lib; do
[ -d "$candidate" ] && SRC_DIR="$candidate" && break
done
fi
if [ -n "$SRC_DIR" ] && [ -d "$SRC_DIR" ] && command -v python3 >/dev/null; then
LEAKS=$(python3 - "$SRC_DIR" <<'PY'
import ast
import os
import re
import sys
TURKISH = re.compile(r'[şŞıİğĞçÇöÖüÜ]')
# Kasıtlı Türkçe literal'lar (UI dışı, source code mantığı için)
EXEMPT_LITERALS = {
"Türkçe", # native language name for picker
"AKTİF", # backward-compat data marker
"İndirilenler", # standard Turkish locale dir name (file path)
"Resimler", # standard Turkish locale dir name
}
EXEMPT_FILES = {"i18n.py"} # i18n wrapper has Turkish examples in comments
src = sys.argv[1]
problems = []
for root, _, files in os.walk(src):
for f in files:
if not f.endswith(".py"):
continue
if f in EXEMPT_FILES:
continue
path = os.path.join(root, f)
try:
with open(path, encoding="utf-8") as fp:
source = fp.read()
tree = ast.parse(source)
except SyntaxError:
continue
# Map: docstring node IDs (skip them)
docstring_ids = set()
for node in ast.walk(tree):
if isinstance(node, (ast.Module, ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
ds = ast.get_docstring(node, clean=False)
if ds and node.body:
first = node.body[0]
if isinstance(first, ast.Expr) and isinstance(first.value, ast.Constant):
docstring_ids.add(id(first.value))
# _()-wrapped IDs (gettext call)
wrapped_ids = set()
for node in ast.walk(tree):
if isinstance(node, ast.Call):
fname = ""
if isinstance(node.func, ast.Name):
fname = node.func.id
elif isinstance(node.func, ast.Attribute):
fname = node.func.attr
if fname in ("_", "gettext", "ngettext", "pgettext"):
for arg in node.args:
if isinstance(arg, ast.Constant):
wrapped_ids.add(id(arg))
# Walk string Constants
for node in ast.walk(tree):
if not isinstance(node, ast.Constant):
continue
if not isinstance(node.value, str):
continue
if id(node) in docstring_ids or id(node) in wrapped_ids:
continue
text = node.value
if not TURKISH.search(text):
continue
if text in EXEMPT_LITERALS:
continue
# Substring of exempt literal? (örn. "AKTİF proje" — kısmi compat)
if any(lit in text for lit in EXEMPT_LITERALS):
continue
problems.append(f"{path}:{node.lineno}: {text!r}")
for p in problems:
print(p)
PY
)
if [ -n "$LEAKS" ]; then
echo "✗ i18n leak: Türkçe string literal — _() ile sar veya EXEMPT_LITERALS'a ekle:"
echo "$LEAKS"
FAILED=1
fi
fi
# ─── 2. Conflict marker / whitespace check ──────────────────────────
if ! git diff --cached --check >/dev/null 2>&1; then
echo "✗ Whitespace error or conflict marker:"
git diff --cached --check
FAILED=1
fi
# ─── 3. Large file warn (>1MB) ─────────────────────────────────────
big=$(git diff --cached --name-only --diff-filter=A | \
xargs -I{} sh -c 'test -f "{}" && find "{}" -size +1M 2>/dev/null' 2>/dev/null | head -5)
if [ -n "$big" ]; then
echo "⚠ Büyük dosya eklenmiş (>1MB) — git LFS düşün:"
echo "$big"
fi
# ─── 4. .po → .mo sync hint ─────────────────────────────────────────
if [ -d "po" ] && [ -f "po/messages.pot" ]; then
if git diff --cached --name-only | grep -q "po/.*\.po$"; then
if ! git diff --cached --name-only | grep -q "locale/.*\.mo$"; then
echo "⚠ .po değişti ama .mo regenerate edilmedi — 'cd po && make compile'"
fi
fi
fi
if [ "$FAILED" = "1" ]; then
echo
echo "Commit reddedildi. Düzeltip tekrar deneyin (veya --no-verify acil durumda)."
exit 1
fi
exit 0