/ 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