tests: use basic format code "%Y" instead of "%s" for test portability
On Windows, strftime() doesn't support format code "%s", and it causes
"invalid format string" error.
https://msdn.microsoft.com/en-us/library/fe06s4ak.aspx
test-command-template.t examines not seconds value in UTC, but
arithmetic calculation. Therefore, using format code "%Y" instead of
"%s" should be reasonable.
FYI:
- Python standard library reference doesn't list "%s" up in format
code list required for "C standard (1989 version)", even though it
also mentions that additional format codes are required for "C
standard (1999 version)"
https://docs.python.org/2.7/library/datetime.html#strftime-and-strptime-behavior
- The Open Group Base Specifications Issue 7 (IEEE Std 1003.1-2008,
2016 Edition) doesn't require strftime to support format code "%s"
http://pubs.opengroup.org/onlinepubs/
9699919799/functions/strftime.html
- "man strftime" of (Open/Oracle) Solaris and Mac OS X (= UNIX
certified OSs) describes about format code "%s"
#!/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
from __future__ import absolute_import, print_function
import os
import re
import sys
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"),
# Forbid "_" in function name.
#
# We skip the check for cffi related functions. They use names mapping the
# name of the C function. C function names may contain "_".
(r"\n\+[ \t]+def (?!cffi)[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:
for m in re.finditer(exp, commit):
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)