contrib/check-code.py
changeset 10719 3be9ae49b628
parent 10718 f18c37fd624f
child 10720 fbcccf9ec58f
equal deleted inserted replaced
10718:f18c37fd624f 10719:3be9ae49b628
   131 checks = [
   131 checks = [
   132     ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
   132     ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
   133     ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
   133     ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
   134     ('c', r'.*\.c$', cfilters, cpats),
   134     ('c', r'.*\.c$', cfilters, cpats),
   135 ]
   135 ]
   136 def checkfile(f, maxerr=None):
   136 
   137     """checks style and portability of a given file"""
   137 class norepeatlogger(object):
       
   138     def __init__(self):
       
   139         self._lastseen = None
       
   140 
       
   141     def log(self, fname, lineno, line, msg):
       
   142         """print error related a to given line of a given file.
       
   143 
       
   144         The faulty line will also be printed but only once in the case
       
   145         of multiple errors.
       
   146 
       
   147         :fname: filename
       
   148         :lineno: line number
       
   149         :line: actual content of the line
       
   150         :msg: error message
       
   151         """
       
   152         msgid = fname, lineno, line
       
   153         if msgid != self._lastseen:
       
   154             print "%s:%d:" % (fname, lineno)
       
   155             print " > %s" % line
       
   156             self._lastseen = msgid
       
   157         print " " + msg
       
   158 
       
   159 _defaultlogger = norepeatlogger()
       
   160 
       
   161 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None):
       
   162     """checks style and portability of a given file
       
   163 
       
   164     :f: filepath
       
   165     :logfunc: function used to report error
       
   166               logfunc(filename, linenumber, linecontent, errormessage)
       
   167     :maxerr: number of error to display before arborting.
       
   168              Set to None (default) to report all errors
       
   169     """
   138     for name, match, filters, pats in checks:
   170     for name, match, filters, pats in checks:
   139         fc = 0
   171         fc = 0
   140         if not re.match(match, f):
   172         if not re.match(match, f):
   141             continue
   173             continue
   142         pre = post = open(f).read()
   174         pre = post = open(f).read()
   147         # print post # uncomment to show filtered version
   179         # print post # uncomment to show filtered version
   148         z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
   180         z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
   149         for n, l in z:
   181         for n, l in z:
   150             if "check-code" + "-ignore" in l[0]:
   182             if "check-code" + "-ignore" in l[0]:
   151                 continue
   183                 continue
   152             lc = 0
       
   153             for p, msg in pats:
   184             for p, msg in pats:
   154                 if re.search(p, l[1]):
   185                 if re.search(p, l[1]):
   155                     if not lc:
   186                     logfunc(f, n+1, l[0], msg)
   156                         print "%s:%d:" % (f, n + 1)
       
   157                         print " > %s" % l[0]
       
   158                     print " %s" % msg
       
   159                     lc += 1
       
   160                     fc += 1
   187                     fc += 1
   161             if maxerr is not None and fc >= maxerr:
   188             if maxerr is not None and fc >= maxerr:
   162                 print " (too many errors, giving up)"
   189                 print " (too many errors, giving up)"
   163                 break
   190                 break
   164         break
   191         break