##// END OF EJS Templates
check-code: find trailing whitespace
Martin Geisler -
r12770:614f0d87 default
parent child Browse files
Show More
@@ -1,294 +1,295
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 optparse
11 import optparse
12
12
13 def repquote(m):
13 def repquote(m):
14 t = re.sub(r"\w", "x", m.group('text'))
14 t = re.sub(r"\w", "x", m.group('text'))
15 t = re.sub(r"[^\sx]", "o", t)
15 t = re.sub(r"[^\sx]", "o", t)
16 return m.group('quote') + t + m.group('quote')
16 return m.group('quote') + t + m.group('quote')
17
17
18 def reppython(m):
18 def reppython(m):
19 comment = m.group('comment')
19 comment = m.group('comment')
20 if comment:
20 if comment:
21 return "#" * len(comment)
21 return "#" * len(comment)
22 return repquote(m)
22 return repquote(m)
23
23
24 def repcomment(m):
24 def repcomment(m):
25 return m.group(1) + "#" * len(m.group(2))
25 return m.group(1) + "#" * len(m.group(2))
26
26
27 def repccomment(m):
27 def repccomment(m):
28 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
28 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
29 return m.group(1) + t + "*/"
29 return m.group(1) + t + "*/"
30
30
31 def repcallspaces(m):
31 def repcallspaces(m):
32 t = re.sub(r"\n\s+", "\n", m.group(2))
32 t = re.sub(r"\n\s+", "\n", m.group(2))
33 return m.group(1) + t
33 return m.group(1) + t
34
34
35 def repinclude(m):
35 def repinclude(m):
36 return m.group(1) + "<foo>"
36 return m.group(1) + "<foo>"
37
37
38 def rephere(m):
38 def rephere(m):
39 t = re.sub(r"\S", "x", m.group(2))
39 t = re.sub(r"\S", "x", m.group(2))
40 return m.group(1) + t
40 return m.group(1) + t
41
41
42
42
43 testpats = [
43 testpats = [
44 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"),
44 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"),
45 (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"),
45 (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"),
46 (r'^function', "don't use 'function', use old style"),
46 (r'^function', "don't use 'function', use old style"),
47 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
47 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
48 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
48 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
49 (r'echo -n', "don't use 'echo -n', use printf"),
49 (r'echo -n', "don't use 'echo -n', use printf"),
50 (r'^diff.*-\w*N', "don't use 'diff -N'"),
50 (r'^diff.*-\w*N', "don't use 'diff -N'"),
51 (r'(^| )wc[^|]*$', "filter wc output"),
51 (r'(^| )wc[^|]*$', "filter wc output"),
52 (r'head -c', "don't use 'head -c', use 'dd'"),
52 (r'head -c', "don't use 'head -c', use 'dd'"),
53 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
53 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
54 (r'printf.*\\\d\d\d', "don't use 'printf \NNN', use Python"),
54 (r'printf.*\\\d\d\d', "don't use 'printf \NNN', use Python"),
55 (r'printf.*\\x', "don't use printf \\x, use Python"),
55 (r'printf.*\\x', "don't use printf \\x, use Python"),
56 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
56 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
57 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
57 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
58 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
58 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
59 "use egrep for extended grep syntax"),
59 "use egrep for extended grep syntax"),
60 (r'/bin/', "don't use explicit paths for tools"),
60 (r'/bin/', "don't use explicit paths for tools"),
61 (r'\$PWD', "don't use $PWD, use `pwd`"),
61 (r'\$PWD', "don't use $PWD, use `pwd`"),
62 (r'[^\n]\Z', "no trailing newline"),
62 (r'[^\n]\Z', "no trailing newline"),
63 (r'export.*=', "don't export and assign at once"),
63 (r'export.*=', "don't export and assign at once"),
64 ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
64 ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
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 ]
67 ]
68
68
69 testfilters = [
69 testfilters = [
70 (r"( *)(#([^\n]*\S)?)", repcomment),
70 (r"( *)(#([^\n]*\S)?)", repcomment),
71 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
71 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
72 ]
72 ]
73
73
74 uprefix = r"^ \$ "
74 uprefix = r"^ \$ "
75 uprefixc = r"^ > "
75 uprefixc = r"^ > "
76 utestpats = [
76 utestpats = [
77 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
77 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
78 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
78 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
79 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"),
79 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"),
80 (uprefix + r'.*\|\| echo.*(fail|error)',
80 (uprefix + r'.*\|\| echo.*(fail|error)',
81 "explicit exit code checks unnecessary"),
81 "explicit exit code checks unnecessary"),
82 (uprefix + r'set -e', "don't use set -e"),
82 (uprefix + r'set -e', "don't use set -e"),
83 (uprefixc + r'( *)\t', "don't use tabs to indent"),
83 (uprefixc + r'( *)\t', "don't use tabs to indent"),
84 ]
84 ]
85
85
86 for p, m in testpats:
86 for p, m in testpats:
87 if p.startswith('^'):
87 if p.startswith('^'):
88 p = uprefix + p[1:]
88 p = uprefix + p[1:]
89 else:
89 else:
90 p = uprefix + p
90 p = uprefix + p
91 utestpats.append((p, m))
91 utestpats.append((p, m))
92
92
93 utestfilters = [
93 utestfilters = [
94 (r"( *)(#([^\n]*\S)?)", repcomment),
94 (r"( *)(#([^\n]*\S)?)", repcomment),
95 ]
95 ]
96
96
97 pypats = [
97 pypats = [
98 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
98 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
99 "tuple parameter unpacking not available in Python 3+"),
99 "tuple parameter unpacking not available in Python 3+"),
100 (r'lambda\s*\(.*,.*\)',
100 (r'lambda\s*\(.*,.*\)',
101 "tuple parameter unpacking not available in Python 3+"),
101 "tuple parameter unpacking not available in Python 3+"),
102 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
102 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
103 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
103 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
104 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
104 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
105 (r'^\s*\t', "don't use tabs"),
105 (r'^\s*\t', "don't use tabs"),
106 (r'\S;\s*\n', "semicolon"),
106 (r'\S;\s*\n', "semicolon"),
107 (r'\w,\w', "missing whitespace after ,"),
107 (r'\w,\w', "missing whitespace after ,"),
108 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
108 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
109 (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"),
109 (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"),
110 (r'.{85}', "line too long"),
110 (r'.{85}', "line too long"),
111 (r'.{81}', "warning: line over 80 characters"),
111 (r'.{81}', "warning: line over 80 characters"),
112 (r'[^\n]\Z', "no trailing newline"),
112 (r'[^\n]\Z', "no trailing newline"),
113 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
113 # (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"),
114 # (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"),
114 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"),
115 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"),
115 (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+',
116 (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+',
116 "linebreak after :"),
117 "linebreak after :"),
117 (r'class\s[^(]:', "old-style class, use class foo(object)"),
118 (r'class\s[^(]:', "old-style class, use class foo(object)"),
118 (r'^\s+del\(', "del isn't a function"),
119 (r'^\s+del\(', "del isn't a function"),
119 (r'^\s+except\(', "except isn't a function"),
120 (r'^\s+except\(', "except isn't a function"),
120 (r',]', "unneeded trailing ',' in list"),
121 (r',]', "unneeded trailing ',' in list"),
121 # (r'class\s[A-Z][^\(]*\((?!Exception)',
122 # (r'class\s[A-Z][^\(]*\((?!Exception)',
122 # "don't capitalize non-exception classes"),
123 # "don't capitalize non-exception classes"),
123 # (r'in range\(', "use xrange"),
124 # (r'in range\(', "use xrange"),
124 # (r'^\s*print\s+', "avoid using print in core and extensions"),
125 # (r'^\s*print\s+', "avoid using print in core and extensions"),
125 (r'[\x80-\xff]', "non-ASCII character literal"),
126 (r'[\x80-\xff]', "non-ASCII character literal"),
126 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
127 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
127 (r'^\s*with\s+', "with not available in Python 2.4"),
128 (r'^\s*with\s+', "with not available in Python 2.4"),
128 (r'(?<!def)\s+(any|all|format)\(',
129 (r'(?<!def)\s+(any|all|format)\(',
129 "any/all/format not available in Python 2.4"),
130 "any/all/format not available in Python 2.4"),
130 (r'(?<!def)\s+(callable)\(',
131 (r'(?<!def)\s+(callable)\(',
131 "callable not available in Python 3, use hasattr(f, '__call__')"),
132 "callable not available in Python 3, use hasattr(f, '__call__')"),
132 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
133 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
133 (r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"),
134 (r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"),
134 # (r'\s\s=', "gratuitous whitespace before ="),
135 # (r'\s\s=', "gratuitous whitespace before ="),
135 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
136 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
136 "missing whitespace around operator"),
137 "missing whitespace around operator"),
137 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s',
138 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s',
138 "missing whitespace around operator"),
139 "missing whitespace around operator"),
139 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
140 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
140 "missing whitespace around operator"),
141 "missing whitespace around operator"),
141 (r'[^+=*!<>&| -](\s=|=\s)[^= ]',
142 (r'[^+=*!<>&| -](\s=|=\s)[^= ]',
142 "wrong whitespace around ="),
143 "wrong whitespace around ="),
143 (r'raise Exception', "don't raise generic exceptions"),
144 (r'raise Exception', "don't raise generic exceptions"),
144 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
145 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
145 "warning: unwrapped ui message"),
146 "warning: unwrapped ui message"),
146 ]
147 ]
147
148
148 pyfilters = [
149 pyfilters = [
149 (r"""(?msx)(?P<comment>\#.*?$)|
150 (r"""(?msx)(?P<comment>\#.*?$)|
150 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
151 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
151 (?P<text>(([^\\]|\\.)*?))
152 (?P<text>(([^\\]|\\.)*?))
152 (?P=quote))""", reppython),
153 (?P=quote))""", reppython),
153 ]
154 ]
154
155
155 cpats = [
156 cpats = [
156 (r'//', "don't use //-style comments"),
157 (r'//', "don't use //-style comments"),
157 (r'^ ', "don't use spaces to indent"),
158 (r'^ ', "don't use spaces to indent"),
158 (r'\S\t', "don't use tabs except for indent"),
159 (r'\S\t', "don't use tabs except for indent"),
159 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
160 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
160 (r'.{85}', "line too long"),
161 (r'.{85}', "line too long"),
161 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
162 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
162 (r'return\(', "return is not a function"),
163 (r'return\(', "return is not a function"),
163 (r' ;', "no space before ;"),
164 (r' ;', "no space before ;"),
164 (r'\w+\* \w+', "use int *foo, not int* foo"),
165 (r'\w+\* \w+', "use int *foo, not int* foo"),
165 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
166 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
166 (r'\S+ (\+\+|--)', "use foo++, not foo ++"),
167 (r'\S+ (\+\+|--)', "use foo++, not foo ++"),
167 (r'\w,\w', "missing whitespace after ,"),
168 (r'\w,\w', "missing whitespace after ,"),
168 (r'\w[+/*]\w', "missing whitespace in expression"),
169 (r'\w[+/*]\w', "missing whitespace in expression"),
169 (r'^#\s+\w', "use #foo, not # foo"),
170 (r'^#\s+\w', "use #foo, not # foo"),
170 (r'[^\n]\Z', "no trailing newline"),
171 (r'[^\n]\Z', "no trailing newline"),
171 ]
172 ]
172
173
173 cfilters = [
174 cfilters = [
174 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
175 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
175 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
176 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
176 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
177 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
177 (r'(\()([^)]+\))', repcallspaces),
178 (r'(\()([^)]+\))', repcallspaces),
178 ]
179 ]
179
180
180 checks = [
181 checks = [
181 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
182 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
182 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
183 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
183 ('c', r'.*\.c$', cfilters, cpats),
184 ('c', r'.*\.c$', cfilters, cpats),
184 ('unified test', r'.*\.t$', utestfilters, utestpats),
185 ('unified test', r'.*\.t$', utestfilters, utestpats),
185 ]
186 ]
186
187
187 class norepeatlogger(object):
188 class norepeatlogger(object):
188 def __init__(self):
189 def __init__(self):
189 self._lastseen = None
190 self._lastseen = None
190
191
191 def log(self, fname, lineno, line, msg, blame):
192 def log(self, fname, lineno, line, msg, blame):
192 """print error related a to given line of a given file.
193 """print error related a to given line of a given file.
193
194
194 The faulty line will also be printed but only once in the case
195 The faulty line will also be printed but only once in the case
195 of multiple errors.
196 of multiple errors.
196
197
197 :fname: filename
198 :fname: filename
198 :lineno: line number
199 :lineno: line number
199 :line: actual content of the line
200 :line: actual content of the line
200 :msg: error message
201 :msg: error message
201 """
202 """
202 msgid = fname, lineno, line
203 msgid = fname, lineno, line
203 if msgid != self._lastseen:
204 if msgid != self._lastseen:
204 if blame:
205 if blame:
205 print "%s:%d (%s):" % (fname, lineno, blame)
206 print "%s:%d (%s):" % (fname, lineno, blame)
206 else:
207 else:
207 print "%s:%d:" % (fname, lineno)
208 print "%s:%d:" % (fname, lineno)
208 print " > %s" % line
209 print " > %s" % line
209 self._lastseen = msgid
210 self._lastseen = msgid
210 print " " + msg
211 print " " + msg
211
212
212 _defaultlogger = norepeatlogger()
213 _defaultlogger = norepeatlogger()
213
214
214 def getblame(f):
215 def getblame(f):
215 lines = []
216 lines = []
216 for l in os.popen('hg annotate -un %s' % f):
217 for l in os.popen('hg annotate -un %s' % f):
217 start, line = l.split(':', 1)
218 start, line = l.split(':', 1)
218 user, rev = start.split()
219 user, rev = start.split()
219 lines.append((line[1:-1], user, rev))
220 lines.append((line[1:-1], user, rev))
220 return lines
221 return lines
221
222
222 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
223 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
223 blame=False):
224 blame=False):
224 """checks style and portability of a given file
225 """checks style and portability of a given file
225
226
226 :f: filepath
227 :f: filepath
227 :logfunc: function used to report error
228 :logfunc: function used to report error
228 logfunc(filename, linenumber, linecontent, errormessage)
229 logfunc(filename, linenumber, linecontent, errormessage)
229 :maxerr: number of error to display before arborting.
230 :maxerr: number of error to display before arborting.
230 Set to None (default) to report all errors
231 Set to None (default) to report all errors
231
232
232 return True if no error is found, False otherwise.
233 return True if no error is found, False otherwise.
233 """
234 """
234 blamecache = None
235 blamecache = None
235 result = True
236 result = True
236 for name, match, filters, pats in checks:
237 for name, match, filters, pats in checks:
237 fc = 0
238 fc = 0
238 if not re.match(match, f):
239 if not re.match(match, f):
239 continue
240 continue
240 pre = post = open(f).read()
241 pre = post = open(f).read()
241 if "no-" + "check-code" in pre:
242 if "no-" + "check-code" in pre:
242 break
243 break
243 for p, r in filters:
244 for p, r in filters:
244 post = re.sub(p, r, post)
245 post = re.sub(p, r, post)
245 # print post # uncomment to show filtered version
246 # print post # uncomment to show filtered version
246 z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
247 z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
247 for n, l in z:
248 for n, l in z:
248 if "check-code" + "-ignore" in l[0]:
249 if "check-code" + "-ignore" in l[0]:
249 continue
250 continue
250 for p, msg in pats:
251 for p, msg in pats:
251 if not warnings and msg.startswith("warning"):
252 if not warnings and msg.startswith("warning"):
252 continue
253 continue
253 if re.search(p, l[1]):
254 if re.search(p, l[1]):
254 bd = ""
255 bd = ""
255 if blame:
256 if blame:
256 bd = 'working directory'
257 bd = 'working directory'
257 if not blamecache:
258 if not blamecache:
258 blamecache = getblame(f)
259 blamecache = getblame(f)
259 if n < len(blamecache):
260 if n < len(blamecache):
260 bl, bu, br = blamecache[n]
261 bl, bu, br = blamecache[n]
261 if bl == l[0]:
262 if bl == l[0]:
262 bd = '%s@%s' % (bu, br)
263 bd = '%s@%s' % (bu, br)
263 logfunc(f, n + 1, l[0], msg, bd)
264 logfunc(f, n + 1, l[0], msg, bd)
264 fc += 1
265 fc += 1
265 result = False
266 result = False
266 if maxerr is not None and fc >= maxerr:
267 if maxerr is not None and fc >= maxerr:
267 print " (too many errors, giving up)"
268 print " (too many errors, giving up)"
268 break
269 break
269 break
270 break
270 return result
271 return result
271
272
272 if __name__ == "__main__":
273 if __name__ == "__main__":
273 parser = optparse.OptionParser("%prog [options] [files]")
274 parser = optparse.OptionParser("%prog [options] [files]")
274 parser.add_option("-w", "--warnings", action="store_true",
275 parser.add_option("-w", "--warnings", action="store_true",
275 help="include warning-level checks")
276 help="include warning-level checks")
276 parser.add_option("-p", "--per-file", type="int",
277 parser.add_option("-p", "--per-file", type="int",
277 help="max warnings per file")
278 help="max warnings per file")
278 parser.add_option("-b", "--blame", action="store_true",
279 parser.add_option("-b", "--blame", action="store_true",
279 help="use annotate to generate blame info")
280 help="use annotate to generate blame info")
280
281
281 parser.set_defaults(per_file=15, warnings=False, blame=False)
282 parser.set_defaults(per_file=15, warnings=False, blame=False)
282 (options, args) = parser.parse_args()
283 (options, args) = parser.parse_args()
283
284
284 if len(args) == 0:
285 if len(args) == 0:
285 check = glob.glob("*")
286 check = glob.glob("*")
286 else:
287 else:
287 check = args
288 check = args
288
289
289 for f in check:
290 for f in check:
290 ret = 0
291 ret = 0
291 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
292 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
292 blame=options.blame):
293 blame=options.blame):
293 ret = 1
294 ret = 1
294 sys.exit(ret)
295 sys.exit(ret)
General Comments 0
You need to be logged in to leave comments. Login now