Share Pastebin
Guest
Public paste!

git pre-commit hook

By: a guest | Mar 22nd, 2010 | Syntax: Python | Size: 3.00 KB | Hits: 136 | Expires: Never
Copy text to clipboard
  1. #!/usr/bin/env python
  2.  
  3. import sys
  4. import subprocess
  5. import os
  6. import re
  7.  
  8. def syscmd(*args, **kw):
  9.     fail_ok = kw.get('fail_ok', False)
  10.     p = subprocess.Popen(args, stdout=subprocess.PIPE)
  11.     out, _ = p.communicate()
  12.     if not fail_ok and p.returncode != 0:
  13.         raise RuntimeError('%s # failed: %s' % (' '.join(args), p.returncode))
  14.     return out
  15.  
  16. def checkline(line, report_error, ext=None):
  17.     if re.search(r'console\.log', line):
  18.         report_error('console.log: %s' % line)
  19.  
  20.     if re.search(r'print[^\n]+', line):
  21.         report_error('print statement: %s' % line)
  22.  
  23.     if ext in ('js', 'py'):
  24.         if re.search(r'\s$', line):
  25.             report_error('Trailing whitespace: %s' % line)
  26.  
  27. def checkfile(filename, report_error):
  28.     if filename.endswith('py'):
  29.         out = syscmd('bin/django-lint', '-e', filename)
  30.  
  31.     if filename.startswith('media') and filename.endswith('js'):
  32.         p = subprocess.Popen(
  33.             ['bin/jslint', filename],
  34.             stdout=subprocess.PIPE
  35.         )
  36.         out, _ = p.communicate()
  37.         if 'No problems found in' not in out:
  38.             report_error('JSlint errors', filename=filename)
  39.             print >> sys.stderr, out
  40.  
  41. def difflines():
  42.     diff = syscmd('git', 'diff', '--cached', '-M')
  43.     filename = None
  44.     lineno = None
  45.     for line in diff.split('\n'):
  46.         m = re.match(r'^diff --git a/(.*) b/\1$', line)
  47.         if m:
  48.             filename = m.group(1)
  49.             continue
  50.         m = re.match(r'@@ -\S+ \+(\d+)', line)
  51.         if m:
  52.             lineno = int(m.group(1)) - 1
  53.             continue
  54.         if line.startswith('+++'):
  55.             continue
  56.         if line.startswith(' '):
  57.             lineno += 1
  58.             continue
  59.         if line.startswith('+'):
  60.             lineno += 1
  61.             yield line, filename, lineno
  62.  
  63. def check(report_error):
  64.     if os.environ.get('SKIPCHECKS'):
  65.         sys.exit(0)
  66.  
  67.     status = syscmd('git', 'status', fail_ok=True)
  68.     if 'Untracked files:' in status:
  69.         report_error('Untracked files')
  70.  
  71.     filenames = set()
  72.     ext = None
  73.     for line, filename, lineno in difflines():
  74.         ext = filename.partition('.')[2]
  75.         filenames.add(filename)
  76.         checkline(line, lambda why: report_error(why, lineno, filename), ext)
  77.  
  78.     if not os.environ.get('SKIPLINT'):
  79.         for filename in sorted(filenames):
  80.             checkfile(filename, report_error)
  81.  
  82. fail = False
  83. def run():
  84.     def report_error(why, line=None, filename=None):
  85.         global fail
  86.         if not fail:
  87.             print >> sys.stderr, "*"
  88.             print >> sys.stderr, "* Errors found:"
  89.             print >> sys.stderr, "*"
  90.         print >> sys.stderr, "* %s" % why
  91.         if line or filename:
  92.             extra = '' + ('line %d ' % line if line else '') + \
  93.                 ('in %s' % filename if filename else '')
  94.             print >> sys.stderr, "* %s" % extra
  95.         print "*"
  96.         fail = True
  97.  
  98.     check(report_error)
  99.  
  100.     return int(fail)
  101.  
  102. sys.exit(run())