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
|
#!/usr/bin/env python
#
# Pre-commit linting hook.
#
# Install from root of repository with:
#
# cp tools/pre-commit-hook.py .git/hooks/pre-commit
import subprocess
import sys
import os
# Run lint.py from the scipy source tree
linters = [
'../../tools/lint.py',
'tools/lint.py',
'lint.py' # in case pre-commit hook is run from tools dir
]
linter = [f for f in linters if os.path.exists(f)][0]
unicode_checks = [
'../../tools/check_unicode.py',
'tools/check_unicode.py',
'check_unicode.py' # in case pre-commit hook is run from tools dir
]
unicode_check = [f for f in unicode_checks if os.path.exists(f)][0]
# names of files that were staged
# add '*.pxd', '*.pxi' once cython-lint supports it
p = subprocess.run(['git', 'diff',
'--cached', '--name-only', '-z',
'--diff-filter=ACMR',
'--', '*.py', '*.pyx'],
capture_output=True, check=True)
files = p.stdout.decode(sys.getfilesystemencoding()).split('\0')
files = [f for f in files if f]
# create a temporary copy of what would get committed, without unstaged
# modifications (e.g., only certain changes in a file may have been committed)
git_dir = os.environ.get('GIT_DIR', '.git')
work_dir = os.path.join(git_dir, '.pre-commit-work_dir')
p = subprocess.run(['git', 'write-tree'], capture_output=True, check=True)
tree_hash = p.stdout.decode('ascii').split('\n')[0]
p = subprocess.run(['git', 'commit-tree', '-p', 'HEAD',
tree_hash, '-m', '...'], capture_output=True, check=True)
fake_commit = p.stdout.decode('ascii').split('\n')[0]
if not os.path.isdir(work_dir):
subprocess.run(['git', 'clone', '-qns', git_dir, work_dir])
subprocess.run(['git', 'reset', '--quiet', '--hard', 'HEAD'],
env={}, cwd=work_dir, check=True)
subprocess.run(['git', 'checkout', '-q', fake_commit],
env={}, cwd=work_dir, check=True)
subprocess.run(['git', 'reset', '--quiet', '--hard', fake_commit],
env={}, cwd=work_dir, check=True)
if '--fix' in sys.argv:
print('Running linter to fix errors...')
p = subprocess.run([linter, '--fix', '--files'] + files)
# Discover which files were modified
p = subprocess.run([linter, '--fix', '--files'] + files, cwd=work_dir)
p = subprocess.run(['git', 'diff', '--name-only', '--', '*.py', '*.pyx'],
capture_output=True, check=True, cwd=work_dir)
files = p.stdout.decode(sys.getfilesystemencoding()).split('\0')
files = [f for f in files if f]
if files:
print('The following files were modified:')
print()
print('\n'.join(files))
else:
print('No files were modified.\n')
print('Please remember to `git add` modified files.')
sys.exit(p.returncode)
p = subprocess.run([linter, '--files'] + files, cwd=work_dir)
if p.returncode != 0:
print('!! Linting failed; please fix errors, `git add` files, and re-commit.')
print()
print('Some errors may be fixable automatically by running:')
print()
print(' ./tools/pre-commit-hook.py --fix')
sys.exit(p.returncode)
p = subprocess.run(unicode_check, cwd=work_dir)
if p.returncode != 0:
sys.exit(p.returncode)
|