/ cppcheck.py
cppcheck.py
1 # This file is part of Buildbot. Buildbot is free software: you can 2 # redistribute it and/or modify it under the terms of the GNU General Public 3 # License as published by the Free Software Foundation, version 2. 4 # 5 # This program is distributed in the hope that it will be useful, but WITHOUT 6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 8 # details. 9 # 10 # You should have received a copy of the GNU General Public License along with 11 # this program; if not, write to the Free Software Foundation, Inc., 51 12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 13 # 14 # Copyright Buildbot Team Members 15 16 import re 17 18 from buildbot.process import logobserver 19 from buildbot.status.results import FAILURE 20 from buildbot.status.results import SUCCESS 21 from buildbot.status.results import WARNINGS 22 from buildbot.steps.shell import ShellCommand 23 24 25 class Cppcheck(ShellCommand): 26 # Highly inspirated from the Pylint step. 27 name = "cppcheck" 28 description = ["running", "cppcheck"] 29 descriptionDone = ["cppcheck"] 30 flunkingIssues = ('error',) 31 32 MESSAGES = ( 33 'error', 'warning', 'style', 'performance', 'portability', 'information') 34 35 renderables = ('binary', 'source', 'extra_args') 36 37 def __init__(self, *args, **kwargs): 38 39 for name, default in [('binary', 'cppcheck'), 40 ('source', ['.']), 41 ('enable', []), 42 ('inconclusive', False), 43 ('extra_args', [])]: 44 setattr(self, name, default) 45 if name in kwargs: 46 setattr(self, name, kwargs[name]) 47 del kwargs[name] 48 49 ShellCommand.__init__(self, *args, **kwargs) 50 self.addLogObserver( 51 'stdio', logobserver.LogLineObserver()) 52 53 command = [self.binary] 54 command.extend(self.source) 55 if self.enable: 56 command.append('--enable=%s' % ','.join(self.enable)) 57 if self.inconclusive: 58 command.append('--inconclusive') 59 command.extend(self.extra_args) 60 self.setCommand(command) 61 62 counts = self.counts = {} 63 summaries = self.summaries = {} 64 for m in self.MESSAGES: 65 counts[m] = 0 66 summaries[m] = [] 67 68 def logConsumer(self): 69 line_re = re.compile( 70 r'(?:\[.+\]: )?\((?P<severity>%s)\) .+' % '|'.join(self.MESSAGES)) 71 72 while True: 73 stream, line = yield 74 m = line_re.match(line) 75 if m is not None: 76 msgsev = m.group('severity') 77 self.summaries[msgsev].append(line) 78 self.counts[msgsev] += 1 79 80 def createSummary(self, log): 81 self.descriptionDone = self.descriptionDone[:] 82 for msg in self.MESSAGES: 83 self.setProperty('cppcheck-%s' % msg, self.counts[msg], 'Cppcheck') 84 if not self.counts[msg]: 85 continue 86 self.descriptionDone.append("%s=%d" % (msg, self.counts[msg])) 87 self.addCompleteLog(msg, '\n'.join(self.summaries[msg])) 88 self.setProperty('cppcheck-total', sum(self.counts.values()), 'Cppcheck') 89 90 def evaluateCommand(self, cmd): 91 """ cppcheck always return 0, unless a special parameter is given """ 92 for msg in self.flunkingIssues: 93 if self.counts[msg] != 0: 94 return FAILURE 95 if self.getProperty('cppcheck-total') != 0: 96 return WARNINGS 97 return SUCCESS