Mercurial > hg
view contrib/check-commit @ 28008:86c4cbdaffee
revset: use manifest.matches in _follow revset
The old _follow revset iterated over every file in the commit and checked if it
matched. For repos with large manifests, this could take 500ms. By switching to
use manifest.matches() we can take advantage of the fastpaths built in to
manifest.py that allows iterating over only the files in the matcher when it's a
simple matcher. This brings the time spent down from 500ms to 0ms during simple
operations like 'hg log -f file.txt'.
author | Durham Goode <durham@fb.com> |
---|---|
date | Fri, 05 Feb 2016 13:30:25 -0800 |
parents | 1d095371de47 |
children | 897b2fcf079f |
line wrap: on
line source
#!/usr/bin/env python # # Copyright 2014 Matt Mackall <mpm@selenic.com> # # A tool/hook to run basic sanity checks on commits/patches for # submission to Mercurial. Install by adding the following to your # .hg/hgrc: # # [hooks] # pretxncommit = contrib/check-commit # # The hook can be temporarily bypassed with: # # $ BYPASS= hg commit # # See also: https://mercurial-scm.org/wiki/ContributingChanges import re, sys, os commitheader = r"^(?:# [^\n]*\n)*" afterheader = commitheader + r"(?!#)" beforepatch = afterheader + r"(?!\n(?!@@))" errors = [ (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"), (beforepatch + r".*[(]issue \d\d\d", "no space allowed between issue and number"), (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"), (commitheader + r"# User [^@\n]+\n", "username is not an email address"), (commitheader + r"(?!merge with )[^#]\S+[^:] ", "summary line doesn't start with 'topic: '"), (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"), (afterheader + r"[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"), (afterheader + r"\S*[^A-Za-z0-9-]\S*: ", "summary keyword should be most user-relevant one-word command or topic"), (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"), (afterheader + r".{79,}", "summary line too long (limit is 78)"), (r"\n\+\n \n", "adds double empty line"), (r"\n \n\+\n", "adds double empty line"), (r"\n\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"), ] word = re.compile('\S') def nonempty(first, second): if word.search(first): return first return second def checkcommit(commit, node = None): exitcode = 0 printed = node is None hits = [] for exp, msg in errors: m = re.search(exp, commit) if m: end = m.end() trailing = re.search(r'(\\n)+$', exp) if trailing: end -= len(trailing.group()) / 2 hits.append((end, exp, msg)) if hits: hits.sort() pos = 0 last = '' for n, l in enumerate(commit.splitlines(True)): pos += len(l) while len(hits): end, exp, msg = hits[0] if pos < end: break if not printed: printed = True print "node: %s" % node print "%d: %s" % (n, msg) print " %s" % nonempty(l, last)[:-1] if "BYPASS" not in os.environ: exitcode = 1 del hits[0] last = nonempty(l, last) return exitcode def readcommit(node): return os.popen("hg export %s" % node).read() if __name__ == "__main__": exitcode = 0 node = os.environ.get("HG_NODE") if node: commit = readcommit(node) exitcode = checkcommit(commit) elif sys.argv[1:]: for node in sys.argv[1:]: exitcode |= checkcommit(readcommit(node), node) else: commit = sys.stdin.read() exitcode = checkcommit(commit) sys.exit(exitcode)