contrib/check-code.py
author Martin Geisler <mg@aragost.com>
Thu, 10 Mar 2011 16:49:37 +0100
changeset 13576 edd06611a7c6
parent 13524 121c89dd7983
child 13736 f3c4421e121c
permissions -rwxr-xr-x
ui: yield unchanged values in walkconfig Ever since walkconfig was introduced back in 25e7ea0f2cff, the values yielded has been mutated by replacing "\n" with "\\n". This makes walkconfig less useful than it could and there is no other way to iterate over all config sections. The third-party reposettings extension used ui.walkconfig but did not take the replacement into account -- this change will actually fix a bug in the extension when a value contains a newline.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
11816
e1359ad582f6 check-code: add exit status
Alecs King <alecsk@gmail.com>
parents: 11764
diff changeset
    10
import re, glob, os, sys
13074
637627f31c74 check-code: check for gratuitous whitespace after Python keywords
Thomas Arendsen Hein <thomas@jtah.de>
parents: 13031
diff changeset
    11
import keyword
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
    12
import optparse
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    13
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    14
def repquote(m):
10722
c4fb2103e734 check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10720
diff changeset
    15
    t = re.sub(r"\w", "x", m.group('text'))
10451
63a9bfad50ff check-code: two more rules
Matt Mackall <mpm@selenic.com>
parents: 10412
diff changeset
    16
    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
    17
    return m.group('quote') + t + m.group('quote')
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    18
10727
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
    19
def reppython(m):
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
    20
    comment = m.group('comment')
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
    21
    if comment:
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
    22
        return "#" * len(comment)
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
    23
    return repquote(m)
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    24
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
def repcomment(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
    return m.group(1) + "#" * len(m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    28
def repccomment(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
    t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
    return m.group(1) + t + "*/"
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
def repcallspaces(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    33
    t = re.sub(r"\n\s+", "\n", m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    34
    return m.group(1) + t
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    36
def repinclude(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
    return m.group(1) + "<foo>"
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
def rephere(m):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
    t = re.sub(r"\S", "x", m.group(2))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
    return m.group(1) + t
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
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    44
testpats = [
10374
3aa35db5e38c check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents: 10373
diff changeset
    45
    (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
    46
    (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    47
    (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
    48
    (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
    49
    (r'echo.*\\n', "don't use 'echo \\n', use printf"),
11884
932448701e7d check-code: catch "echo -n" in tests
Martin Geisler <mg@lazybytes.net>
parents: 11599
diff changeset
    50
    (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
    51
    (r'^diff.*-\w*N', "don't use 'diff -N'"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
    (r'(^| )wc[^|]*$', "filter wc output"),
10374
3aa35db5e38c check-code.py: make help strings consistent
Martin Geisler <mg@lazybytes.net>
parents: 10373
diff changeset
    53
    (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
    54
    (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
    55
    (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
    56
    (r'printf.*\\x', "don't use printf \\x, use Python"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
    (r'\$\(.*\)', "don't use $(expr), use `expr`"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
    (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
    59
    (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
     "use egrep for extended grep syntax"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
    (r'/bin/', "don't use explicit paths for tools"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
    (r'\$PWD', "don't use $PWD, use `pwd`"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
    (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
    64
    (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
    65
    ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
11210
0c0088881562 check-code: add check for 'source'
Yuya Nishihara <yuya@tcha.org>
parents: 10905
diff changeset
    66
    (r'^source\b', "don't use 'source', use '.'"),
12367
3acd5f7ab9d0 tests: compatibility fix.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 12366
diff changeset
    67
    (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
13301
4b07578967e6 check-code: do not complain about 'ls x | foo -v'
Martin Geisler <mg@aragost.com>
parents: 13161
diff changeset
    68
    (r'ls\s+[^|-]+\s+-', "options to 'ls' must come before filenames"),
13524
121c89dd7983 check-code: catch "echo > $HGRCPATH" too
Martin Geisler <mg@aragost.com>
parents: 13522
diff changeset
    69
    (r'[^>]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
10281
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
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
testfilters = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
    (r"( *)(#([^\n]*\S)?)", repcomment),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
    (r"<<(\S+)((.|\n)*?\n\1)", rephere),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
12364
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    77
uprefix = r"^  \$ "
12743
4c4aeaab2339 check-code: add 'no tab indent' check for unified tests
Adrian Buehlmann <adrian@cadifra.com>
parents: 12367
diff changeset
    78
uprefixc = r"^  > "
12364
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    79
utestpats = [
12785
c7d23b4ca4ba check-code: warning and fixes for whitespace in unified tests
Matt Mackall <mpm@selenic.com>
parents: 12770
diff changeset
    80
    (r'^(\S|  $ ).*(\S\s+|^\s+)\n', "trailing whitespace on non-output"),
12366
c01dc9087d9a tests: drop a bunch of sed calls from unified tests
Matt Mackall <mpm@selenic.com>
parents: 12364
diff changeset
    81
    (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
12364
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    82
    (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    83
    (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"),
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    84
    (uprefix + r'.*\|\| echo.*(fail|error)',
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    85
     "explicit exit code checks unnecessary"),
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    86
    (uprefix + r'set -e', "don't use set -e"),
12743
4c4aeaab2339 check-code: add 'no tab indent' check for unified tests
Adrian Buehlmann <adrian@cadifra.com>
parents: 12367
diff changeset
    87
    (uprefixc + r'( *)\t', "don't use tabs to indent"),
12364
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    88
]
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    89
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    90
for p, m in testpats:
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    91
    if p.startswith('^'):
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    92
        p = uprefix + p[1:]
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    93
    else:
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    94
        p = uprefix + p
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    95
    utestpats.append((p, m))
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    96
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    97
utestfilters = [
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    98
    (r"( *)(#([^\n]*\S)?)", repcomment),
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
    99
]
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
   100
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   101
pypats = [
11568
d5d4e6a30613 check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents: 11522
diff changeset
   102
    (r'^\s*def\s*\w+\s*\(.*,\s*\(',
d5d4e6a30613 check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents: 11522
diff changeset
   103
     "tuple parameter unpacking not available in Python 3+"),
d5d4e6a30613 check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents: 11522
diff changeset
   104
    (r'lambda\s*\(.*,.*\)',
d5d4e6a30613 check-code: check for tuple parameter unpacking (missing in py3k)
Renato Cunha <renatoc@gmail.com>
parents: 11522
diff changeset
   105
     "tuple parameter unpacking not available in Python 3+"),
11764
16723af520b0 check-code: added a check for calls to the builtin cmp function
Renato Cunha <renatoc@gmail.com>
parents: 11672
diff changeset
   106
    (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
11569
f8576644a222 check-code: added check for reduce usage
Renato Cunha <renatoc@gmail.com>
parents: 11568
diff changeset
   107
    (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
11602
ba2520dd1e29 check-code: catch dict.has_key
Martin Geisler <mg@lazybytes.net>
parents: 11601
diff changeset
   108
    (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   109
    (r'^\s*\t', "don't use tabs"),
10412
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
   110
    (r'\S;\s*\n', "semicolon"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   111
    (r'\w,\w', "missing whitespace after ,"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   112
    (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   113
    (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   114
    (r'.{85}', "line too long"),
11672
dad185761392 check-code: add warning on lines over 80 characters
Matt Mackall <mpm@selenic.com>
parents: 11604
diff changeset
   115
    (r'.{81}', "warning: line over 80 characters"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   116
    (r'[^\n]\Z', "no trailing newline"),
12770
614f0d8724ab check-code: find trailing whitespace
Martin Geisler <mg@lazybytes.net>
parents: 12743
diff changeset
   117
    (r'(\S\s+|^\s+)\n', "trailing whitespace"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   118
#    (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   119
#    (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
   120
    (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
   121
     "linebreak after :"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
    (r'class\s[^(]:', "old-style class, use class foo(object)"),
13076
a861c7155f09 check-code: single check for Python keywords used as a function
Thomas Arendsen Hein <thomas@jtah.de>
parents: 13074
diff changeset
   123
    (r'\b(%s)\(' % '|'.join(keyword.kwlist),
a861c7155f09 check-code: single check for Python keywords used as a function
Thomas Arendsen Hein <thomas@jtah.de>
parents: 13074
diff changeset
   124
     "Python keyword is not a function"),
10412
5326800d6937 check-code: import some pylint checks
Matt Mackall <mpm@selenic.com>
parents: 10374
diff changeset
   125
    (r',]', "unneeded trailing ',' in list"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   126
#    (r'class\s[A-Z][^\(]*\((?!Exception)',
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   127
#     "don't capitalize non-exception classes"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   128
#    (r'in range\(', "use xrange"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   129
#    (r'^\s*print\s+', "avoid using print in core and extensions"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   130
    (r'[\x80-\xff]', "non-ASCII character literal"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   131
    (r'("\')\.format\(', "str.format() not available in Python 2.4"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   132
    (r'^\s*with\s+', "with not available in Python 2.4"),
13160
07d08c130892 check-code: catch "except as"
Matt Mackall <mpm@selenic.com>
parents: 13076
diff changeset
   133
    (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
13161
11eb53464e68 check-code: catch os.path.relpath
Matt Mackall <mpm@selenic.com>
parents: 13160
diff changeset
   134
    (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
11345
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   135
    (r'(?<!def)\s+(any|all|format)\(',
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   136
     "any/all/format not available in Python 2.4"),
11522
eaa7666ad53f check-code: add test for callable
Martin Geisler <mg@aragost.com>
parents: 11345
diff changeset
   137
    (r'(?<!def)\s+(callable)\(',
eaa7666ad53f check-code: add test for callable
Martin Geisler <mg@aragost.com>
parents: 11345
diff changeset
   138
     "callable not available in Python 3, use hasattr(f, '__call__')"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   139
    (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
13074
637627f31c74 check-code: check for gratuitous whitespace after Python keywords
Thomas Arendsen Hein <thomas@jtah.de>
parents: 13031
diff changeset
   140
    (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
637627f31c74 check-code: check for gratuitous whitespace after Python keywords
Thomas Arendsen Hein <thomas@jtah.de>
parents: 13031
diff changeset
   141
     "gratuitous whitespace after Python keyword"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   142
    (r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   143
#    (r'\s\s=', "gratuitous whitespace before ="),
11345
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   144
    (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   145
     "missing whitespace around operator"),
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   146
    (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s',
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   147
     "missing whitespace around operator"),
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   148
    (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   149
     "missing whitespace around operator"),
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   150
    (r'[^+=*!<>&| -](\s=|=\s)[^= ]',
4b81f82b03e3 check-code: reformat long lines
Martin Geisler <mg@aragost.com>
parents: 11343
diff changeset
   151
     "wrong whitespace around ="),
10451
63a9bfad50ff check-code: two more rules
Matt Mackall <mpm@selenic.com>
parents: 10412
diff changeset
   152
    (r'raise Exception', "don't raise generic exceptions"),
11599
6fcc066c0c2c check-code: warn about untranslated ui.warn calls
Martin Geisler <mg@lazybytes.net>
parents: 11522
diff changeset
   153
    (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   154
     "warning: unwrapped ui message"),
13026
53391819f195 check-code: catch Python 'is' comparing number or string literals
Adrian Buehlmann <adrian@cadifra.com>
parents: 13012
diff changeset
   155
    (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
13031
3da456d0c885 code style: prefer 'is' and 'is not' tests with singletons
Martin Geisler <mg@aragost.com>
parents: 13026
diff changeset
   156
    (r' [=!]=\s+(True|False|None)',
3da456d0c885 code style: prefer 'is' and 'is not' tests with singletons
Martin Geisler <mg@aragost.com>
parents: 13026
diff changeset
   157
     "comparison with singleton, use 'is' or 'is not' instead"),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   158
]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   159
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   160
pyfilters = [
10727
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
   161
    (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
   162
         ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
   163
          (?P<text>(([^\\]|\\.)*?))
62b8f15683f2 check-code: more tests and more robust python filtering
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10723
diff changeset
   164
          (?P=quote))""", reppython),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   165
]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   166
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   167
cpats = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   168
    (r'//', "don't use //-style comments"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   169
    (r'^  ', "don't use spaces to indent"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   170
    (r'\S\t', "don't use tabs except for indent"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   171
    (r'(\S\s+|^\s+)\n', "trailing whitespace"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   172
    (r'.{85}', "line too long"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   173
    (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
   174
    (r'return\(', "return is not a function"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   175
    (r' ;', "no space before ;"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   176
    (r'\w+\* \w+', "use int *foo, not int* foo"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   177
    (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   178
    (r'\S+ (\+\+|--)', "use foo++, not foo ++"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   179
    (r'\w,\w', "missing whitespace after ,"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   180
    (r'\w[+/*]\w', "missing whitespace in expression"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   181
    (r'^#\s+\w', "use #foo, not # foo"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   182
    (r'[^\n]\Z', "no trailing newline"),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   183
]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   184
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   185
cfilters = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   186
    (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
10722
c4fb2103e734 check-code: improve quote detection regexp, add tests
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10720
diff changeset
   187
    (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   188
    (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   189
    (r'(\()([^)]+\))', repcallspaces),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   190
]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   191
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   192
checks = [
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   193
    ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   194
    ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   195
    ('c', r'.*\.c$', cfilters, cpats),
12364
e128fa4615f2 check-code: add some basic support for unified tests
Matt Mackall <mpm@selenic.com>
parents: 11886
diff changeset
   196
    ('unified test', r'.*\.t$', utestfilters, utestpats),
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   197
]
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   198
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   199
class norepeatlogger(object):
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   200
    def __init__(self):
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   201
        self._lastseen = None
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   202
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   203
    def log(self, fname, lineno, line, msg, blame):
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   204
        """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
   205
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   206
        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
   207
        of multiple errors.
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   208
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   209
        :fname: filename
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   210
        :lineno: line number
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   211
        :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
   212
        :msg: error message
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   213
        """
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   214
        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
   215
        if msgid != self._lastseen:
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   216
            if blame:
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   217
                print "%s:%d (%s):" % (fname, lineno, blame)
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   218
            else:
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   219
                print "%s:%d:" % (fname, lineno)
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   220
            print " > %s" % line
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   221
            self._lastseen = msgid
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   222
        print " " + msg
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   223
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   224
_defaultlogger = norepeatlogger()
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   225
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   226
def getblame(f):
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   227
    lines = []
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   228
    for l in os.popen('hg annotate -un %s' % f):
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   229
        start, line = l.split(':', 1)
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   230
        user, rev = start.split()
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   231
        lines.append((line[1:-1], user, rev))
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   232
    return lines
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   233
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   234
def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   235
              blame=False):
10719
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   236
    """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
   237
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   238
    :f: filepath
3be9ae49b628 code-code: Add a logfunc argument to checkfile
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10718
diff changeset
   239
    :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
   240
              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
   241
    :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
   242
             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
   243
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
   244
    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
   245
    """
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   246
    blamecache = None
10720
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
   247
    result = True
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   248
    for name, match, filters, pats in checks:
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   249
        fc = 0
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   250
        if not re.match(match, f):
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   251
            continue
13400
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13301
diff changeset
   252
        fp = open(f)
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13301
diff changeset
   253
        pre = post = fp.read()
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13301
diff changeset
   254
        fp.close()
10287
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
   255
        if "no-" + "check-code" in pre:
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
   256
            break
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   257
        for p, r in filters:
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   258
            post = re.sub(p, r, post)
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   259
        # print post # uncomment to show filtered version
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   260
        z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   261
        for n, l in z:
10287
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
   262
            if "check-code" + "-ignore" in l[0]:
5da892be3497 check-code: add some ignore hints
Matt Mackall <mpm@selenic.com>
parents: 10286
diff changeset
   263
                continue
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   264
            for p, msg in pats:
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   265
                if not warnings and msg.startswith("warning"):
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   266
                    continue
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   267
                if re.search(p, l[1]):
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   268
                    bd = ""
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   269
                    if blame:
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   270
                        bd = 'working directory'
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   271
                        if not blamecache:
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   272
                            blamecache = getblame(f)
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   273
                        if n < len(blamecache):
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   274
                            bl, bu, br = blamecache[n]
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   275
                            if bl == l[0]:
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   276
                                bd = '%s@%s' % (bu, br)
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   277
                    logfunc(f, n + 1, l[0], msg, bd)
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   278
                    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
   279
                    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
   280
            if maxerr is not None and fc >= maxerr:
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   281
                print " (too many errors, giving up)"
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   282
                break
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   283
        break
10720
fbcccf9ec58f check-code: add a return value to checkfile function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10719
diff changeset
   284
    return result
10717
b1f4fcef99b3 check-code: Add a ``checkfile`` function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10716
diff changeset
   285
10716
5f92bde72eef check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10707
diff changeset
   286
if __name__ == "__main__":
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   287
    parser = optparse.OptionParser("%prog [options] [files]")
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   288
    parser.add_option("-w", "--warnings", action="store_true",
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   289
                      help="include warning-level checks")
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   290
    parser.add_option("-p", "--per-file", type="int",
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   291
                      help="max warnings per file")
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   292
    parser.add_option("-b", "--blame", action="store_true",
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   293
                      help="use annotate to generate blame info")
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   294
11604
c5d40818b270 check-code: add --blame switch
Matt Mackall <mpm@selenic.com>
parents: 11602
diff changeset
   295
    parser.set_defaults(per_file=15, warnings=False, blame=False)
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   296
    (options, args) = parser.parse_args()
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   297
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   298
    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
   299
        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
   300
    else:
10895
217557b26bc7 check-code: add a warnings level
Matt Mackall <mpm@selenic.com>
parents: 10814
diff changeset
   301
        check = args
10281
e7d3b509af8b Introduce check-code.py
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   302
10716
5f92bde72eef check-code: Only call check-code if __name__ = "__main__".
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 10707
diff changeset
   303
    for f in check:
11816
e1359ad582f6 check-code: add exit status
Alecs King <alecsk@gmail.com>
parents: 11764
diff changeset
   304
        ret = 0
e1359ad582f6 check-code: add exit status
Alecs King <alecsk@gmail.com>
parents: 11764
diff changeset
   305
        if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
e1359ad582f6 check-code: add exit status
Alecs King <alecsk@gmail.com>
parents: 11764
diff changeset
   306
                         blame=options.blame):
e1359ad582f6 check-code: add exit status
Alecs King <alecsk@gmail.com>
parents: 11764
diff changeset
   307
            ret = 1
e1359ad582f6 check-code: add exit status
Alecs King <alecsk@gmail.com>
parents: 11764
diff changeset
   308
    sys.exit(ret)