##// END OF EJS Templates
check-code: there must also be whitespace between ')' and operator...
check-code: there must also be whitespace between ')' and operator The check pattern only checked for whitespace between keyword and operator. Now it also warns: > x = f(),7 missing whitespace after , > x = f()+7 missing whitespace in expression

File last commit:

r18054:b35e3364 default
r18054:b35e3364 default
Show More
check-code.py
454 lines | 16.0 KiB | text/x-python | PythonLexer
Matt Mackall
Introduce check-code.py...
r10281 #!/usr/bin/env python
#
# check-code - a style and portability checker for Mercurial
#
Matt Mackall
check-code: fix copyright date
r10290 # Copyright 2010 Matt Mackall <mpm@selenic.com>
Matt Mackall
Introduce check-code.py...
r10281 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Alecs King
check-code: add exit status...
r11816 import re, glob, os, sys
Thomas Arendsen Hein
check-code: check for gratuitous whitespace after Python keywords
r13074 import keyword
Matt Mackall
check-code: add a warnings level...
r10895 import optparse
Matt Mackall
Introduce check-code.py...
r10281
def repquote(m):
Benoit Boissinot
check-code: improve quote detection regexp, add tests
r10722 t = re.sub(r"\w", "x", m.group('text'))
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 t = re.sub(r"[^\s\nx]", "o", t)
Benoit Boissinot
check-code: improve quote detection regexp, add tests
r10722 return m.group('quote') + t + m.group('quote')
Matt Mackall
Introduce check-code.py...
r10281
Benoit Boissinot
check-code: more tests and more robust python filtering
r10727 def reppython(m):
comment = m.group('comment')
if comment:
return "#" * len(comment)
return repquote(m)
Matt Mackall
Introduce check-code.py...
r10281
def repcomment(m):
return m.group(1) + "#" * len(m.group(2))
def repccomment(m):
t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
return m.group(1) + t + "*/"
def repcallspaces(m):
t = re.sub(r"\n\s+", "\n", m.group(2))
return m.group(1) + t
def repinclude(m):
return m.group(1) + "<foo>"
def rephere(m):
t = re.sub(r"\S", "x", m.group(2))
return m.group(1) + t
testpats = [
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 [
Mads Kiilerich
check-code: put grouping around regexps generated from testpats...
r16495 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
Martin Geisler
check-code.py: make help strings consistent
r10374 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
Matt Mackall
tests: remove sed -i from test-record
r16332 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
Mads Kiilerich
test-alias: adapt for Windows...
r16965 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
Martin Geisler
check-code: catch "echo -n" in tests
r11884 (r'echo -n', "don't use 'echo -n', use printf"),
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
Martin Geisler
check-code.py: make help strings consistent
r10374 (r'head -c', "don't use 'head -c', use 'dd'"),
Matt Mackall
tests: use md5sum.py instead of sha1sum, add check
r15389 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
Martin Geisler
check-code.py: make help strings consistent
r10374 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
Mads Kiilerich
check-code: 'printf \0' is apparently fine - accept it in check-code...
r16486 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
Martin Geisler
check-code.py: make help strings consistent
r10374 (r'printf.*\\x', "don't use printf \\x, use Python"),
Matt Mackall
Introduce check-code.py...
r10281 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
(r'rm -rf \*', "don't use naked rm -rf, target a directory"),
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
Matt Mackall
Introduce check-code.py...
r10281 "use egrep for extended grep syntax"),
(r'/bin/', "don't use explicit paths for tools"),
(r'[^\n]\Z', "no trailing newline"),
Mads Kiilerich
test-merge-default and check-code.py: No "export x=x" in sh
r10658 (r'export.*=', "don't export and assign at once"),
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 (r'^source\b', "don't use 'source', use '.'"),
Dan Villiom Podlaski Christiansen
tests: compatibility fix....
r12367 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
Matt Mackall
tests: fix check-code detection of anchored expressions, fix echo -n usage
r15364 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
Mads Kiilerich
tests: don't use 'test -e'...
r15282 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
Mads Kiilerich
tests: don't use alias...
r16013 (r'^alias\b.*=', "don't use alias, use a function"),
Mads Kiilerich
tests: solaris sh can not negate exit status with '!'
r16485 (r'if\s*!', "don't use '!' to negate exit status"),
Mads Kiilerich
tests: don't use /dev/urandom for largefiles testing...
r16494 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
Mads Kiilerich
tests: use 'do sleep 0' instead of 'do true', also on first line of command...
r16496 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
Mads Kiilerich
tests: avoid tab indent on all kinds of lines of sh commands
r16497 (r'^( *)\t', "don't use tabs to indent"),
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 ],
# warnings
Mads Kiilerich
tests: run most check-code sh checks on continued lines too...
r16672 [
(r'^function', "don't use 'function', use old style"),
(r'^diff.*-\w*N', "don't use 'diff -N'"),
(r'\$PWD', "don't use $PWD, use `pwd`"),
(r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
]
Matt Mackall
Introduce check-code.py...
r10281 ]
testfilters = [
(r"( *)(#([^\n]*\S)?)", repcomment),
(r"<<(\S+)((.|\n)*?\n\1)", rephere),
]
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 uprefix = r"^ \$ "
Matt Mackall
check-code: add some basic support for unified tests
r12364 utestpats = [
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 [
Mads Kiilerich
check-code: fix check for trailing whitespace on continued lines too...
r17347 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
Mads Kiilerich
tests: unify the last sh tests...
r16673 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
"use regex test output patterns instead of sed"),
Matt Mackall
check-code: add some basic support for unified tests
r12364 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
Patrick Mezard
test-svn-subrepo: fix reference output for svn 1.7...
r15607 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
Matt Mackall
check-code: add some basic support for unified tests
r12364 (uprefix + r'.*\|\| echo.*(fail|error)',
"explicit exit code checks unnecessary"),
(uprefix + r'set -e', "don't use set -e"),
Mads Kiilerich
tests: fix incorrect markup of continued lines of sh commands
r16487 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
Mads Kiilerich
check-code: verify that 'saved backup bundle to ...' is '(glob)'ed...
r17111 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
"use (glob) to match Windows paths too"),
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 ],
# warnings
[]
Matt Mackall
check-code: add some basic support for unified tests
r12364 ]
Mads Kiilerich
check-code: fix checking for sh style in .t tests...
r14203 for i in [0, 1]:
for p, m in testpats[i]:
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 if p.startswith(r'^'):
Mads Kiilerich
tests: run most check-code sh checks on continued lines too...
r16672 p = r"^ [$>] (%s)" % p[1:]
Mads Kiilerich
check-code: fix checking for sh style in .t tests...
r14203 else:
Mads Kiilerich
tests: run most check-code sh checks on continued lines too...
r16672 p = r"^ [$>] .*(%s)" % p
Mads Kiilerich
check-code: fix checking for sh style in .t tests...
r14203 utestpats[i].append((p, m))
Matt Mackall
check-code: add some basic support for unified tests
r12364
utestfilters = [
Idan Kamara
check-code: replace heredocs in unified tests...
r17711 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
Matt Mackall
check-code: add some basic support for unified tests
r12364 (r"( *)(#([^\n]*\S)?)", repcomment),
]
Matt Mackall
Introduce check-code.py...
r10281 pypats = [
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 [
Renato Cunha
check-code: check for tuple parameter unpacking (missing in py3k)
r11568 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
"tuple parameter unpacking not available in Python 3+"),
(r'lambda\s*\(.*,.*\)',
"tuple parameter unpacking not available in Python 3+"),
Renato Cunha
check-code: added a check for calls to the builtin cmp function
r11764 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
Renato Cunha
check-code: added check for reduce usage
r11569 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
Martin Geisler
check-code: catch dict.has_key
r11602 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
Matt Mackall
Introduce check-code.py...
r10281 (r'^\s*\t', "don't use tabs"),
Matt Mackall
check-code: import some pylint checks
r10412 (r'\S;\s*\n', "semicolon"),
Matt Mackall
check-code: check for % inside _()
r16234 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
(r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
Mads Kiilerich
check-code: there must also be whitespace between ')' and operator...
r18054 (r'(\w|\)),\w', "missing whitespace after ,"),
(r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
Mads Kiilerich
avoid using abbreviations that look like spelling errors
r17428 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
Thomas Arendsen Hein
check-code: catch yield inside try/finally (with tests)...
r17620 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
r'((?:\n|\1\s.*\n)+?)\1finally:',
'no yield inside try/finally in Python 2.4'),
Brodie Rao
check-code: promote 80+ character line warning to an error
r16702 (r'.{81}', "line too long"),
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
Matt Mackall
Introduce check-code.py...
r10281 (r'[^\n]\Z', "no trailing newline"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
Brodie Rao
cleanup: eradicate long lines
r16683 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
# "don't use underbars in identifiers"),
Matt Mackall
check-code: enable camelcase check, fix up problems
r15457 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
"don't use camelcase in identifiers"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
Matt Mackall
check-code: check thyself
r10286 "linebreak after :"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
(r'class\s[^( \n]+\(\):',
Thomas Arendsen Hein
check-code: fix class style checking (with tests)...
r14763 "class foo() not available in Python 2.4, use class foo(object)"),
Thomas Arendsen Hein
check-code: single check for Python keywords used as a function...
r13076 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
"Python keyword is not a function"),
Matt Mackall
check-code: import some pylint checks
r10412 (r',]', "unneeded trailing ',' in list"),
Matt Mackall
Introduce check-code.py...
r10281 # (r'class\s[A-Z][^\(]*\((?!Exception)',
# "don't capitalize non-exception classes"),
# (r'in range\(', "use xrange"),
# (r'^\s*print\s+', "avoid using print in core and extensions"),
(r'[\x80-\xff]', "non-ASCII character literal"),
(r'("\')\.format\(', "str.format() not available in Python 2.4"),
(r'^\s*with\s+', "with not available in Python 2.4"),
Matt Mackall
check-code: complain about set.isdisjoint
r14267 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
Matt Mackall
check-code: catch "except as"
r13160 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
Matt Mackall
check-code: catch os.path.relpath
r13161 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
Martin Geisler
check-code: reformat long lines
r11345 (r'(?<!def)\s+(any|all|format)\(',
"any/all/format not available in Python 2.4"),
Martin Geisler
check-code: add test for callable
r11522 (r'(?<!def)\s+(callable)\(',
Augie Fackler
check-code: disallow use of hasattr()...
r14978 "callable not available in Python 3, use getattr(f, '__call__', None)"),
Matt Mackall
Introduce check-code.py...
r10281 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
Thomas Arendsen Hein
check-code: check for gratuitous whitespace after Python keywords
r13074 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
"gratuitous whitespace after Python keyword"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
Matt Mackall
Introduce check-code.py...
r10281 # (r'\s\s=', "gratuitous whitespace before ="),
Pierre-Yves David
check-code: recognise %= as an operator
r17167 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
Martin Geisler
check-code: reformat long lines
r11345 "missing whitespace around operator"),
Pierre-Yves David
check-code: recognise %= as an operator
r17167 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
Martin Geisler
check-code: reformat long lines
r11345 "missing whitespace around operator"),
Pierre-Yves David
check-code: recognise %= as an operator
r17167 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
Martin Geisler
check-code: reformat long lines
r11345 "missing whitespace around operator"),
Pierre-Yves David
check-code: recognise %= as an operator
r17167 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
Martin Geisler
check-code: reformat long lines
r11345 "wrong whitespace around ="),
Matt Mackall
check-code: two more rules...
r10451 (r'raise Exception', "don't raise generic exceptions"),
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
(r' [=!]=\s+(True|False|None)',
"comparison with singleton, use 'is' or 'is not' instead"),
Martin Geisler
check-code: flag 0/1 used as constant Boolean expression
r14494 (r'^\s*(while|if) [01]:',
"use True/False for constant Boolean expression"),
Patrick Mezard
mq: replace hasattr() with util.safehasattr(), update check-code.py
r16416 (r'(?:(?<!def)\s+|\()hasattr',
Augie Fackler
check-code: disallow use of hasattr()...
r14978 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
Dan Villiom Podlaski Christiansen
check-code: disallow calling opener(...).read() and opener(..).write()
r14169 (r'opener\([^)]*\).read\(',
"use opener.read() instead"),
Mads Kiilerich
avoid using abbreviations that look like spelling errors
r17428 (r'BaseException', 'not in Python 2.4, use Exception'),
(r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
Dan Villiom Podlaski Christiansen
check-code: disallow calling opener(...).read() and opener(..).write()
r14169 (r'opener\([^)]*\).write\(',
"use opener.write() instead"),
(r'[\s\(](open|file)\([^)]*\)\.read\(',
"use util.readfile() instead"),
(r'[\s\(](open|file)\([^)]*\)\.write\(',
"use util.readfile() instead"),
(r'^[\s\(]*(open(er)?|file)\([^)]*\)',
"always assign an opened file to a variable, and close it afterwards"),
(r'[\s\(](open|file)\([^)]*\)\.',
"always assign an opened file to a variable, and close it afterwards"),
Matt Mackall
check-code: catch misspellings of descendant...
r14549 (r'(?i)descendent', "the proper spelling is descendAnt"),
Matt Mackall
check-code: don't mark debug messages for translation
r14709 (r'\.debug\(\_', "don't mark debug messages for translation"),
Martin Geisler
check-code: catch unnecessary s.strip().split() calls
r16590 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
Brodie Rao
check-code: ignore naked excepts with a "re-raise" comment...
r16705 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
Mads Kiilerich
check-code: indent 4 spaces in py files
r17299 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
Matt Mackall
check-code: move i18n check from warning to error
r17957 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
"missing _() in ui message (use () to hide false-positives)"),
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 ],
# warnings
[
]
Matt Mackall
Introduce check-code.py...
r10281 ]
pyfilters = [
Benoit Boissinot
check-code: more tests and more robust python filtering
r10727 (r"""(?msx)(?P<comment>\#.*?$)|
((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
(?P<text>(([^\\]|\\.)*?))
(?P=quote))""", reppython),
Matt Mackall
Introduce check-code.py...
r10281 ]
cpats = [
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 [
Matt Mackall
Introduce check-code.py...
r10281 (r'//', "don't use //-style comments"),
(r'^ ', "don't use spaces to indent"),
(r'\S\t', "don't use tabs except for indent"),
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
Brodie Rao
check-code: promote 80+ character line warning to an error
r16702 (r'.{81}', "line too long"),
Matt Mackall
Introduce check-code.py...
r10281 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
(r'return\(', "return is not a function"),
(r' ;', "no space before ;"),
(r'\w+\* \w+', "use int *foo, not int* foo"),
(r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
Matt Mackall
check-code: avoid false-positive on ++
r16413 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
Matt Mackall
Introduce check-code.py...
r10281 (r'\w,\w', "missing whitespace after ,"),
Matt Mackall
osutil: fix up check-code issues
r13736 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
Matt Mackall
Introduce check-code.py...
r10281 (r'^#\s+\w', "use #foo, not # foo"),
(r'[^\n]\Z', "no trailing newline"),
Dan Villiom Podlaski Christiansen
osutil: replace #import with #include, and add a check for it
r13748 (r'^\s*#import\b', "use only #include in standard C code"),
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 ],
# warnings
[]
Matt Mackall
Introduce check-code.py...
r10281 ]
cfilters = [
(r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
Benoit Boissinot
check-code: improve quote detection regexp, add tests
r10722 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
Matt Mackall
Introduce check-code.py...
r10281 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
(r'(\()([^)]+\))', repcallspaces),
]
timeless
check-code: check for repo in revlog and ui in util
r14137 inutilpats = [
[
(r'\bui\.', "don't use ui in util"),
],
# warnings
[]
]
inrevlogpats = [
[
(r'\brepo\.', "don't use repo in revlog"),
],
# warnings
[]
]
Matt Mackall
Introduce check-code.py...
r10281 checks = [
('python', r'.*\.(py|cgi)$', pyfilters, pypats),
('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
('c', r'.*\.c$', cfilters, cpats),
Matt Mackall
check-code: add some basic support for unified tests
r12364 ('unified test', r'.*\.t$', utestfilters, utestpats),
timeless
check-code: check for repo in revlog and ui in util
r14137 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
inrevlogpats),
('layering violation ui in util', r'mercurial/util\.py', pyfilters,
inutilpats),
Matt Mackall
Introduce check-code.py...
r10281 ]
Pierre-Yves David
code-code: Add a logfunc argument to checkfile...
r10719 class norepeatlogger(object):
def __init__(self):
self._lastseen = None
Matt Mackall
check-code: add --blame switch
r11604 def log(self, fname, lineno, line, msg, blame):
Pierre-Yves David
code-code: Add a logfunc argument to checkfile...
r10719 """print error related a to given line of a given file.
The faulty line will also be printed but only once in the case
of multiple errors.
Matt Mackall
Introduce check-code.py...
r10281
Pierre-Yves David
code-code: Add a logfunc argument to checkfile...
r10719 :fname: filename
:lineno: line number
:line: actual content of the line
:msg: error message
"""
msgid = fname, lineno, line
if msgid != self._lastseen:
Matt Mackall
check-code: add --blame switch
r11604 if blame:
print "%s:%d (%s):" % (fname, lineno, blame)
else:
print "%s:%d:" % (fname, lineno)
Pierre-Yves David
code-code: Add a logfunc argument to checkfile...
r10719 print " > %s" % line
self._lastseen = msgid
print " " + msg
_defaultlogger = norepeatlogger()
Matt Mackall
check-code: add --blame switch
r11604 def getblame(f):
lines = []
for l in os.popen('hg annotate -un %s' % f):
start, line = l.split(':', 1)
user, rev = start.split()
lines.append((line[1:-1], user, rev))
return lines
def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
Mads Kiilerich
check-code: add --nolineno option for hiding line numbers...
r15502 blame=False, debug=False, lineno=True):
Pierre-Yves David
code-code: Add a logfunc argument to checkfile...
r10719 """checks style and portability of a given file
:f: filepath
:logfunc: function used to report error
logfunc(filename, linenumber, linecontent, errormessage)
Mads Kiilerich
fix trivial spelling errors
r17424 :maxerr: number of error to display before aborting.
Mads Kiilerich
tests: keep track of all check-code.py warnings
r15873 Set to false (default) to report all errors
Pierre-Yves David
check-code: add a return value to checkfile function...
r10720
return True if no error is found, False otherwise.
Pierre-Yves David
code-code: Add a logfunc argument to checkfile...
r10719 """
Matt Mackall
check-code: add --blame switch
r11604 blamecache = None
Pierre-Yves David
check-code: add a return value to checkfile function...
r10720 result = True
Matt Mackall
Introduce check-code.py...
r10281 for name, match, filters, pats in checks:
timeless
check-code: adding debug flag
r14135 if debug:
print name, f
Matt Mackall
Introduce check-code.py...
r10281 fc = 0
if not re.match(match, f):
timeless
check-code: adding debug flag
r14135 if debug:
print "Skipping %s for %s it doesn't match %s" % (
name, match, f)
Matt Mackall
Introduce check-code.py...
r10281 continue
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp = open(f)
pre = post = fp.read()
fp.close()
Matt Mackall
check-code: add some ignore hints
r10287 if "no-" + "check-code" in pre:
timeless
check-code: adding debug flag
r14135 if debug:
print "Skipping %s for %s it has no- and check-code" % (
name, f)
Matt Mackall
check-code: add some ignore hints
r10287 break
Matt Mackall
Introduce check-code.py...
r10281 for p, r in filters:
post = re.sub(p, r, post)
Idan Kamara
check-code: separate warnings to avoid repetitive str.startswith
r14009 if warnings:
pats = pats[0] + pats[1]
else:
pats = pats[0]
Matt Mackall
Introduce check-code.py...
r10281 # print post # uncomment to show filtered version
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281
timeless
check-code: adding debug flag
r14135 if debug:
print "Checking %s for %s" % (name, f)
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281
prelines = None
errors = []
Brodie Rao
check-code: ignore naked excepts with a "re-raise" comment...
r16705 for pat in pats:
if len(pat) == 3:
p, msg, ignore = pat
else:
p, msg = pat
ignore = None
Mads Kiilerich
fix trivial spelling errors
r17424 # fix-up regexes for multi-line searches
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 po = p
# \s doesn't match \n
p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
# [^...] doesn't match newline
p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
#print po, '=>', p
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 pos = 0
n = 0
Matt Mackall
check-code: fix issues with finding patterns in unified tests, fix tests...
r15372 for m in re.finditer(p, post, re.MULTILINE):
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 if prelines is None:
prelines = pre.splitlines()
postlines = post.splitlines(True)
start = m.start()
while n < len(postlines):
step = len(postlines[n])
if pos + step > start:
break
pos += step
n += 1
l = prelines[n]
if "check-code" + "-ignore" in l:
if debug:
print "Skipping %s for %s:%s (check-code -ignore)" % (
name, f, n)
continue
Brodie Rao
check-code: ignore naked excepts with a "re-raise" comment...
r16705 elif ignore and re.search(ignore, l, re.MULTILINE):
continue
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 bd = ""
if blame:
bd = 'working directory'
if not blamecache:
blamecache = getblame(f)
if n < len(blamecache):
bl, bu, br = blamecache[n]
if bl == l:
bd = '%s@%s' % (bu, br)
Mads Kiilerich
check-code: add --nolineno option for hiding line numbers...
r15502 errors.append((f, lineno and n + 1, l, msg, bd))
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281 result = False
errors.sort()
for e in errors:
logfunc(*e)
fc += 1
Mads Kiilerich
tests: keep track of all check-code.py warnings
r15873 if maxerr and fc >= maxerr:
Matt Mackall
Introduce check-code.py...
r10281 print " (too many errors, giving up)"
break
Matt Mackall
check-code: support multiline matches like try/except/finally...
r15281
Pierre-Yves David
check-code: add a return value to checkfile function...
r10720 return result
Pierre-Yves David
check-code: Add a ``checkfile`` function...
r10717
Pierre-Yves David
check-code: Only call check-code if __name__ = "__main__"....
r10716 if __name__ == "__main__":
Matt Mackall
check-code: add a warnings level...
r10895 parser = optparse.OptionParser("%prog [options] [files]")
parser.add_option("-w", "--warnings", action="store_true",
help="include warning-level checks")
parser.add_option("-p", "--per-file", type="int",
help="max warnings per file")
Matt Mackall
check-code: add --blame switch
r11604 parser.add_option("-b", "--blame", action="store_true",
help="use annotate to generate blame info")
timeless
check-code: adding debug flag
r14135 parser.add_option("", "--debug", action="store_true",
help="show debug information")
Mads Kiilerich
check-code: add --nolineno option for hiding line numbers...
r15502 parser.add_option("", "--nolineno", action="store_false",
dest='lineno', help="don't show line numbers")
Matt Mackall
check-code: add a warnings level...
r10895
Mads Kiilerich
check-code: add --nolineno option for hiding line numbers...
r15502 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
lineno=True)
Matt Mackall
check-code: add a warnings level...
r10895 (options, args) = parser.parse_args()
if len(args) == 0:
Pierre-Yves David
check-code: Only call check-code if __name__ = "__main__"....
r10716 check = glob.glob("*")
else:
Matt Mackall
check-code: add a warnings level...
r10895 check = args
Matt Mackall
Introduce check-code.py...
r10281
Mads Kiilerich
check-code: fix return code initialization...
r15544 ret = 0
Pierre-Yves David
check-code: Only call check-code if __name__ = "__main__"....
r10716 for f in check:
Alecs King
check-code: add exit status...
r11816 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
Mads Kiilerich
check-code: add --nolineno option for hiding line numbers...
r15502 blame=options.blame, debug=options.debug,
lineno=options.lineno):
Alecs King
check-code: add exit status...
r11816 ret = 1
sys.exit(ret)