Created
October 19, 2015 14:55
-
-
Save malloc47/12d79be6f59654cddc8c to your computer and use it in GitHub Desktop.
Python pre-commit hook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Inspired by: https://gist.github.com/thraxil/3123935 | |
# Differs from above link by using the results of `git show` | |
# instead of using `git stash`, which prevents unintended | |
# side-effects | |
import os | |
import re | |
import subprocess | |
import sys | |
import atexit | |
import traceback | |
gitcmd = 'git' | |
tmpfile = 'check.tmp' | |
CHECKS = [ | |
{ | |
'output': 'Checking for pdbs...', | |
'command': 'grep -n "import pdb" %s', | |
'match_files': ['.*\.py$'], | |
'ignore_files': ['.*scripts/.*'], | |
}, | |
{ | |
'output': 'Checking for print statements...', | |
'command': "grep -n '\sprint(' %s", | |
'match_files': ['.*\.py$'], | |
'ignore_files': ['.*scripts/.*'], | |
}, | |
{ | |
'output': 'Checking for tabs...', | |
'command': 'grep -n -P "\t" %s', | |
'match_files': ['.*\.py$'], | |
}, | |
{ | |
'output': 'Running pyflakes...', | |
'command': "pyflakes %s", | |
'match_files': ['.*\.py$'], | |
'ignore_files': ['.*scripts/.*'], | |
}, | |
{ | |
'output': 'Running pep8...', | |
# ignore line too long, whitespace before :, etc. | |
'command': "pep8 --ignore=E501,E203 %s", | |
'match_files': ['.*\.py$'], | |
'ignore_files': ['.*scripts/.*'], | |
} | |
] | |
CMDS = [ | |
{ | |
'output' : 'Running git whitespace check...', | |
'command' : 'git diff --cached --check' | |
} | |
] | |
def matches_file(file_name, match_files): | |
return any(re.compile(match_file).match(file_name) for match_file in match_files) | |
@atexit.register | |
def exit(): | |
try: | |
os.remove(tmpfile) | |
except: | |
pass | |
def check_files(files, check): | |
result = 0 | |
print(check['output']) | |
def strip_prefix(s,p): | |
return s[len(p):] if s.startswith(p) else s | |
for file_name in files: | |
if not 'match_files' in check or matches_file(file_name, check['match_files']): | |
if not 'ignore_files' in check or not matches_file(file_name, check['ignore_files']): | |
process = subprocess.Popen(gitcmd | |
+ ' show :' | |
+ file_name | |
+ '> ' | |
+ tmpfile | |
+' && ' | |
+ check['command'] % 'check.tmp', | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
shell=True) | |
out, err = process.communicate() | |
if out or err: | |
prefix = '\t%s:' % file_name | |
output_lines = ['%s%s' % (prefix, strip_prefix(line,tmpfile+':')) | |
for line | |
in out.splitlines()] | |
print('\n'.join(output_lines)) | |
if err: | |
print(err) | |
result = 1 | |
return result | |
def main(all_files): | |
files = [] | |
if all_files: | |
for root, dirs, file_names in os.walk('.'): | |
for file_name in file_names: | |
files.append(os.path.join(root, file_name)) | |
else: | |
p = subprocess.Popen([ | |
gitcmd, | |
'diff-index', | |
'-z', | |
'--cached', | |
'HEAD', | |
'--name-only', | |
'--diff-filter=AM'], stdout=subprocess.PIPE) | |
f,err = p.communicate() | |
files = filter(bool,f.split('\0')) | |
result = 0 | |
# for one-off commands | |
for cmd in CMDS: | |
print(cmd['output']) | |
result = (subprocess.call(cmd['command'], shell=True) | |
or result) | |
# for command that must be run on multiple files | |
for check in CHECKS: | |
result = check_files(files, check) or result | |
if not result: | |
print('No errors found!') | |
else: | |
print('Errors found!') | |
sys.exit(result) | |
if __name__ == '__main__': | |
all_files = False | |
if len(sys.argv) > 1 and (sys.argv[1] == '--all-files' or sys.argv[1] == '-a'): | |
all_files = True | |
try: | |
main(all_files) | |
except KeyboardInterrupt: | |
print("Early termination requested...") | |
# always fail out when exiting early | |
sys.exit(1) | |
except Exception: | |
traceback.print_exc(file=sys.stdout) | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment