contrib/check-code.py
changeset 10895 217557b26bc7
parent 10814 cd0c49bdbfd9
child 10905 13a1b2fb7ef2
equal deleted inserted replaced
10894:26cf11f9f322 10895:217557b26bc7
     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 sys, re, glob
    10 import sys, re, glob
       
    11 import optparse
    11 
    12 
    12 def repquote(m):
    13 def repquote(m):
    13     t = re.sub(r"\w", "x", m.group('text'))
    14     t = re.sub(r"\w", "x", m.group('text'))
    14     t = re.sub(r"[^\sx]", "o", t)
    15     t = re.sub(r"[^\sx]", "o", t)
    15     return m.group('quote') + t + m.group('quote')
    16     return m.group('quote') + t + m.group('quote')
    97     (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
    98     (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
    98     (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s', "missing whitespace around operator"),
    99     (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s', "missing whitespace around operator"),
    99     (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
   100     (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
   100     (r'[^+=*!<>&| -](\s=|=\s)[^= ]', "wrong whitespace around ="),
   101     (r'[^+=*!<>&| -](\s=|=\s)[^= ]', "wrong whitespace around ="),
   101     (r'raise Exception', "don't raise generic exceptions"),
   102     (r'raise Exception', "don't raise generic exceptions"),
   102     (r'ui\.(status|progress|write|note)\([\'\"]x', "unwrapped ui message"),
   103     (r'ui\.(status|progress|write|note)\([\'\"]x',
       
   104      "warning: unwrapped ui message"),
   103 ]
   105 ]
   104 
   106 
   105 pyfilters = [
   107 pyfilters = [
   106     (r"""(?msx)(?P<comment>\#.*?$)|
   108     (r"""(?msx)(?P<comment>\#.*?$)|
   107          ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
   109          ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
   162             self._lastseen = msgid
   164             self._lastseen = msgid
   163         print " " + msg
   165         print " " + msg
   164 
   166 
   165 _defaultlogger = norepeatlogger()
   167 _defaultlogger = norepeatlogger()
   166 
   168 
   167 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None):
   169 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False):
   168     """checks style and portability of a given file
   170     """checks style and portability of a given file
   169 
   171 
   170     :f: filepath
   172     :f: filepath
   171     :logfunc: function used to report error
   173     :logfunc: function used to report error
   172               logfunc(filename, linenumber, linecontent, errormessage)
   174               logfunc(filename, linenumber, linecontent, errormessage)
   189         z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
   191         z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
   190         for n, l in z:
   192         for n, l in z:
   191             if "check-code" + "-ignore" in l[0]:
   193             if "check-code" + "-ignore" in l[0]:
   192                 continue
   194                 continue
   193             for p, msg in pats:
   195             for p, msg in pats:
       
   196                 if not warnings and msg.startswith("warning"):
       
   197                     continue
   194                 if re.search(p, l[1]):
   198                 if re.search(p, l[1]):
   195                     logfunc(f, n + 1, l[0], msg)
   199                     logfunc(f, n + 1, l[0], msg)
   196                     fc += 1
   200                     fc += 1
   197                     result = False
   201                     result = False
   198             if maxerr is not None and fc >= maxerr:
   202             if maxerr is not None and fc >= maxerr:
   201         break
   205         break
   202     return result
   206     return result
   203 
   207 
   204 
   208 
   205 if __name__ == "__main__":
   209 if __name__ == "__main__":
   206     if len(sys.argv) == 1:
   210     parser = optparse.OptionParser("%prog [options] [files]")
       
   211     parser.add_option("-w", "--warnings", action="store_true",
       
   212                       help="include warning-level checks")
       
   213     parser.add_option("-p", "--per-file", type="int",
       
   214                       help="max warnings per file")
       
   215 
       
   216     parser.set_defaults(per_file=15, warnings=False)
       
   217     (options, args) = parser.parse_args()
       
   218 
       
   219     if len(args) == 0:
   207         check = glob.glob("*")
   220         check = glob.glob("*")
   208     else:
   221     else:
   209         check = sys.argv[1:]
   222         check = args
   210 
   223 
   211     for f in check:
   224     for f in check:
   212         checkfile(f, maxerr=15)
   225         checkfile(f, maxerr=options.per_file, warnings=options.warnings)