-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathsafe-commit-hook.py
More file actions
executable file
·123 lines (97 loc) · 3.16 KB
/
safe-commit-hook.py
File metadata and controls
executable file
·123 lines (97 loc) · 3.16 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
#!/usr/bin/env python
import os
import json
import subprocess
import re
def get_repo_root():
output = subprocess.check_output('git rev-parse --show-toplevel', shell=True)
repo_root = output.split("\n")[0]
return os.path.join(repo_root)
def make_exact_matcher(str):
def m(target):
return str == target
return m
def make_regex_matcher(pattern):
prog = re.compile(pattern)
def m(target):
return prog.match(target)
return m
def make_str_matcher(p):
if p['type'] == 'regex':
return make_regex_matcher(p['pattern'])
elif p['type'] == 'match':
return make_exact_matcher(p['pattern'])
def make_filename_matcher(p):
def m(target_filename):
t = os.path.basename(target_filename)
return p['_match'](t)
return m
def make_extension_matcher(p):
def m(target_filename):
_, file_extension = os.path.splitext(target_filename)
file_extension = file_extension[1:]
return p['_match'](file_extension)
return m
def make_path_matcher(p):
def m(target_filename):
return p['_match'](target_filename)
return m
def make_matcher(p):
p['_match'] = make_str_matcher(p)
if p['part'] == 'filename':
return make_filename_matcher(p)
if p['part'] == 'extension':
return make_extension_matcher(p)
if p['part'] == 'path':
return make_path_matcher(p)
def read_patterns():
matchers = []
with open(DEFAULT_PATTERNS) as data_file:
data = json.load(data_file)
for p in data:
matcher = make_matcher(p)
if matcher:
p['matcher'] = matcher
matchers.append(p)
return matchers
def load_whitelist():
ignore = []
with open(WHITELIST) as wl:
for line in wl.readlines():
line = line.strip('\n')
path = os.path.join(REPO_ROOT, line)
ignore.append(path)
return ignore
def match_patterns(patterns, files, whitelist=None):
commit_safe = True
for f in files:
file_path = os.path.join(REPO_ROOT, f)
if whitelist and file_path in whitelist:
continue
else:
for p in patterns:
if p['matcher'](f):
if commit_safe:
print '\033[91m' + "[ERROR] Unable to complete git commit." + '\033[0m'
commit_safe = False
print "%s: %s" % (f, p['caption'])
if p['description']:
print p['description']
if not commit_safe:
exit(1)
def main():
global DEFAULT_PATTERNS, REPO_ROOT, WHITELIST
DEFAULT_PATTERNS = os.path.expanduser('~/.safe-commit-hook/git-deny-patterns.json')
REPO_ROOT = get_repo_root()
WHITELIST = os.path.join(REPO_ROOT, '.git-safe-commit-ignore')
cmd = 'git diff --name-only --cached'
result = subprocess.check_output(cmd, shell=True)
files = result.split("\n")
patterns = read_patterns()
if os.path.exists(WHITELIST):
whitelist = load_whitelist()
match_patterns(patterns, files, whitelist)
else:
match_patterns(patterns, files)
if __name__ == "__main__":
main()