Mercurial > hg > check_whitespace
view check_whitespace.py @ 17:8d5ba09be6c5 default tip
Fix some mercurial-on-python3 incompatibilities.
author | Sjoerd Mullender <sjoerd@acm.org> |
---|---|
date | Thu, 03 Sep 2020 18:17:08 +0200 (2020-09-03) |
parents | 86405cf4b913 |
children |
line wrap: on
line source
#!/usr/bin/env python # # Mercurial hook to check for inappropriate whitespace. Currently it # only checks Python files. # # This script is based on the code in the Mercurial book # <http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html#id403945> '''hook to refuse commits that introduce some bad inputs. Inputs that are refused are conflict markers (rows of < or > characters), and tabs and trailing white space in Python sources. Usage: in your ~/.hgrc file add: [hooks] pretxncommit.whitespace = python:/path/to/check_whitespace.py:hook pretxnchangegroup.whitespace = python:/path/to/check_whitespace.py:hook ''' import re import os binary_suffixes = { b'.bam', b'.bmp', b'.bz2', b'.chm', b'.cpl', b'.dia', b'.dll', b'.gz', b'.ico', b'.pdf', b'.png', b'.rtf', b'.zip', } def trailing_whitespace(difflines): linenum = 0 header = False filename = '' fnre = re.compile(br'(?:---|\+\+\+) (?P<filename>[^\t\r\n]+)') lnre = re.compile(br'@@ -\d+,\d+ \+(?P<lineno>\d+),') wsre = re.compile(br'\+.*[ \t]$') tbre = re.compile(br'\+.*\t') resre = re.compile(br'\+(<<<<<<<|>>>>>>>|======= end)') adding = False islink = False # symlinks can have no newline at end for chunk in difflines: for line in chunk.split(b'\n'): if header: if line.startswith(b'new file mode'): islink = b'120000' in line # remember the name of the file that this diff affects m = fnre.match(line) if m is not None and m.group('filename') != b'/dev/null': filename = m.group('filename').split(b'/', 1)[-1] if line.startswith(b'+++ '): header = False continue if line.startswith(b'diff '): header = True adding = False islink = False continue # hunk header - save the line number m = lnre.match(line) if m is not None: linenum = int(m.group('lineno')) continue if header or not filename: continue if line.startswith(b'+'): adding = True elif line.startswith(b' ') or line.startswith(b'-'): adding = False elif adding \ and not islink \ and line.startswith(br'\ No newline at end of file') \ and not filename.endswith(b'vertoo.data') \ and not os.path.splitext(filename)[1] in binary_suffixes: adding = False yield filename, linenum, b'no newline at end of file' # hunk body - check for an added line with bad whitespace if filename[-3:] == b'.py' or filename[-5:] == b'.py.in': m = tbre.match(line) if m is not None: yield filename, linenum, b'TABs' # trailing whitespace, for now only in Python source m = wsre.match(line) if m is not None: if filename[-3:] == b'.py' or filename[-5:] == b'.py.in': yield filename, linenum, b'trailing whitespace' # conflict markers m = resre.match(line) if m is not None: yield filename, linenum, b'conflict marker' if line and line[0] in b' +': linenum += 1 def hook(ui, repo, hooktype, node=None, source=None, **kwargs): import os, sys, subprocess if hooktype not in [b'pretxnchangegroup', b'pretxncommit']: ui.write(b'Hook should be pretxncommit/pretxnchangegroup not "%s".' % hooktype) return 1 added = False branches = {} for rev in range(repo[node].rev(), len(repo)): branch = repo[rev].branch() if branch not in branches: # first time we see this branch, remember parents to diff against branches[branch] = repo[rev].parents() desc = 0 for d in repo[rev].descendants(): break else: # no descendants for this revision, check diff with saved parents for p in branches[branch]: for filename, linenum, msg in trailing_whitespace(repo[rev].diff(p)): ui.write(b'%s, line %d, branch %s: %s added\n' % (filename, linenum, branch, msg)) added = True if added: # save the commit message so we don't need to retype it if source != 'serve': cmtsv = os.path.join(b'.hg',b'commit.save') subprocess.call(['hg', 'tip', '--template', '{desc}'], stdout=open(cmtsv, 'w')) ui.write(b'commit message saved to %s\n' % cmtsv) return 1 if __name__ == '__main__': import sys sys.stderr.write('call this hook using the Python interface.\n' 'In your .hgrc file you should have:\n' 'pretxncommit.whitespace = python:<path-to-check_whitespace-directory>/check_whitespace.py:hook\n') sys.exit(1)