Mercurial > hg
annotate contrib/check-code.py @ 15364:572c22c88be6 stable
tests: fix check-code detection of anchored expressions, fix echo -n usage
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Wed, 26 Oct 2011 12:56:27 -0500 |
parents | 24856af7237c |
children | 695ac6aca77f |
rev | line source |
---|---|
10281 | 1 #!/usr/bin/env python |
2 # | |
3 # check-code - a style and portability checker for Mercurial | |
4 # | |
10290
7cc60de189d7
check-code: fix copyright date
Matt Mackall <mpm@selenic.com>
parents:
10287
diff
changeset
|
5 # Copyright 2010 Matt Mackall <mpm@selenic.com> |
10281 | 6 # |
7 # This software may be used and distributed according to the terms of the | |
8 # GNU General Public License version 2 or any later version. | |
9 | |
11816
e1359ad582f6
check-code: add exit status
Alecs King <alecsk@gmail.com>
parents:
11764
diff
changeset
|
10 import re, glob, os, sys |
13074
637627f31c74
check-code: check for gratuitous whitespace after Python keywords
Thomas Arendsen Hein <thomas@jtah.de>
parents:
13031
diff
changeset
|
11 import keyword |
10895
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
12 import optparse |
10281 | 13 |
14 def repquote(m): | |
10722
c4fb2103e734
check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10720
diff
changeset
|
15 t = re.sub(r"\w", "x", m.group('text')) |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
16 t = re.sub(r"[^\s\nx]", "o", t) |
10722
c4fb2103e734
check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10720
diff
changeset
|
17 return m.group('quote') + t + m.group('quote') |
10281 | 18 |
10727
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
19 def reppython(m): |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
20 comment = m.group('comment') |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
21 if comment: |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
22 return "#" * len(comment) |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
23 return repquote(m) |
10281 | 24 |
25 def repcomment(m): | |
26 return m.group(1) + "#" * len(m.group(2)) | |
27 | |
28 def repccomment(m): | |
29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2)) | |
30 return m.group(1) + t + "*/" | |
31 | |
32 def repcallspaces(m): | |
33 t = re.sub(r"\n\s+", "\n", m.group(2)) | |
34 return m.group(1) + t | |
35 | |
36 def repinclude(m): | |
37 return m.group(1) + "<foo>" | |
38 | |
39 def rephere(m): | |
40 t = re.sub(r"\S", "x", m.group(2)) | |
41 return m.group(1) + t | |
42 | |
43 | |
44 testpats = [ | |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
45 [ |
10374
3aa35db5e38c
check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents:
10373
diff
changeset
|
46 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"), |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
48 (r'(^|\n)function', "don't use 'function', use old style"), |
10374
3aa35db5e38c
check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents:
10373
diff
changeset
|
49 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"), |
10373
e4c7972002e4
check-code.py: escape backslash
Mads Kiilerich <mads@kiilerich.com>
parents:
10291
diff
changeset
|
50 (r'echo.*\\n', "don't use 'echo \\n', use printf"), |
11884
932448701e7d
check-code: catch "echo -n" in tests
Martin Geisler <mg@lazybytes.net>
parents:
11599
diff
changeset
|
51 (r'echo -n', "don't use 'echo -n', use printf"), |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
52 (r'(^|\n)diff.*-\w*N', "don't use 'diff -N'"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
53 (r'(^| )wc[^|\n]*$', "filter wc output"), |
10374
3aa35db5e38c
check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents:
10373
diff
changeset
|
54 (r'head -c', "don't use 'head -c', use 'dd'"), |
3aa35db5e38c
check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents:
10373
diff
changeset
|
55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"), |
3aa35db5e38c
check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents:
10373
diff
changeset
|
56 (r'printf.*\\\d\d\d', "don't use 'printf \NNN', use Python"), |
3aa35db5e38c
check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents:
10373
diff
changeset
|
57 (r'printf.*\\x', "don't use printf \\x, use Python"), |
10281 | 58 (r'\$\(.*\)', "don't use $(expr), use `expr`"), |
59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"), | |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
60 (r'(^|\|\s*)grep (-\w\s+)*[^|\n]*[(|]\w', |
10281 | 61 "use egrep for extended grep syntax"), |
62 (r'/bin/', "don't use explicit paths for tools"), | |
63 (r'\$PWD', "don't use $PWD, use `pwd`"), | |
64 (r'[^\n]\Z', "no trailing newline"), | |
10658
95c7c4b7e67a
test-merge-default and check-code.py: No "export x=x" in sh
Mads Kiilerich <mads@kiilerich.com>
parents:
10451
diff
changeset
|
65 (r'export.*=', "don't export and assign at once"), |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
66 ('(^|\n)([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\\^', "^ must be quoted"), |
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
67 (r'(^|\n)source\b', "don't use 'source', use '.'"), |
12367
3acd5f7ab9d0
tests: compatibility fix.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
12366
diff
changeset
|
68 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"), |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
69 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
70 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"), |
14831
0407b7613e99
treediscovery: rename stop() in tests to fix failures on AIX.
Jim Hague <jim.hague@acm.org>
parents:
14763
diff
changeset
|
71 (r'stop\(\)', "don't use 'stop' as a shell function name"), |
15282
d4addef0ec74
tests: don't use 'test -e'
Mads Kiilerich <mads@kiilerich.com>
parents:
14978
diff
changeset
|
72 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"), |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
73 ], |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
74 # warnings |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
75 [] |
10281 | 76 ] |
77 | |
78 testfilters = [ | |
79 (r"( *)(#([^\n]*\S)?)", repcomment), | |
80 (r"<<(\S+)((.|\n)*?\n\1)", rephere), | |
81 ] | |
82 | |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
83 uprefix = r"(^|\n) \$\s*" |
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
84 uprefixc = r"(^|\n) > " |
12364
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
85 utestpats = [ |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
86 [ |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
87 (r'(^|\n)(\S| $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"), |
12366
c01dc9087d9a
tests: drop a bunch of sed calls from unified tests
Matt Mackall <mpm@selenic.com>
parents:
12364
diff
changeset
|
88 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"), |
12364
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
89 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"), |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
90 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"), |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
91 (uprefix + r'.*\|\| echo.*(fail|error)', |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
92 "explicit exit code checks unnecessary"), |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
93 (uprefix + r'set -e', "don't use set -e"), |
12743
4c4aeaab2339
check-code: add 'no tab indent' check for unified tests
Adrian Buehlmann <adrian@cadifra.com>
parents:
12367
diff
changeset
|
94 (uprefixc + r'( *)\t', "don't use tabs to indent"), |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
95 ], |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
96 # warnings |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
97 [] |
12364
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
98 ] |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
99 |
14203
b230922eb0c3
check-code: fix checking for sh style in .t tests
Mads Kiilerich <mads@kiilerich.com>
parents:
14169
diff
changeset
|
100 for i in [0, 1]: |
b230922eb0c3
check-code: fix checking for sh style in .t tests
Mads Kiilerich <mads@kiilerich.com>
parents:
14169
diff
changeset
|
101 for p, m in testpats[i]: |
15364
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
102 if p.startswith(r'(^|\n)'): |
572c22c88be6
tests: fix check-code detection of anchored expressions, fix echo -n usage
Matt Mackall <mpm@selenic.com>
parents:
15334
diff
changeset
|
103 p = uprefix + p[6:] |
14203
b230922eb0c3
check-code: fix checking for sh style in .t tests
Mads Kiilerich <mads@kiilerich.com>
parents:
14169
diff
changeset
|
104 else: |
b230922eb0c3
check-code: fix checking for sh style in .t tests
Mads Kiilerich <mads@kiilerich.com>
parents:
14169
diff
changeset
|
105 p = uprefix + p |
b230922eb0c3
check-code: fix checking for sh style in .t tests
Mads Kiilerich <mads@kiilerich.com>
parents:
14169
diff
changeset
|
106 utestpats[i].append((p, m)) |
12364
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
107 |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
108 utestfilters = [ |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
109 (r"( *)(#([^\n]*\S)?)", repcomment), |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
110 ] |
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
111 |
10281 | 112 pypats = [ |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
113 [ |
11568
d5d4e6a30613
check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents:
11522
diff
changeset
|
114 (r'^\s*def\s*\w+\s*\(.*,\s*\(', |
d5d4e6a30613
check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents:
11522
diff
changeset
|
115 "tuple parameter unpacking not available in Python 3+"), |
d5d4e6a30613
check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents:
11522
diff
changeset
|
116 (r'lambda\s*\(.*,.*\)', |
d5d4e6a30613
check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents:
11522
diff
changeset
|
117 "tuple parameter unpacking not available in Python 3+"), |
11764
16723af520b0
check-code: added a check for calls to the builtin cmp function
Renato Cunha <renatoc@gmail.com>
parents:
11672
diff
changeset
|
118 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"), |
11569
f8576644a222
check-code: added check for reduce usage
Renato Cunha <renatoc@gmail.com>
parents:
11568
diff
changeset
|
119 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"), |
11602
ba2520dd1e29
check-code: catch dict.has_key
Martin Geisler <mg@lazybytes.net>
parents:
11601
diff
changeset
|
120 (r'\.has_key\b', "dict.has_key is not available in Python 3+"), |
10281 | 121 (r'^\s*\t', "don't use tabs"), |
10412
5326800d6937
check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents:
10374
diff
changeset
|
122 (r'\S;\s*\n', "semicolon"), |
10281 | 123 (r'\w,\w', "missing whitespace after ,"), |
124 (r'\w[+/*\-<>]\w', "missing whitespace in expression"), | |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
125 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"), |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
126 (r'(?m)(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n' |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
127 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'), |
10281 | 128 (r'.{85}', "line too long"), |
15296
4b71c17caeb8
check-code: report suspicious string joins
Matt Mackall <mpm@selenic.com>
parents:
15284
diff
changeset
|
129 (r'(?m) x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'), |
10281 | 130 (r'[^\n]\Z', "no trailing newline"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
131 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
132 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"), |
10281 | 133 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
134 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+', |
10286 | 135 "linebreak after :"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
136 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"), |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
137 (r'class\s[^( \n]+\(\):', |
14763
b071cd58af50
check-code: fix class style checking (with tests)
Thomas Arendsen Hein <thomas@intevation.de>
parents:
14709
diff
changeset
|
138 "class foo() not available in Python 2.4, use class foo(object)"), |
13076
a861c7155f09
check-code: single check for Python keywords used as a function
Thomas Arendsen Hein <thomas@jtah.de>
parents:
13074
diff
changeset
|
139 (r'\b(%s)\(' % '|'.join(keyword.kwlist), |
a861c7155f09
check-code: single check for Python keywords used as a function
Thomas Arendsen Hein <thomas@jtah.de>
parents:
13074
diff
changeset
|
140 "Python keyword is not a function"), |
10412
5326800d6937
check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents:
10374
diff
changeset
|
141 (r',]', "unneeded trailing ',' in list"), |
10281 | 142 # (r'class\s[A-Z][^\(]*\((?!Exception)', |
143 # "don't capitalize non-exception classes"), | |
144 # (r'in range\(', "use xrange"), | |
145 # (r'^\s*print\s+', "avoid using print in core and extensions"), | |
146 (r'[\x80-\xff]', "non-ASCII character literal"), | |
147 (r'("\')\.format\(', "str.format() not available in Python 2.4"), | |
148 (r'^\s*with\s+', "with not available in Python 2.4"), | |
14267
6332c02b3d68
check-code: complain about set.isdisjoint
Matt Mackall <mpm@selenic.com>
parents:
14203
diff
changeset
|
149 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"), |
13160
07d08c130892
check-code: catch "except as"
Matt Mackall <mpm@selenic.com>
parents:
13076
diff
changeset
|
150 (r'^\s*except.* as .*:', "except as not available in Python 2.4"), |
13161
11eb53464e68
check-code: catch os.path.relpath
Matt Mackall <mpm@selenic.com>
parents:
13160
diff
changeset
|
151 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"), |
11345
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
152 (r'(?<!def)\s+(any|all|format)\(', |
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
153 "any/all/format not available in Python 2.4"), |
11522
eaa7666ad53f
check-code: add test for callable
Martin Geisler <mg@aragost.com>
parents:
11345
diff
changeset
|
154 (r'(?<!def)\s+(callable)\(', |
14978
5a0fdc715769
check-code: disallow use of hasattr()
Augie Fackler <durin42@gmail.com>
parents:
14831
diff
changeset
|
155 "callable not available in Python 3, use getattr(f, '__call__', None)"), |
10281 | 156 (r'if\s.*\selse', "if ... else form not available in Python 2.4"), |
13074
637627f31c74
check-code: check for gratuitous whitespace after Python keywords
Thomas Arendsen Hein <thomas@jtah.de>
parents:
13031
diff
changeset
|
157 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist), |
637627f31c74
check-code: check for gratuitous whitespace after Python keywords
Thomas Arendsen Hein <thomas@jtah.de>
parents:
13031
diff
changeset
|
158 "gratuitous whitespace after Python keyword"), |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
159 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"), |
10281 | 160 # (r'\s\s=', "gratuitous whitespace before ="), |
11345
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
161 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', |
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
162 "missing whitespace around operator"), |
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
163 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s', |
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
164 "missing whitespace around operator"), |
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
165 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', |
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
166 "missing whitespace around operator"), |
14303
e2be0bba0d83
check-code: add /= to operator list
Sune Foldager <cryo@cyanite.org>
parents:
14267
diff
changeset
|
167 (r'[^+=*/!<>&| -](\s=|=\s)[^= ]', |
11345
4b81f82b03e3
check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents:
11343
diff
changeset
|
168 "wrong whitespace around ="), |
10451
63a9bfad50ff
check-code: two more rules
Matt Mackall <mpm@selenic.com>
parents:
10412
diff
changeset
|
169 (r'raise Exception', "don't raise generic exceptions"), |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
170 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"), |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
171 (r' [=!]=\s+(True|False|None)', |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
172 "comparison with singleton, use 'is' or 'is not' instead"), |
14494
1ffeeb91c55d
check-code: flag 0/1 used as constant Boolean expression
Martin Geisler <mg@lazybytes.net>
parents:
14303
diff
changeset
|
173 (r'^\s*(while|if) [01]:', |
1ffeeb91c55d
check-code: flag 0/1 used as constant Boolean expression
Martin Geisler <mg@lazybytes.net>
parents:
14303
diff
changeset
|
174 "use True/False for constant Boolean expression"), |
14978
5a0fdc715769
check-code: disallow use of hasattr()
Augie Fackler <durin42@gmail.com>
parents:
14831
diff
changeset
|
175 (r'(?<!def)\s+hasattr', |
5a0fdc715769
check-code: disallow use of hasattr()
Augie Fackler <durin42@gmail.com>
parents:
14831
diff
changeset
|
176 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'), |
14169
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
177 (r'opener\([^)]*\).read\(', |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
178 "use opener.read() instead"), |
15334
24856af7237c
check-code: catch BaseException and os.path.relpath
Matt Mackall <mpm@selenic.com>
parents:
15296
diff
changeset
|
179 (r'BaseException', 'not in Py2.4, use Exception'), |
24856af7237c
check-code: catch BaseException and os.path.relpath
Matt Mackall <mpm@selenic.com>
parents:
15296
diff
changeset
|
180 (r'os\.path\.relpath', 'os.path.relpath is not in Py2.5'), |
14169
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
181 (r'opener\([^)]*\).write\(', |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
182 "use opener.write() instead"), |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
183 (r'[\s\(](open|file)\([^)]*\)\.read\(', |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
184 "use util.readfile() instead"), |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
185 (r'[\s\(](open|file)\([^)]*\)\.write\(', |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
186 "use util.readfile() instead"), |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
187 (r'^[\s\(]*(open(er)?|file)\([^)]*\)', |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
188 "always assign an opened file to a variable, and close it afterwards"), |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
189 (r'[\s\(](open|file)\([^)]*\)\.', |
1b4b82063ce2
check-code: disallow calling opener(...).read() and opener(..).write()
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
14137
diff
changeset
|
190 "always assign an opened file to a variable, and close it afterwards"), |
14549
48ec0763afbb
check-code: catch misspellings of descendant
Matt Mackall <mpm@selenic.com>
parents:
14494
diff
changeset
|
191 (r'(?i)descendent', "the proper spelling is descendAnt"), |
14709
6c7283faa967
check-code: don't mark debug messages for translation
Matt Mackall <mpm@selenic.com>
parents:
14549
diff
changeset
|
192 (r'\.debug\(\_', "don't mark debug messages for translation"), |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
193 ], |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
194 # warnings |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
195 [ |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
196 (r'.{81}', "warning: line over 80 characters"), |
14005
bb391e0515ba
check-code: warn about naked except clauses
Idan Kamara <idankk86@gmail.com>
parents:
13748
diff
changeset
|
197 (r'^\s*except:$', "warning: naked except clause"), |
11599
6fcc066c0c2c
check-code: warn about untranslated ui.warn calls
Martin Geisler <mg@lazybytes.net>
parents:
11522
diff
changeset
|
198 (r'ui\.(status|progress|write|note|warn)\([\'\"]x', |
10895
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
199 "warning: unwrapped ui message"), |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
200 ] |
10281 | 201 ] |
202 | |
203 pyfilters = [ | |
10727
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
204 (r"""(?msx)(?P<comment>\#.*?$)| |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
205 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!"))) |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
206 (?P<text>(([^\\]|\\.)*?)) |
62b8f15683f2
check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10723
diff
changeset
|
207 (?P=quote))""", reppython), |
10281 | 208 ] |
209 | |
210 cpats = [ | |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
211 [ |
10281 | 212 (r'//', "don't use //-style comments"), |
213 (r'^ ', "don't use spaces to indent"), | |
214 (r'\S\t', "don't use tabs except for indent"), | |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
215 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), |
10281 | 216 (r'.{85}', "line too long"), |
217 (r'(while|if|do|for)\(', "use space after while/if/do/for"), | |
218 (r'return\(', "return is not a function"), | |
219 (r' ;', "no space before ;"), | |
220 (r'\w+\* \w+', "use int *foo, not int* foo"), | |
221 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"), | |
222 (r'\S+ (\+\+|--)', "use foo++, not foo ++"), | |
223 (r'\w,\w', "missing whitespace after ,"), | |
13736
f3c4421e121c
osutil: fix up check-code issues
Matt Mackall <mpm@selenic.com>
parents:
13524
diff
changeset
|
224 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"), |
10281 | 225 (r'^#\s+\w', "use #foo, not # foo"), |
226 (r'[^\n]\Z', "no trailing newline"), | |
13748
26f8844d1757
osutil: replace #import with #include, and add a check for it
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
13736
diff
changeset
|
227 (r'^\s*#import\b', "use only #include in standard C code"), |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
228 ], |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
229 # warnings |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
230 [] |
10281 | 231 ] |
232 | |
233 cfilters = [ | |
234 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment), | |
10722
c4fb2103e734
check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10720
diff
changeset
|
235 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote), |
10281 | 236 (r'''(#\s*include\s+<)([^>]+)>''', repinclude), |
237 (r'(\()([^)]+\))', repcallspaces), | |
238 ] | |
239 | |
14137
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
240 inutilpats = [ |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
241 [ |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
242 (r'\bui\.', "don't use ui in util"), |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
243 ], |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
244 # warnings |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
245 [] |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
246 ] |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
247 |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
248 inrevlogpats = [ |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
249 [ |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
250 (r'\brepo\.', "don't use repo in revlog"), |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
251 ], |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
252 # warnings |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
253 [] |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
254 ] |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
255 |
10281 | 256 checks = [ |
257 ('python', r'.*\.(py|cgi)$', pyfilters, pypats), | |
258 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats), | |
259 ('c', r'.*\.c$', cfilters, cpats), | |
12364
e128fa4615f2
check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents:
11886
diff
changeset
|
260 ('unified test', r'.*\.t$', utestfilters, utestpats), |
14137
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
261 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters, |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
262 inrevlogpats), |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
263 ('layering violation ui in util', r'mercurial/util\.py', pyfilters, |
83a94c2fe6f4
check-code: check for repo in revlog and ui in util
timeless <timeless@mozdev.org>
parents:
14136
diff
changeset
|
264 inutilpats), |
10281 | 265 ] |
266 | |
10719
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
267 class norepeatlogger(object): |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
268 def __init__(self): |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
269 self._lastseen = None |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
270 |
11604
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
271 def log(self, fname, lineno, line, msg, blame): |
10719
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
272 """print error related a to given line of a given file. |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
273 |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
274 The faulty line will also be printed but only once in the case |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
275 of multiple errors. |
10281 | 276 |
10719
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
277 :fname: filename |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
278 :lineno: line number |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
279 :line: actual content of the line |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
280 :msg: error message |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
281 """ |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
282 msgid = fname, lineno, line |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
283 if msgid != self._lastseen: |
11604
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
284 if blame: |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
285 print "%s:%d (%s):" % (fname, lineno, blame) |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
286 else: |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
287 print "%s:%d:" % (fname, lineno) |
10719
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
288 print " > %s" % line |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
289 self._lastseen = msgid |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
290 print " " + msg |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
291 |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
292 _defaultlogger = norepeatlogger() |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
293 |
11604
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
294 def getblame(f): |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
295 lines = [] |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
296 for l in os.popen('hg annotate -un %s' % f): |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
297 start, line = l.split(':', 1) |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
298 user, rev = start.split() |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
299 lines.append((line[1:-1], user, rev)) |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
300 return lines |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
301 |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
302 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False, |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
303 blame=False, debug=False): |
10719
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
304 """checks style and portability of a given file |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
305 |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
306 :f: filepath |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
307 :logfunc: function used to report error |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
308 logfunc(filename, linenumber, linecontent, errormessage) |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
309 :maxerr: number of error to display before arborting. |
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
310 Set to None (default) to report all errors |
10720
fbcccf9ec58f
check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10719
diff
changeset
|
311 |
fbcccf9ec58f
check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10719
diff
changeset
|
312 return True if no error is found, False otherwise. |
10719
3be9ae49b628
code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10718
diff
changeset
|
313 """ |
11604
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
314 blamecache = None |
10720
fbcccf9ec58f
check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10719
diff
changeset
|
315 result = True |
10281 | 316 for name, match, filters, pats in checks: |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
317 if debug: |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
318 print name, f |
10281 | 319 fc = 0 |
320 if not re.match(match, f): | |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
321 if debug: |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
322 print "Skipping %s for %s it doesn't match %s" % ( |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
323 name, match, f) |
10281 | 324 continue |
13400
14f3795a5ed7
explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
13301
diff
changeset
|
325 fp = open(f) |
14f3795a5ed7
explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
13301
diff
changeset
|
326 pre = post = fp.read() |
14f3795a5ed7
explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
13301
diff
changeset
|
327 fp.close() |
10287
5da892be3497
check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents:
10286
diff
changeset
|
328 if "no-" + "check-code" in pre: |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
329 if debug: |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
330 print "Skipping %s for %s it has no- and check-code" % ( |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
331 name, f) |
10287
5da892be3497
check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents:
10286
diff
changeset
|
332 break |
10281 | 333 for p, r in filters: |
334 post = re.sub(p, r, post) | |
14009
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
335 if warnings: |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
336 pats = pats[0] + pats[1] |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
337 else: |
64de9ca66511
check-code: separate warnings to avoid repetitive str.startswith
Idan Kamara <idankk86@gmail.com>
parents:
14005
diff
changeset
|
338 pats = pats[0] |
10281 | 339 # print post # uncomment to show filtered version |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
340 |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
341 if debug: |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
342 print "Checking %s for %s" % (name, f) |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
343 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
344 prelines = None |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
345 errors = [] |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
346 for p, msg in pats: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
347 pos = 0 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
348 n = 0 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
349 for m in re.finditer(p, post): |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
350 if prelines is None: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
351 prelines = pre.splitlines() |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
352 postlines = post.splitlines(True) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
353 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
354 start = m.start() |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
355 while n < len(postlines): |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
356 step = len(postlines[n]) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
357 if pos + step > start: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
358 break |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
359 pos += step |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
360 n += 1 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
361 l = prelines[n] |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
362 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
363 if "check-code" + "-ignore" in l: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
364 if debug: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
365 print "Skipping %s for %s:%s (check-code -ignore)" % ( |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
366 name, f, n) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
367 continue |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
368 bd = "" |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
369 if blame: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
370 bd = 'working directory' |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
371 if not blamecache: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
372 blamecache = getblame(f) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
373 if n < len(blamecache): |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
374 bl, bu, br = blamecache[n] |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
375 if bl == l: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
376 bd = '%s@%s' % (bu, br) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
377 errors.append((f, n + 1, l, msg, bd)) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
378 result = False |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
379 |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
380 errors.sort() |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
381 for e in errors: |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
382 logfunc(*e) |
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
383 fc += 1 |
10718
f18c37fd624f
check-code: Add a ``maxerr`` argument to the ``checkfile`` function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10717
diff
changeset
|
384 if maxerr is not None and fc >= maxerr: |
10281 | 385 print " (too many errors, giving up)" |
386 break | |
15281
aeeb2afcdc25
check-code: support multiline matches like try/except/finally
Matt Mackall <mpm@selenic.com>
parents:
14978
diff
changeset
|
387 |
10720
fbcccf9ec58f
check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10719
diff
changeset
|
388 return result |
10717
b1f4fcef99b3
check-code: Add a ``checkfile`` function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10716
diff
changeset
|
389 |
10716
5f92bde72eef
check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10707
diff
changeset
|
390 if __name__ == "__main__": |
10895
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
391 parser = optparse.OptionParser("%prog [options] [files]") |
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
392 parser.add_option("-w", "--warnings", action="store_true", |
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
393 help="include warning-level checks") |
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
394 parser.add_option("-p", "--per-file", type="int", |
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
395 help="max warnings per file") |
11604
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
396 parser.add_option("-b", "--blame", action="store_true", |
c5d40818b270
check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents:
11602
diff
changeset
|
397 help="use annotate to generate blame info") |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
398 parser.add_option("", "--debug", action="store_true", |
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
399 help="show debug information") |
10895
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
400 |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
401 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False) |
10895
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
402 (options, args) = parser.parse_args() |
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
403 |
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
404 if len(args) == 0: |
10716
5f92bde72eef
check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10707
diff
changeset
|
405 check = glob.glob("*") |
5f92bde72eef
check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10707
diff
changeset
|
406 else: |
10895
217557b26bc7
check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents:
10814
diff
changeset
|
407 check = args |
10281 | 408 |
10716
5f92bde72eef
check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10707
diff
changeset
|
409 for f in check: |
11816
e1359ad582f6
check-code: add exit status
Alecs King <alecsk@gmail.com>
parents:
11764
diff
changeset
|
410 ret = 0 |
e1359ad582f6
check-code: add exit status
Alecs King <alecsk@gmail.com>
parents:
11764
diff
changeset
|
411 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings, |
14135
673abd432104
check-code: adding debug flag
timeless <timeless@mozdev.org>
parents:
14009
diff
changeset
|
412 blame=options.blame, debug=options.debug): |
11816
e1359ad582f6
check-code: add exit status
Alecs King <alecsk@gmail.com>
parents:
11764
diff
changeset
|
413 ret = 1 |
e1359ad582f6
check-code: add exit status
Alecs King <alecsk@gmail.com>
parents:
11764
diff
changeset
|
414 sys.exit(ret) |