##// END OF EJS Templates
check-code: replace heredocs in unified tests...
Idan Kamara -
r17711:cf204e98 default
parent child Browse files
Show More
@@ -1,453 +1,454
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # check-code - a style and portability checker for Mercurial
3 # check-code - a style and portability checker for Mercurial
4 #
4 #
5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
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.
8 # GNU General Public License version 2 or any later version.
9
9
10 import re, glob, os, sys
10 import re, glob, os, sys
11 import keyword
11 import keyword
12 import optparse
12 import optparse
13
13
14 def repquote(m):
14 def repquote(m):
15 t = re.sub(r"\w", "x", m.group('text'))
15 t = re.sub(r"\w", "x", m.group('text'))
16 t = re.sub(r"[^\s\nx]", "o", t)
16 t = re.sub(r"[^\s\nx]", "o", t)
17 return m.group('quote') + t + m.group('quote')
17 return m.group('quote') + t + m.group('quote')
18
18
19 def reppython(m):
19 def reppython(m):
20 comment = m.group('comment')
20 comment = m.group('comment')
21 if comment:
21 if comment:
22 return "#" * len(comment)
22 return "#" * len(comment)
23 return repquote(m)
23 return repquote(m)
24
24
25 def repcomment(m):
25 def repcomment(m):
26 return m.group(1) + "#" * len(m.group(2))
26 return m.group(1) + "#" * len(m.group(2))
27
27
28 def repccomment(m):
28 def repccomment(m):
29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
30 return m.group(1) + t + "*/"
30 return m.group(1) + t + "*/"
31
31
32 def repcallspaces(m):
32 def repcallspaces(m):
33 t = re.sub(r"\n\s+", "\n", m.group(2))
33 t = re.sub(r"\n\s+", "\n", m.group(2))
34 return m.group(1) + t
34 return m.group(1) + t
35
35
36 def repinclude(m):
36 def repinclude(m):
37 return m.group(1) + "<foo>"
37 return m.group(1) + "<foo>"
38
38
39 def rephere(m):
39 def rephere(m):
40 t = re.sub(r"\S", "x", m.group(2))
40 t = re.sub(r"\S", "x", m.group(2))
41 return m.group(1) + t
41 return m.group(1) + t
42
42
43
43
44 testpats = [
44 testpats = [
45 [
45 [
46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
48 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
48 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
49 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
49 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
50 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
50 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
51 (r'echo -n', "don't use 'echo -n', use printf"),
51 (r'echo -n', "don't use 'echo -n', use printf"),
52 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
52 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
53 (r'head -c', "don't use 'head -c', use 'dd'"),
53 (r'head -c', "don't use 'head -c', use 'dd'"),
54 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
54 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
56 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
56 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
57 (r'printf.*\\x', "don't use printf \\x, use Python"),
57 (r'printf.*\\x', "don't use printf \\x, use Python"),
58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
61 "use egrep for extended grep syntax"),
61 "use egrep for extended grep syntax"),
62 (r'/bin/', "don't use explicit paths for tools"),
62 (r'/bin/', "don't use explicit paths for tools"),
63 (r'[^\n]\Z', "no trailing newline"),
63 (r'[^\n]\Z', "no trailing newline"),
64 (r'export.*=', "don't export and assign at once"),
64 (r'export.*=', "don't export and assign at once"),
65 (r'^source\b', "don't use 'source', use '.'"),
65 (r'^source\b', "don't use 'source', use '.'"),
66 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
66 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
67 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
67 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
68 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
68 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
69 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
69 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
70 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
70 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
71 (r'^alias\b.*=', "don't use alias, use a function"),
71 (r'^alias\b.*=', "don't use alias, use a function"),
72 (r'if\s*!', "don't use '!' to negate exit status"),
72 (r'if\s*!', "don't use '!' to negate exit status"),
73 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
73 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
74 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
74 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
75 (r'^( *)\t', "don't use tabs to indent"),
75 (r'^( *)\t', "don't use tabs to indent"),
76 ],
76 ],
77 # warnings
77 # warnings
78 [
78 [
79 (r'^function', "don't use 'function', use old style"),
79 (r'^function', "don't use 'function', use old style"),
80 (r'^diff.*-\w*N', "don't use 'diff -N'"),
80 (r'^diff.*-\w*N', "don't use 'diff -N'"),
81 (r'\$PWD', "don't use $PWD, use `pwd`"),
81 (r'\$PWD', "don't use $PWD, use `pwd`"),
82 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
82 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
83 ]
83 ]
84 ]
84 ]
85
85
86 testfilters = [
86 testfilters = [
87 (r"( *)(#([^\n]*\S)?)", repcomment),
87 (r"( *)(#([^\n]*\S)?)", repcomment),
88 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
88 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
89 ]
89 ]
90
90
91 uprefix = r"^ \$ "
91 uprefix = r"^ \$ "
92 utestpats = [
92 utestpats = [
93 [
93 [
94 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
94 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
95 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
95 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
96 "use regex test output patterns instead of sed"),
96 "use regex test output patterns instead of sed"),
97 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
97 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
98 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
98 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
99 (uprefix + r'.*\|\| echo.*(fail|error)',
99 (uprefix + r'.*\|\| echo.*(fail|error)',
100 "explicit exit code checks unnecessary"),
100 "explicit exit code checks unnecessary"),
101 (uprefix + r'set -e', "don't use set -e"),
101 (uprefix + r'set -e', "don't use set -e"),
102 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
102 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
103 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
103 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
104 "use (glob) to match Windows paths too"),
104 "use (glob) to match Windows paths too"),
105 ],
105 ],
106 # warnings
106 # warnings
107 []
107 []
108 ]
108 ]
109
109
110 for i in [0, 1]:
110 for i in [0, 1]:
111 for p, m in testpats[i]:
111 for p, m in testpats[i]:
112 if p.startswith(r'^'):
112 if p.startswith(r'^'):
113 p = r"^ [$>] (%s)" % p[1:]
113 p = r"^ [$>] (%s)" % p[1:]
114 else:
114 else:
115 p = r"^ [$>] .*(%s)" % p
115 p = r"^ [$>] .*(%s)" % p
116 utestpats[i].append((p, m))
116 utestpats[i].append((p, m))
117
117
118 utestfilters = [
118 utestfilters = [
119 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
119 (r"( *)(#([^\n]*\S)?)", repcomment),
120 (r"( *)(#([^\n]*\S)?)", repcomment),
120 ]
121 ]
121
122
122 pypats = [
123 pypats = [
123 [
124 [
124 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
125 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
125 "tuple parameter unpacking not available in Python 3+"),
126 "tuple parameter unpacking not available in Python 3+"),
126 (r'lambda\s*\(.*,.*\)',
127 (r'lambda\s*\(.*,.*\)',
127 "tuple parameter unpacking not available in Python 3+"),
128 "tuple parameter unpacking not available in Python 3+"),
128 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
129 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
129 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
130 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
130 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
131 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
131 (r'^\s*\t', "don't use tabs"),
132 (r'^\s*\t', "don't use tabs"),
132 (r'\S;\s*\n', "semicolon"),
133 (r'\S;\s*\n', "semicolon"),
133 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
134 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
134 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
135 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
135 (r'\w,\w', "missing whitespace after ,"),
136 (r'\w,\w', "missing whitespace after ,"),
136 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
137 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
137 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
138 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
138 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
139 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
139 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
140 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
140 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
141 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
141 r'((?:\n|\1\s.*\n)+?)\1finally:',
142 r'((?:\n|\1\s.*\n)+?)\1finally:',
142 'no yield inside try/finally in Python 2.4'),
143 'no yield inside try/finally in Python 2.4'),
143 (r'.{81}', "line too long"),
144 (r'.{81}', "line too long"),
144 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
145 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
145 (r'[^\n]\Z', "no trailing newline"),
146 (r'[^\n]\Z', "no trailing newline"),
146 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
147 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
147 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
148 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
148 # "don't use underbars in identifiers"),
149 # "don't use underbars in identifiers"),
149 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
150 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
150 "don't use camelcase in identifiers"),
151 "don't use camelcase in identifiers"),
151 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
152 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
152 "linebreak after :"),
153 "linebreak after :"),
153 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
154 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
154 (r'class\s[^( \n]+\(\):',
155 (r'class\s[^( \n]+\(\):',
155 "class foo() not available in Python 2.4, use class foo(object)"),
156 "class foo() not available in Python 2.4, use class foo(object)"),
156 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
157 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
157 "Python keyword is not a function"),
158 "Python keyword is not a function"),
158 (r',]', "unneeded trailing ',' in list"),
159 (r',]', "unneeded trailing ',' in list"),
159 # (r'class\s[A-Z][^\(]*\((?!Exception)',
160 # (r'class\s[A-Z][^\(]*\((?!Exception)',
160 # "don't capitalize non-exception classes"),
161 # "don't capitalize non-exception classes"),
161 # (r'in range\(', "use xrange"),
162 # (r'in range\(', "use xrange"),
162 # (r'^\s*print\s+', "avoid using print in core and extensions"),
163 # (r'^\s*print\s+', "avoid using print in core and extensions"),
163 (r'[\x80-\xff]', "non-ASCII character literal"),
164 (r'[\x80-\xff]', "non-ASCII character literal"),
164 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
165 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
165 (r'^\s*with\s+', "with not available in Python 2.4"),
166 (r'^\s*with\s+', "with not available in Python 2.4"),
166 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
167 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
167 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
168 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
168 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
169 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
169 (r'(?<!def)\s+(any|all|format)\(',
170 (r'(?<!def)\s+(any|all|format)\(',
170 "any/all/format not available in Python 2.4"),
171 "any/all/format not available in Python 2.4"),
171 (r'(?<!def)\s+(callable)\(',
172 (r'(?<!def)\s+(callable)\(',
172 "callable not available in Python 3, use getattr(f, '__call__', None)"),
173 "callable not available in Python 3, use getattr(f, '__call__', None)"),
173 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
174 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
174 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
175 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
175 "gratuitous whitespace after Python keyword"),
176 "gratuitous whitespace after Python keyword"),
176 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
177 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
177 # (r'\s\s=', "gratuitous whitespace before ="),
178 # (r'\s\s=', "gratuitous whitespace before ="),
178 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
179 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
179 "missing whitespace around operator"),
180 "missing whitespace around operator"),
180 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
181 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
181 "missing whitespace around operator"),
182 "missing whitespace around operator"),
182 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
183 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
183 "missing whitespace around operator"),
184 "missing whitespace around operator"),
184 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
185 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
185 "wrong whitespace around ="),
186 "wrong whitespace around ="),
186 (r'raise Exception', "don't raise generic exceptions"),
187 (r'raise Exception', "don't raise generic exceptions"),
187 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
188 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
188 (r' [=!]=\s+(True|False|None)',
189 (r' [=!]=\s+(True|False|None)',
189 "comparison with singleton, use 'is' or 'is not' instead"),
190 "comparison with singleton, use 'is' or 'is not' instead"),
190 (r'^\s*(while|if) [01]:',
191 (r'^\s*(while|if) [01]:',
191 "use True/False for constant Boolean expression"),
192 "use True/False for constant Boolean expression"),
192 (r'(?:(?<!def)\s+|\()hasattr',
193 (r'(?:(?<!def)\s+|\()hasattr',
193 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
194 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
194 (r'opener\([^)]*\).read\(',
195 (r'opener\([^)]*\).read\(',
195 "use opener.read() instead"),
196 "use opener.read() instead"),
196 (r'BaseException', 'not in Python 2.4, use Exception'),
197 (r'BaseException', 'not in Python 2.4, use Exception'),
197 (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
198 (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
198 (r'opener\([^)]*\).write\(',
199 (r'opener\([^)]*\).write\(',
199 "use opener.write() instead"),
200 "use opener.write() instead"),
200 (r'[\s\(](open|file)\([^)]*\)\.read\(',
201 (r'[\s\(](open|file)\([^)]*\)\.read\(',
201 "use util.readfile() instead"),
202 "use util.readfile() instead"),
202 (r'[\s\(](open|file)\([^)]*\)\.write\(',
203 (r'[\s\(](open|file)\([^)]*\)\.write\(',
203 "use util.readfile() instead"),
204 "use util.readfile() instead"),
204 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
205 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
205 "always assign an opened file to a variable, and close it afterwards"),
206 "always assign an opened file to a variable, and close it afterwards"),
206 (r'[\s\(](open|file)\([^)]*\)\.',
207 (r'[\s\(](open|file)\([^)]*\)\.',
207 "always assign an opened file to a variable, and close it afterwards"),
208 "always assign an opened file to a variable, and close it afterwards"),
208 (r'(?i)descendent', "the proper spelling is descendAnt"),
209 (r'(?i)descendent', "the proper spelling is descendAnt"),
209 (r'\.debug\(\_', "don't mark debug messages for translation"),
210 (r'\.debug\(\_', "don't mark debug messages for translation"),
210 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
211 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
211 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
212 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
212 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
213 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
213 ],
214 ],
214 # warnings
215 # warnings
215 [
216 [
216 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
217 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
217 "warning: unwrapped ui message"),
218 "warning: unwrapped ui message"),
218 ]
219 ]
219 ]
220 ]
220
221
221 pyfilters = [
222 pyfilters = [
222 (r"""(?msx)(?P<comment>\#.*?$)|
223 (r"""(?msx)(?P<comment>\#.*?$)|
223 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
224 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
224 (?P<text>(([^\\]|\\.)*?))
225 (?P<text>(([^\\]|\\.)*?))
225 (?P=quote))""", reppython),
226 (?P=quote))""", reppython),
226 ]
227 ]
227
228
228 cpats = [
229 cpats = [
229 [
230 [
230 (r'//', "don't use //-style comments"),
231 (r'//', "don't use //-style comments"),
231 (r'^ ', "don't use spaces to indent"),
232 (r'^ ', "don't use spaces to indent"),
232 (r'\S\t', "don't use tabs except for indent"),
233 (r'\S\t', "don't use tabs except for indent"),
233 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
234 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
234 (r'.{81}', "line too long"),
235 (r'.{81}', "line too long"),
235 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
236 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
236 (r'return\(', "return is not a function"),
237 (r'return\(', "return is not a function"),
237 (r' ;', "no space before ;"),
238 (r' ;', "no space before ;"),
238 (r'\w+\* \w+', "use int *foo, not int* foo"),
239 (r'\w+\* \w+', "use int *foo, not int* foo"),
239 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
240 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
240 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
241 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
241 (r'\w,\w', "missing whitespace after ,"),
242 (r'\w,\w', "missing whitespace after ,"),
242 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
243 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
243 (r'^#\s+\w', "use #foo, not # foo"),
244 (r'^#\s+\w', "use #foo, not # foo"),
244 (r'[^\n]\Z', "no trailing newline"),
245 (r'[^\n]\Z', "no trailing newline"),
245 (r'^\s*#import\b', "use only #include in standard C code"),
246 (r'^\s*#import\b', "use only #include in standard C code"),
246 ],
247 ],
247 # warnings
248 # warnings
248 []
249 []
249 ]
250 ]
250
251
251 cfilters = [
252 cfilters = [
252 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
253 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
253 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
254 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
254 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
255 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
255 (r'(\()([^)]+\))', repcallspaces),
256 (r'(\()([^)]+\))', repcallspaces),
256 ]
257 ]
257
258
258 inutilpats = [
259 inutilpats = [
259 [
260 [
260 (r'\bui\.', "don't use ui in util"),
261 (r'\bui\.', "don't use ui in util"),
261 ],
262 ],
262 # warnings
263 # warnings
263 []
264 []
264 ]
265 ]
265
266
266 inrevlogpats = [
267 inrevlogpats = [
267 [
268 [
268 (r'\brepo\.', "don't use repo in revlog"),
269 (r'\brepo\.', "don't use repo in revlog"),
269 ],
270 ],
270 # warnings
271 # warnings
271 []
272 []
272 ]
273 ]
273
274
274 checks = [
275 checks = [
275 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
276 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
276 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
277 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
277 ('c', r'.*\.c$', cfilters, cpats),
278 ('c', r'.*\.c$', cfilters, cpats),
278 ('unified test', r'.*\.t$', utestfilters, utestpats),
279 ('unified test', r'.*\.t$', utestfilters, utestpats),
279 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
280 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
280 inrevlogpats),
281 inrevlogpats),
281 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
282 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
282 inutilpats),
283 inutilpats),
283 ]
284 ]
284
285
285 class norepeatlogger(object):
286 class norepeatlogger(object):
286 def __init__(self):
287 def __init__(self):
287 self._lastseen = None
288 self._lastseen = None
288
289
289 def log(self, fname, lineno, line, msg, blame):
290 def log(self, fname, lineno, line, msg, blame):
290 """print error related a to given line of a given file.
291 """print error related a to given line of a given file.
291
292
292 The faulty line will also be printed but only once in the case
293 The faulty line will also be printed but only once in the case
293 of multiple errors.
294 of multiple errors.
294
295
295 :fname: filename
296 :fname: filename
296 :lineno: line number
297 :lineno: line number
297 :line: actual content of the line
298 :line: actual content of the line
298 :msg: error message
299 :msg: error message
299 """
300 """
300 msgid = fname, lineno, line
301 msgid = fname, lineno, line
301 if msgid != self._lastseen:
302 if msgid != self._lastseen:
302 if blame:
303 if blame:
303 print "%s:%d (%s):" % (fname, lineno, blame)
304 print "%s:%d (%s):" % (fname, lineno, blame)
304 else:
305 else:
305 print "%s:%d:" % (fname, lineno)
306 print "%s:%d:" % (fname, lineno)
306 print " > %s" % line
307 print " > %s" % line
307 self._lastseen = msgid
308 self._lastseen = msgid
308 print " " + msg
309 print " " + msg
309
310
310 _defaultlogger = norepeatlogger()
311 _defaultlogger = norepeatlogger()
311
312
312 def getblame(f):
313 def getblame(f):
313 lines = []
314 lines = []
314 for l in os.popen('hg annotate -un %s' % f):
315 for l in os.popen('hg annotate -un %s' % f):
315 start, line = l.split(':', 1)
316 start, line = l.split(':', 1)
316 user, rev = start.split()
317 user, rev = start.split()
317 lines.append((line[1:-1], user, rev))
318 lines.append((line[1:-1], user, rev))
318 return lines
319 return lines
319
320
320 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
321 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
321 blame=False, debug=False, lineno=True):
322 blame=False, debug=False, lineno=True):
322 """checks style and portability of a given file
323 """checks style and portability of a given file
323
324
324 :f: filepath
325 :f: filepath
325 :logfunc: function used to report error
326 :logfunc: function used to report error
326 logfunc(filename, linenumber, linecontent, errormessage)
327 logfunc(filename, linenumber, linecontent, errormessage)
327 :maxerr: number of error to display before aborting.
328 :maxerr: number of error to display before aborting.
328 Set to false (default) to report all errors
329 Set to false (default) to report all errors
329
330
330 return True if no error is found, False otherwise.
331 return True if no error is found, False otherwise.
331 """
332 """
332 blamecache = None
333 blamecache = None
333 result = True
334 result = True
334 for name, match, filters, pats in checks:
335 for name, match, filters, pats in checks:
335 if debug:
336 if debug:
336 print name, f
337 print name, f
337 fc = 0
338 fc = 0
338 if not re.match(match, f):
339 if not re.match(match, f):
339 if debug:
340 if debug:
340 print "Skipping %s for %s it doesn't match %s" % (
341 print "Skipping %s for %s it doesn't match %s" % (
341 name, match, f)
342 name, match, f)
342 continue
343 continue
343 fp = open(f)
344 fp = open(f)
344 pre = post = fp.read()
345 pre = post = fp.read()
345 fp.close()
346 fp.close()
346 if "no-" + "check-code" in pre:
347 if "no-" + "check-code" in pre:
347 if debug:
348 if debug:
348 print "Skipping %s for %s it has no- and check-code" % (
349 print "Skipping %s for %s it has no- and check-code" % (
349 name, f)
350 name, f)
350 break
351 break
351 for p, r in filters:
352 for p, r in filters:
352 post = re.sub(p, r, post)
353 post = re.sub(p, r, post)
353 if warnings:
354 if warnings:
354 pats = pats[0] + pats[1]
355 pats = pats[0] + pats[1]
355 else:
356 else:
356 pats = pats[0]
357 pats = pats[0]
357 # print post # uncomment to show filtered version
358 # print post # uncomment to show filtered version
358
359
359 if debug:
360 if debug:
360 print "Checking %s for %s" % (name, f)
361 print "Checking %s for %s" % (name, f)
361
362
362 prelines = None
363 prelines = None
363 errors = []
364 errors = []
364 for pat in pats:
365 for pat in pats:
365 if len(pat) == 3:
366 if len(pat) == 3:
366 p, msg, ignore = pat
367 p, msg, ignore = pat
367 else:
368 else:
368 p, msg = pat
369 p, msg = pat
369 ignore = None
370 ignore = None
370
371
371 # fix-up regexes for multi-line searches
372 # fix-up regexes for multi-line searches
372 po = p
373 po = p
373 # \s doesn't match \n
374 # \s doesn't match \n
374 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
375 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
375 # [^...] doesn't match newline
376 # [^...] doesn't match newline
376 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
377 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
377
378
378 #print po, '=>', p
379 #print po, '=>', p
379
380
380 pos = 0
381 pos = 0
381 n = 0
382 n = 0
382 for m in re.finditer(p, post, re.MULTILINE):
383 for m in re.finditer(p, post, re.MULTILINE):
383 if prelines is None:
384 if prelines is None:
384 prelines = pre.splitlines()
385 prelines = pre.splitlines()
385 postlines = post.splitlines(True)
386 postlines = post.splitlines(True)
386
387
387 start = m.start()
388 start = m.start()
388 while n < len(postlines):
389 while n < len(postlines):
389 step = len(postlines[n])
390 step = len(postlines[n])
390 if pos + step > start:
391 if pos + step > start:
391 break
392 break
392 pos += step
393 pos += step
393 n += 1
394 n += 1
394 l = prelines[n]
395 l = prelines[n]
395
396
396 if "check-code" + "-ignore" in l:
397 if "check-code" + "-ignore" in l:
397 if debug:
398 if debug:
398 print "Skipping %s for %s:%s (check-code -ignore)" % (
399 print "Skipping %s for %s:%s (check-code -ignore)" % (
399 name, f, n)
400 name, f, n)
400 continue
401 continue
401 elif ignore and re.search(ignore, l, re.MULTILINE):
402 elif ignore and re.search(ignore, l, re.MULTILINE):
402 continue
403 continue
403 bd = ""
404 bd = ""
404 if blame:
405 if blame:
405 bd = 'working directory'
406 bd = 'working directory'
406 if not blamecache:
407 if not blamecache:
407 blamecache = getblame(f)
408 blamecache = getblame(f)
408 if n < len(blamecache):
409 if n < len(blamecache):
409 bl, bu, br = blamecache[n]
410 bl, bu, br = blamecache[n]
410 if bl == l:
411 if bl == l:
411 bd = '%s@%s' % (bu, br)
412 bd = '%s@%s' % (bu, br)
412 errors.append((f, lineno and n + 1, l, msg, bd))
413 errors.append((f, lineno and n + 1, l, msg, bd))
413 result = False
414 result = False
414
415
415 errors.sort()
416 errors.sort()
416 for e in errors:
417 for e in errors:
417 logfunc(*e)
418 logfunc(*e)
418 fc += 1
419 fc += 1
419 if maxerr and fc >= maxerr:
420 if maxerr and fc >= maxerr:
420 print " (too many errors, giving up)"
421 print " (too many errors, giving up)"
421 break
422 break
422
423
423 return result
424 return result
424
425
425 if __name__ == "__main__":
426 if __name__ == "__main__":
426 parser = optparse.OptionParser("%prog [options] [files]")
427 parser = optparse.OptionParser("%prog [options] [files]")
427 parser.add_option("-w", "--warnings", action="store_true",
428 parser.add_option("-w", "--warnings", action="store_true",
428 help="include warning-level checks")
429 help="include warning-level checks")
429 parser.add_option("-p", "--per-file", type="int",
430 parser.add_option("-p", "--per-file", type="int",
430 help="max warnings per file")
431 help="max warnings per file")
431 parser.add_option("-b", "--blame", action="store_true",
432 parser.add_option("-b", "--blame", action="store_true",
432 help="use annotate to generate blame info")
433 help="use annotate to generate blame info")
433 parser.add_option("", "--debug", action="store_true",
434 parser.add_option("", "--debug", action="store_true",
434 help="show debug information")
435 help="show debug information")
435 parser.add_option("", "--nolineno", action="store_false",
436 parser.add_option("", "--nolineno", action="store_false",
436 dest='lineno', help="don't show line numbers")
437 dest='lineno', help="don't show line numbers")
437
438
438 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
439 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
439 lineno=True)
440 lineno=True)
440 (options, args) = parser.parse_args()
441 (options, args) = parser.parse_args()
441
442
442 if len(args) == 0:
443 if len(args) == 0:
443 check = glob.glob("*")
444 check = glob.glob("*")
444 else:
445 else:
445 check = args
446 check = args
446
447
447 ret = 0
448 ret = 0
448 for f in check:
449 for f in check:
449 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
450 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
450 blame=options.blame, debug=options.debug,
451 blame=options.blame, debug=options.debug,
451 lineno=options.lineno):
452 lineno=options.lineno):
452 ret = 1
453 ret = 1
453 sys.exit(ret)
454 sys.exit(ret)
@@ -1,183 +1,170
1 $ check_code="$TESTDIR"/../contrib/check-code.py
1 $ check_code="$TESTDIR"/../contrib/check-code.py
2 $ cd "$TESTDIR"/..
2 $ cd "$TESTDIR"/..
3 $ if hg identify -q > /dev/null; then :
3 $ if hg identify -q > /dev/null; then :
4 > else
4 > else
5 > echo "skipped: not a Mercurial working dir" >&2
5 > echo "skipped: not a Mercurial working dir" >&2
6 > exit 80
6 > exit 80
7 > fi
7 > fi
8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
9
9
10 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
10 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
11 hgext/convert/cvsps.py:0:
11 hgext/convert/cvsps.py:0:
12 > ui.write('Ancestors: %s\n' % (','.join(r)))
12 > ui.write('Ancestors: %s\n' % (','.join(r)))
13 warning: unwrapped ui message
13 warning: unwrapped ui message
14 hgext/convert/cvsps.py:0:
14 hgext/convert/cvsps.py:0:
15 > ui.write('Parent: %d\n' % cs.parents[0].id)
15 > ui.write('Parent: %d\n' % cs.parents[0].id)
16 warning: unwrapped ui message
16 warning: unwrapped ui message
17 hgext/convert/cvsps.py:0:
17 hgext/convert/cvsps.py:0:
18 > ui.write('Parents: %s\n' %
18 > ui.write('Parents: %s\n' %
19 warning: unwrapped ui message
19 warning: unwrapped ui message
20 hgext/convert/cvsps.py:0:
20 hgext/convert/cvsps.py:0:
21 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
21 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
22 warning: unwrapped ui message
22 warning: unwrapped ui message
23 hgext/convert/cvsps.py:0:
23 hgext/convert/cvsps.py:0:
24 > ui.write('Author: %s\n' % cs.author)
24 > ui.write('Author: %s\n' % cs.author)
25 warning: unwrapped ui message
25 warning: unwrapped ui message
26 hgext/convert/cvsps.py:0:
26 hgext/convert/cvsps.py:0:
27 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
27 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
28 warning: unwrapped ui message
28 warning: unwrapped ui message
29 hgext/convert/cvsps.py:0:
29 hgext/convert/cvsps.py:0:
30 > ui.write('Date: %s\n' % util.datestr(cs.date,
30 > ui.write('Date: %s\n' % util.datestr(cs.date,
31 warning: unwrapped ui message
31 warning: unwrapped ui message
32 hgext/convert/cvsps.py:0:
32 hgext/convert/cvsps.py:0:
33 > ui.write('Log:\n')
33 > ui.write('Log:\n')
34 warning: unwrapped ui message
34 warning: unwrapped ui message
35 hgext/convert/cvsps.py:0:
35 hgext/convert/cvsps.py:0:
36 > ui.write('Members: \n')
36 > ui.write('Members: \n')
37 warning: unwrapped ui message
37 warning: unwrapped ui message
38 hgext/convert/cvsps.py:0:
38 hgext/convert/cvsps.py:0:
39 > ui.write('PatchSet %d \n' % cs.id)
39 > ui.write('PatchSet %d \n' % cs.id)
40 warning: unwrapped ui message
40 warning: unwrapped ui message
41 hgext/convert/cvsps.py:0:
41 hgext/convert/cvsps.py:0:
42 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
42 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
43 warning: unwrapped ui message
43 warning: unwrapped ui message
44 hgext/hgk.py:0:
44 hgext/hgk.py:0:
45 > ui.write("parent %s\n" % p)
45 > ui.write("parent %s\n" % p)
46 warning: unwrapped ui message
46 warning: unwrapped ui message
47 hgext/hgk.py:0:
47 hgext/hgk.py:0:
48 > ui.write('k=%s\nv=%s\n' % (name, value))
48 > ui.write('k=%s\nv=%s\n' % (name, value))
49 warning: unwrapped ui message
49 warning: unwrapped ui message
50 hgext/hgk.py:0:
50 hgext/hgk.py:0:
51 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
51 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
52 warning: unwrapped ui message
52 warning: unwrapped ui message
53 hgext/hgk.py:0:
53 hgext/hgk.py:0:
54 > ui.write("branch %s\n\n" % ctx.branch())
54 > ui.write("branch %s\n\n" % ctx.branch())
55 warning: unwrapped ui message
55 warning: unwrapped ui message
56 hgext/hgk.py:0:
56 hgext/hgk.py:0:
57 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
57 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
58 warning: unwrapped ui message
58 warning: unwrapped ui message
59 hgext/hgk.py:0:
59 hgext/hgk.py:0:
60 > ui.write("revision %d\n" % ctx.rev())
60 > ui.write("revision %d\n" % ctx.rev())
61 warning: unwrapped ui message
61 warning: unwrapped ui message
62 hgext/hgk.py:0:
62 hgext/hgk.py:0:
63 > ui.write("tree %s\n" % short(ctx.changeset()[0]))
63 > ui.write("tree %s\n" % short(ctx.changeset()[0]))
64 warning: unwrapped ui message
64 warning: unwrapped ui message
65 hgext/mq.py:0:
65 hgext/mq.py:0:
66 > ui.write("mq: %s\n" % ', '.join(m))
66 > ui.write("mq: %s\n" % ', '.join(m))
67 warning: unwrapped ui message
67 warning: unwrapped ui message
68 hgext/patchbomb.py:0:
68 hgext/patchbomb.py:0:
69 > ui.write('Subject: %s\n' % subj)
69 > ui.write('Subject: %s\n' % subj)
70 warning: unwrapped ui message
70 warning: unwrapped ui message
71 hgext/patchbomb.py:0:
71 hgext/patchbomb.py:0:
72 > ui.write('From: %s\n' % sender)
72 > ui.write('From: %s\n' % sender)
73 warning: unwrapped ui message
73 warning: unwrapped ui message
74 mercurial/commands.py:0:
74 mercurial/commands.py:0:
75 > ui.note('branch %s\n' % data)
75 > ui.note('branch %s\n' % data)
76 warning: unwrapped ui message
76 warning: unwrapped ui message
77 mercurial/commands.py:0:
77 mercurial/commands.py:0:
78 > ui.note('node %s\n' % str(data))
78 > ui.note('node %s\n' % str(data))
79 warning: unwrapped ui message
79 warning: unwrapped ui message
80 mercurial/commands.py:0:
80 mercurial/commands.py:0:
81 > ui.note('tag %s\n' % name)
81 > ui.note('tag %s\n' % name)
82 warning: unwrapped ui message
82 warning: unwrapped ui message
83 mercurial/commands.py:0:
83 mercurial/commands.py:0:
84 > ui.write("unpruned common: %s\n" % " ".join([short(n)
84 > ui.write("unpruned common: %s\n" % " ".join([short(n)
85 warning: unwrapped ui message
85 warning: unwrapped ui message
86 mercurial/commands.py:0:
86 mercurial/commands.py:0:
87 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
87 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
88 warning: unwrapped ui message
88 warning: unwrapped ui message
89 mercurial/commands.py:0:
89 mercurial/commands.py:0:
90 > ui.write("local is subset\n")
90 > ui.write("local is subset\n")
91 warning: unwrapped ui message
91 warning: unwrapped ui message
92 mercurial/commands.py:0:
92 mercurial/commands.py:0:
93 > ui.write("remote is subset\n")
93 > ui.write("remote is subset\n")
94 warning: unwrapped ui message
94 warning: unwrapped ui message
95 mercurial/commands.py:0:
95 mercurial/commands.py:0:
96 > ui.write('deltas against other : ' + fmt % pcfmt(numother,
96 > ui.write('deltas against other : ' + fmt % pcfmt(numother,
97 warning: unwrapped ui message
97 warning: unwrapped ui message
98 mercurial/commands.py:0:
98 mercurial/commands.py:0:
99 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
99 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
100 warning: unwrapped ui message
100 warning: unwrapped ui message
101 mercurial/commands.py:0:
101 mercurial/commands.py:0:
102 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
102 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
103 warning: unwrapped ui message
103 warning: unwrapped ui message
104 mercurial/commands.py:0:
104 mercurial/commands.py:0:
105 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
105 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
106 warning: unwrapped ui message
106 warning: unwrapped ui message
107 mercurial/commands.py:0:
107 mercurial/commands.py:0:
108 > ui.write("match: %s\n" % m(d[0]))
108 > ui.write("match: %s\n" % m(d[0]))
109 warning: unwrapped ui message
109 warning: unwrapped ui message
110 mercurial/commands.py:0:
110 mercurial/commands.py:0:
111 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
111 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
112 warning: unwrapped ui message
112 warning: unwrapped ui message
113 mercurial/commands.py:0:
113 mercurial/commands.py:0:
114 > ui.write('path %s\n' % k)
114 > ui.write('path %s\n' % k)
115 warning: unwrapped ui message
115 warning: unwrapped ui message
116 mercurial/commands.py:0:
116 mercurial/commands.py:0:
117 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
117 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
118 warning: unwrapped ui message
118 warning: unwrapped ui message
119 mercurial/commands.py:0:
119 mercurial/commands.py:0:
120 > ui.write("digraph G {\n")
120 > ui.write("digraph G {\n")
121 warning: unwrapped ui message
121 warning: unwrapped ui message
122 mercurial/commands.py:0:
122 mercurial/commands.py:0:
123 > ui.write("internal: %s %s\n" % d)
123 > ui.write("internal: %s %s\n" % d)
124 warning: unwrapped ui message
124 warning: unwrapped ui message
125 mercurial/commands.py:0:
125 mercurial/commands.py:0:
126 > ui.write("standard: %s\n" % util.datestr(d))
126 > ui.write("standard: %s\n" % util.datestr(d))
127 warning: unwrapped ui message
127 warning: unwrapped ui message
128 mercurial/commands.py:0:
128 mercurial/commands.py:0:
129 > ui.write('avg chain length : ' + fmt % avgchainlen)
129 > ui.write('avg chain length : ' + fmt % avgchainlen)
130 warning: unwrapped ui message
130 warning: unwrapped ui message
131 mercurial/commands.py:0:
131 mercurial/commands.py:0:
132 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
132 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
133 warning: unwrapped ui message
133 warning: unwrapped ui message
134 mercurial/commands.py:0:
134 mercurial/commands.py:0:
135 > ui.write('compression ratio : ' + fmt % compratio)
135 > ui.write('compression ratio : ' + fmt % compratio)
136 warning: unwrapped ui message
136 warning: unwrapped ui message
137 mercurial/commands.py:0:
137 mercurial/commands.py:0:
138 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
138 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
139 warning: unwrapped ui message
139 warning: unwrapped ui message
140 mercurial/commands.py:0:
140 mercurial/commands.py:0:
141 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
141 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
142 warning: unwrapped ui message
142 warning: unwrapped ui message
143 mercurial/commands.py:0:
143 mercurial/commands.py:0:
144 > ui.write('flags : %s\n' % ', '.join(flags))
144 > ui.write('flags : %s\n' % ', '.join(flags))
145 warning: unwrapped ui message
145 warning: unwrapped ui message
146 mercurial/commands.py:0:
146 mercurial/commands.py:0:
147 > ui.write('format : %d\n' % format)
147 > ui.write('format : %d\n' % format)
148 warning: unwrapped ui message
148 warning: unwrapped ui message
149 mercurial/commands.py:0:
149 mercurial/commands.py:0:
150 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
150 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
151 warning: unwrapped ui message
151 warning: unwrapped ui message
152 mercurial/commands.py:0:
152 mercurial/commands.py:0:
153 > ui.write('revision size : ' + fmt2 % totalsize)
153 > ui.write('revision size : ' + fmt2 % totalsize)
154 warning: unwrapped ui message
154 warning: unwrapped ui message
155 mercurial/commands.py:0:
155 mercurial/commands.py:0:
156 > ui.write('revisions : ' + fmt2 % numrevs)
156 > ui.write('revisions : ' + fmt2 % numrevs)
157 warning: unwrapped ui message
157 warning: unwrapped ui message
158 warning: unwrapped ui message
158 warning: unwrapped ui message
159 mercurial/commands.py:0:
159 mercurial/commands.py:0:
160 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
160 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
161 warning: unwrapped ui message
161 warning: unwrapped ui message
162 tests/autodiff.py:0:
162 tests/autodiff.py:0:
163 > ui.write('data lost for: %s\n' % fn)
163 > ui.write('data lost for: %s\n' % fn)
164 warning: unwrapped ui message
164 warning: unwrapped ui message
165 tests/test-convert-mtn.t:0:
166 > > function get_passphrase(keypair_id)
167 don't use 'function', use old style
168 tests/test-import-git.t:0:
169 > > Mc\${NkU|\`?^000jF3jhEB
170 ^ must be quoted
171 tests/test-import.t:0:
172 > > diff -Naur proj-orig/foo proj-new/foo
173 don't use 'diff -N'
174 don't use 'diff -N'
175 tests/test-schemes.t:0:
176 > > z = file:\$PWD/
177 don't use $PWD, use `pwd`
178 tests/test-ui-color.py:0:
165 tests/test-ui-color.py:0:
179 > testui.warn('warning\n')
166 > testui.warn('warning\n')
180 warning: unwrapped ui message
167 warning: unwrapped ui message
181 tests/test-ui-color.py:0:
168 tests/test-ui-color.py:0:
182 > testui.write('buffered\n')
169 > testui.write('buffered\n')
183 warning: unwrapped ui message
170 warning: unwrapped ui message
General Comments 0
You need to be logged in to leave comments. Login now