#!/usr/bin/env python
# From:
# http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html#id403945
#
# Add this file to .hgrc as pretxncommit hook:
#
# [hooks]
# pretxncommit.whitespace = dotfiles/hg/check_whitespace.py
from __future__ import print_function
import os, sys, pwd
import re
from subprocess import check_output
def trailing_whitespace_filter(difflines):
linenum, header = 0, False
for line in difflines:
# Remove the final newline character from each line, or it will
# be detected as 'trailing whitespace' further on.
while 1 <= len(line) and line[-1] in ['\n', '\r']:
line = line[:-1]
if header:
# remember the name of the file that this diff affects
m = re.match(r'(?:---|\+\+\+) ([^\t]+)', line)
if m and m.group(1) != '/dev/null':
filename = m.group(1).split('/', 1)[-1].strip()
if line.startswith('+++ '):
header = False
continue
if line.startswith('diff '):
header = True
continue
# hunk header - save the line number
m = re.match(r'@@ -\d+,\d+ \+(\d+),', line)
if m:
linenum = int(m.group(1))
continue
# hunk body - check for an added line with trailing whitespace
m = re.match(r'^\+.*\s$', line)
if m:
yield filename, linenum
if line and line[0] in ' +':
linenum += 1
def is_trailing_whitespace_added():
added = 0
filenames = []
for filename, linenum in trailing_whitespace_filter(os.popen('hg export tip')):
print(
('whitespace: {0}:{1}: trailing whitespace added'.format(filename, linenum)),
file=sys.stderr
)
added += 1
filenames.append(filename)
return added, filenames
def is_merge():
parents = check_output(['hg', 'parents', '--template', '{rev}\n']).rstrip().split('\n')
return 1 < len(parents)
def is_run_as_root():
return os.getuid() == 0
# pretxncommit
def hook(ui, repo, hooktype, node, **kwargs):
from pprint import pprint
trailing_whitespace, filenames = is_trailing_whitespace_added()
if is_merge():
# We always allow merges to proceed.
if trailing_whitespace:
print("whitespace: Am I my brother's keeper?", file=sys.stderr)
print("whitespace: Ignoring trailing whitespace introduced during merge", file=sys.stderr)
else:
print('whitespace: Merge commit, not enforcing whitespace', file=sys.stderr)
return 0
if is_run_as_root():
print("whitespace: Ignoring whitespace when root, for etckeeper's sake", file=sys.stderr)
return 0
if trailing_whitespace:
# save the commit message so we don't need to retype it, and exit non-zero.
os.system('hg tip --template "{desc}" > .hg/last-message.txt')
print('whitespace: Trailing whitespace detected', file=sys.stderr)
print('whitespace: Commit message saved to .hg/last-message.txt', file=sys.stderr)
print(
"whitespace: # sed -i 's, *$,,' {filenames}".format(
filenames=' '.join(filenames)
),
file=sys.stderr
)
return 1