Last active
June 5, 2022 14:46
-
-
Save jbylund/2bfde62b0bc7a5261747 to your computer and use it in GitHub Desktop.
pre-commit
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/python | |
import subprocess | |
import os | |
import json | |
import sys | |
def get_staged_files(): | |
return subprocess.check_output("git diff --cached --name-only".split()).strip().split('\n') | |
class Check(object): | |
def __init__(self, filetype=None, check_command=None): | |
self.filetype = filetype | |
self.check_command = check_command | |
def check_file(self, ifilename): | |
exit_code = 0 | |
exit_code |= self.check_trailing_whitespace(ifilename) | |
exit_code |= self.check_filesize(ifilename) | |
if self.check_command is not None: | |
dev_null = open(os.devnull, 'w') | |
check_command = self.check_command.format(ifilename).split() | |
check_process = subprocess.Popen(check_command, stderr=subprocess.PIPE, stdout=dev_null) | |
if check_process.wait() != 0: | |
print >> sys.stderr, """ERROR: "{}" is not valid {}""".format(ifilename, self.filetype) | |
print >> sys.stderr, check_process.stderr.read().strip() | |
print >> sys.stderr | |
exit_code |= 1 | |
if 'python' == self.filetype: # cleanup for python files | |
compiled_name = "{}c".format(ifilename) | |
os.path.exists(compiled_name) and os.remove(compiled_name) | |
return exit_code | |
def check_trailing_whitespace(self, ifilename): | |
exit_code = 0 | |
with open(ifilename) as infile: | |
for lineno, line in enumerate(infile): | |
line = line.rstrip('\n\r') | |
if line != line.rstrip(): | |
print """ERROR: Trailing whitespace in "{}", at line {}.""".format(infile.name, lineno + 1) | |
exit_code = 1 | |
return exit_code | |
def check_filesize(self, ifilename): | |
if os.stat(ifilename).st_size > 545048: | |
print >> sys.stderr, """ERROR: "{}" is larger than 5mb, it's probably not code (at the very least it should be modularized).""".format(ifilename) | |
return 1 | |
return 0 | |
class FileChecker(object): | |
checks = { | |
'py': Check(filetype='python', check_command="python -m py_compile {}"), | |
'php': Check(filetype='php', check_command="php -l {}"), | |
'json': Check(filetype='json', check_command="python -m json.tool {}"), | |
'bash': Check(filetype='bash', check_command="bash -n {}"), | |
'sh': Check(filetype='bash', check_command="bash -n {}") | |
} | |
def check_file(self, ifilename): | |
_, _, extension = ifilename.rpartition('.') | |
checker = self.checks.get(extension, Check()) | |
return checker.check_file(ifilename) | |
def main(): | |
staged_files = get_staged_files() | |
exit_code = 0 | |
filechecker = FileChecker() | |
for ifile in staged_files: | |
if not os.path.isfile(ifile): | |
continue | |
try: | |
exit_code |= filechecker.check_file(ifile) | |
except Exception as oops: | |
print >> sys.stderr, """WARNING: Check logic failed on "{}".""".format(ifile), oops | |
if exit_code: | |
print >> sys.stderr, "ERROR: Rejecting this commit, please fix issues and try again." | |
sys.exit(exit_code) | |
if "__main__" == __name__: | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment