#!/usr/bin/env python
# Check that the input file has no external include guards.
# Returns with 0 exit code on success, 1 otherwise.
import re
import sys
import subprocess
def git(*args, **kwargs):
return subprocess.check_output(['git'] + list(args), **kwargs)
def get_changed_paths(filter):
output = git('diff', '--cached', '--name-only', '-z', '--diff-filter='+filter)
return output.split('\0')[:-1] # remove trailing ''
def get_against():
try:
head = git('rev-parse', '--verify', 'HEAD', stderr=None)
except subprocess.CalledProcessError:
# Initial commit: diff against an empty tree object
return '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
else:
return 'HEAD'
against = get_against()
success = True
def croak(path, line, msg, *args):
global success
success = False
if path is not None:
sys.stderr.write("%s:%d: " % (path, line or 0))
sys.stderr.write(msg % args if args else msg)
if msg[-1] != '\n':
sys.stderr.write('\n')
def check_filenames():
try:
allownonascii = git('config', '--get', '--bool', 'hooks.allownonascii')
except subprocess.CalledProcessError:
pass
else:
if allownonascii == 'true':
return
for path in get_changed_paths('ACR'):
try:
path.decode('ascii')
except UnicodeDecodeError:
croak(path, 0, "Non-ASCII file name")
def check_whitespace():
try:
git('diff-index', '--check', '--cached', against, stderr=None)
except subprocess.CalledProcessError as e:
sys.stderr.write(e.output)
global success
success = False
guard_re = re.compile('^[ \t]*#\s*ifndef\s+_.*?_H(PP)?\n'
'\s*#\s*include\s+(".*?")\s*\n'
'\s*#\s*endif.*?$',
re.MULTILINE)
def check_external_guards (infile):
contents = infile.read()
for m in guard_re.finditer(contents):
lineno = 1 + contents[:m.start()].count('\n')
croak(infile.name, lineno, "External include guard")
croak(None, None, m.group(0))
def check_changed_files():
for path in get_changed_paths('AM'):
check_external_guards(open(path))
def main():
check_filenames()
check_changed_files()
check_whitespace()
if not success:
exit(1)
if __name__ == '__main__':
main()