annotate contrib/check-code.py @ 11109:a2bc2f2d77a9

subrepo: normalize path part of URLs so that pulling subrepos from webdir works For a "all projects at root" repo layout eg: /main /sub Where subrepos are used such that a clone of main has this layout: ./main/ ./main/.hgsub ./main/sub/ And the .hgsub content is: sub = ../sub This allows a pull from a hgweb where main and sub are exposed at the root (or same directory level) The current code doesn't normalize the path component of a pull url. this results in trying to pull from http://server.com/hg/main/../sub Current hgweb implementation doesn't reduce the path component so this results in a 404 error though everything is setup logically. This patch adresses this 404 error on the puller side normalizing the URLs used for pulling sub repos. For this example, the URL would be reduced to http://server.com/hg/sub Fix + test
author Edouard Gomez <ed.gomez@free.fr>
date Sat, 01 May 2010 23:05:19 +0200
parents 13a1b2fb7ef2
children 0c0088881562
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 #!/usr/bin/env python
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # check-code - a style and portability checker for Mercurial
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
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
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
6 #
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7 # This software may be used and distributed according to the terms of the
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
8 # GNU General Public License version 2 or any later version.
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
9
10905
13a1b2fb7ef2 pylint, pyflakes: remove unused or duplicate imports
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 10895
diff changeset
10 import re, glob
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
11 import optparse
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
12
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13 def repquote(m):
10722
c4fb2103e734 check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10720
diff changeset
14 t = re.sub(r"\w", "x", m.group('text'))
10451
63a9bfad50ff check-code: two more rules
Matt Mackall <mpm@selenic.com>
parents: 10412
diff changeset
15 t = re.sub(r"[^\sx]", "o", t)
10722
c4fb2103e734 check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10720
diff changeset
16 return m.group('quote') + t + m.group('quote')
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17
10727
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
18 def reppython(m):
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
19 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
20 if comment:
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
21 return "#" * len(comment)
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
22 return repquote(m)
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
24 def repcomment(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
25 return m.group(1) + "#" * len(m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
26
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
27 def repccomment(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29 return m.group(1) + t + "*/"
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
30
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
31 def repcallspaces(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 t = re.sub(r"\n\s+", "\n", m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
33 return m.group(1) + t
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
34
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 def repinclude(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36 return m.group(1) + "<foo>"
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 def rephere(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 t = re.sub(r"\S", "x", m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40 return m.group(1) + t
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
41
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
42
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
43 testpats = [
10374
3aa35db5e38c check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents: 10373
diff changeset
44 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"),
3aa35db5e38c check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents: 10373
diff changeset
45 (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
46 (r'^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
47 (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
48 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
10374
3aa35db5e38c check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents: 10373
diff changeset
49 (r'^diff.*-\w*N', "don't use 'diff -N'"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
50 (r'(^| )wc[^|]*$', "filter wc output"),
10374
3aa35db5e38c check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents: 10373
diff changeset
51 (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
52 (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
53 (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
54 (r'printf.*\\x', "don't use printf \\x, use Python"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
55 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
56 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
57 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
58 "use egrep for extended grep syntax"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
59 (r'/bin/', "don't use explicit paths for tools"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
60 (r'\$PWD', "don't use $PWD, use `pwd`"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
61 (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
62 (r'export.*=', "don't export and assign at once"),
10802
6e4cf8319f54 check-code.py: Check for bare ^
Mads Kiilerich <mads@kiilerich.com>
parents: 10658
diff changeset
63 ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
64 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
65
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
66 testfilters = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
67 (r"( *)(#([^\n]*\S)?)", repcomment),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
68 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
69 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
70
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
71 pypats = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
72 (r'^\s*\t', "don't use tabs"),
10412
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
73 (r'\S;\s*\n', "semicolon"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
74 (r'\w,\w', "missing whitespace after ,"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
75 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
76 (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
77 (r'.{85}', "line too long"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
78 (r'[^\n]\Z', "no trailing newline"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
79 # (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
80 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"),
10286
cc0340ef47f7 check-code: check thyself
Matt Mackall <mpm@selenic.com>
parents: 10281
diff changeset
81 (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+',
cc0340ef47f7 check-code: check thyself
Matt Mackall <mpm@selenic.com>
parents: 10281
diff changeset
82 "linebreak after :"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
83 (r'class\s[^(]:', "old-style class, use class foo(object)"),
10291
61c93743fae0 check-code: del isn't a function
Matt Mackall <mpm@selenic.com>
parents: 10290
diff changeset
84 (r'^\s+del\(', "del isn't a function"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
85 (r'^\s+except\(', "except isn't a function"),
10412
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
86 (r',]', "unneeded trailing ',' in list"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
87 # (r'class\s[A-Z][^\(]*\((?!Exception)',
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
88 # "don't capitalize non-exception classes"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
89 # (r'in range\(', "use xrange"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
90 # (r'^\s*print\s+', "avoid using print in core and extensions"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
91 (r'[\x80-\xff]', "non-ASCII character literal"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
92 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
93 (r'^\s*with\s+', "with not available in Python 2.4"),
10702
1437542a9fd7 check-code: add check for any/all
Matt Mackall <mpm@selenic.com>
parents: 10658
diff changeset
94 (r'^\s*(any|all)\(', "any/all not available in Python 2.4"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
95 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
96 (r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
97 # (r'\s\s=', "gratuitous whitespace before ="),
10412
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
98 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
99 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s', "missing whitespace around operator"),
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
100 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
101 (r'[^+=*!<>&| -](\s=|=\s)[^= ]', "wrong whitespace around ="),
10451
63a9bfad50ff check-code: two more rules
Matt Mackall <mpm@selenic.com>
parents: 10412
diff changeset
102 (r'raise Exception', "don't raise generic exceptions"),
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
103 (r'ui\.(status|progress|write|note)\([\'\"]x',
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
104 "warning: unwrapped ui message"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
105 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
106
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
107 pyfilters = [
10727
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
108 (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
109 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
110 (?P<text>(([^\\]|\\.)*?))
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
111 (?P=quote))""", reppython),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
112 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
113
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
114 cpats = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
115 (r'//', "don't use //-style comments"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
116 (r'^ ', "don't use spaces to indent"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
117 (r'\S\t', "don't use tabs except for indent"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
118 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
119 (r'.{85}', "line too long"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
120 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
121 (r'return\(', "return is not a function"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
122 (r' ;', "no space before ;"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
123 (r'\w+\* \w+', "use int *foo, not int* foo"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
124 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
125 (r'\S+ (\+\+|--)', "use foo++, not foo ++"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
126 (r'\w,\w', "missing whitespace after ,"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
127 (r'\w[+/*]\w', "missing whitespace in expression"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
128 (r'^#\s+\w', "use #foo, not # foo"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
129 (r'[^\n]\Z', "no trailing newline"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
130 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
131
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
132 cfilters = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
133 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
10722
c4fb2103e734 check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10720
diff changeset
134 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
135 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
136 (r'(\()([^)]+\))', repcallspaces),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
137 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
138
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
139 checks = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
140 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
141 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
142 ('c', r'.*\.c$', cfilters, cpats),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
143 ]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
144
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
145 class norepeatlogger(object):
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
146 def __init__(self):
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
147 self._lastseen = None
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
148
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
149 def log(self, fname, lineno, line, msg):
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
150 """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
151
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
152 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
153 of multiple errors.
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
154
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
155 :fname: filename
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
156 :lineno: line number
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
157 :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
158 :msg: error message
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
159 """
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
160 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
161 if msgid != self._lastseen:
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
162 print "%s:%d:" % (fname, lineno)
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
163 print " > %s" % line
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
164 self._lastseen = msgid
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
165 print " " + msg
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
166
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
167 _defaultlogger = norepeatlogger()
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
168
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
169 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False):
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
170 """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
171
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
172 :f: filepath
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
173 :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
174 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
175 :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
176 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
177
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
178 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
179 """
10720
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
180 result = True
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
181 for name, match, filters, pats in checks:
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
182 fc = 0
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
183 if not re.match(match, f):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
184 continue
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
185 pre = post = open(f).read()
10287
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
186 if "no-" + "check-code" in pre:
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
187 break
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
188 for p, r in filters:
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
189 post = re.sub(p, r, post)
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
190 # print post # uncomment to show filtered version
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
191 z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
192 for n, l in z:
10287
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
193 if "check-code" + "-ignore" in l[0]:
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
194 continue
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
195 for p, msg in pats:
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
196 if not warnings and msg.startswith("warning"):
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
197 continue
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
198 if re.search(p, l[1]):
10723
8ea152e94484 check-code: fix check-code complaint
Matt Mackall <mpm@selenic.com>
parents: 10722
diff changeset
199 logfunc(f, n + 1, l[0], msg)
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
200 fc += 1
10720
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
201 result = False
10718
f18c37fd624f check-code: Add a ``maxerr`` argument to the ``checkfile`` function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10717
diff changeset
202 if maxerr is not None and fc >= maxerr:
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
203 print " (too many errors, giving up)"
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
204 break
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
205 break
10720
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
206 return result
10717
b1f4fcef99b3 check-code: Add a ``checkfile`` function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10716
diff changeset
207
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
208
10716
5f92bde72eef check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10707
diff changeset
209 if __name__ == "__main__":
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
210 parser = optparse.OptionParser("%prog [options] [files]")
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
211 parser.add_option("-w", "--warnings", action="store_true",
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
212 help="include warning-level checks")
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
213 parser.add_option("-p", "--per-file", type="int",
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
214 help="max warnings per file")
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
215
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
216 parser.set_defaults(per_file=15, warnings=False)
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
217 (options, args) = parser.parse_args()
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
218
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
219 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
220 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
221 else:
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
222 check = args
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
223
10716
5f92bde72eef check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10707
diff changeset
224 for f in check:
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
225 checkfile(f, maxerr=options.per_file, warnings=options.warnings)