1#!/usr/bin/env python 2 3# Check that the input file has no external include guards. 4# Returns with 0 exit code on success, 1 otherwise. 5 6import re 7import sys 8import subprocess 9 10def git(*args, **kwargs): 11 return subprocess.check_output(['git'] + list(args), **kwargs) 12 13def get_changed_paths(filter): 14 output = git('diff', '--cached', '--name-only', '-z', '--diff-filter='+filter) 15 return output.split('\0')[:-1] # remove trailing '' 16 17def get_against(): 18 try: 19 head = git('rev-parse', '--verify', 'HEAD', stderr=None) 20 except subprocess.CalledProcessError: 21 # Initial commit: diff against an empty tree object 22 return '4b825dc642cb6eb9a060e54bf8d69288fbee4904' 23 else: 24 return 'HEAD' 25 26against = get_against() 27 28success = True 29 30def croak(path, line, msg, *args): 31 global success 32 success = False 33 if path is not None: 34 sys.stderr.write("%s:%d: " % (path, line or 0)) 35 sys.stderr.write(msg % args if args else msg) 36 if msg[-1] != '\n': 37 sys.stderr.write('\n') 38 39def check_filenames(): 40 try: 41 allownonascii = git('config', '--get', '--bool', 'hooks.allownonascii') 42 except subprocess.CalledProcessError: 43 pass 44 else: 45 if allownonascii == 'true': 46 return 47 48 for path in get_changed_paths('ACR'): 49 try: 50 path.decode('ascii') 51 except UnicodeDecodeError: 52 croak(path, 0, "Non-ASCII file name") 53 54def check_whitespace(): 55 try: 56 git('diff-index', '--check', '--cached', against, stderr=None) 57 except subprocess.CalledProcessError as e: 58 sys.stderr.write(e.output) 59 global success 60 success = False 61 62guard_re = re.compile('^[ \t]*#\s*ifndef\s+_.*?_H(PP)?\n' 63 '\s*#\s*include\s+(".*?")\s*\n' 64 '\s*#\s*endif.*?$', 65 re.MULTILINE) 66 67def check_external_guards (infile): 68 contents = infile.read() 69 for m in guard_re.finditer(contents): 70 lineno = 1 + contents[:m.start()].count('\n') 71 croak(infile.name, lineno, "External include guard") 72 croak(None, None, m.group(0)) 73 74def check_changed_files(): 75 for path in get_changed_paths('AM'): 76 check_external_guards(open(path)) 77 78def main(): 79 check_filenames() 80 check_changed_files() 81 check_whitespace() 82 if not success: 83 exit(1) 84 85if __name__ == '__main__': 86 main() 87