Package buildbot :: Package steps :: Module python
[frames] | no frames]

Source Code for Module buildbot.steps.python

  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   
 17  from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS 
 18  from buildbot.steps.shell import ShellCommand 
 19  import re 
 20   
 21  try: 
 22      import cStringIO 
 23      StringIO = cStringIO.StringIO 
 24  except ImportError: 
 25      from StringIO import StringIO 
 26   
 27   
28 -class BuildEPYDoc(ShellCommand):
29 name = "epydoc" 30 command = ["make", "epydocs"] 31 description = ["building", "epydocs"] 32 descriptionDone = ["epydoc"] 33
34 - def createSummary(self, log):
35 import_errors = 0 36 warnings = 0 37 errors = 0 38 39 for line in StringIO(log.getText()): 40 if line.startswith("Error importing "): 41 import_errors += 1 42 if line.find("Warning: ") != -1: 43 warnings += 1 44 if line.find("Error: ") != -1: 45 errors += 1 46 47 self.descriptionDone = self.descriptionDone[:] 48 if import_errors: 49 self.descriptionDone.append("ierr=%d" % import_errors) 50 if warnings: 51 self.descriptionDone.append("warn=%d" % warnings) 52 if errors: 53 self.descriptionDone.append("err=%d" % errors) 54 55 self.import_errors = import_errors 56 self.warnings = warnings 57 self.errors = errors
58
59 - def evaluateCommand(self, cmd):
60 if cmd.rc != 0: 61 return FAILURE 62 if self.warnings or self.errors: 63 return WARNINGS 64 return SUCCESS
65 66
67 -class PyFlakes(ShellCommand):
68 name = "pyflakes" 69 command = ["make", "pyflakes"] 70 description = ["running", "pyflakes"] 71 descriptionDone = ["pyflakes"] 72 flunkOnFailure = False 73 flunkingIssues = ["undefined"] # any pyflakes lines like this cause FAILURE 74 75 MESSAGES = ("unused", "undefined", "redefs", "import*", "misc") 76
77 - def createSummary(self, log):
78 counts = {} 79 summaries = {} 80 for m in self.MESSAGES: 81 counts[m] = 0 82 summaries[m] = [] 83 84 first = True 85 for line in StringIO(log.getText()).readlines(): 86 # the first few lines might contain echoed commands from a 'make 87 # pyflakes' step, so don't count these as warnings. Stop ignoring 88 # the initial lines as soon as we see one with a colon. 89 if first: 90 if line.find(":") != -1: 91 # there's the colon, this is the first real line 92 first = False 93 # fall through and parse the line 94 else: 95 # skip this line, keep skipping non-colon lines 96 continue 97 if line.find("imported but unused") != -1: 98 m = "unused" 99 elif line.find("*' used; unable to detect undefined names") != -1: 100 m = "import*" 101 elif line.find("undefined name") != -1: 102 m = "undefined" 103 elif line.find("redefinition of unused") != -1: 104 m = "redefs" 105 else: 106 m = "misc" 107 summaries[m].append(line) 108 counts[m] += 1 109 110 self.descriptionDone = self.descriptionDone[:] 111 for m in self.MESSAGES: 112 if counts[m]: 113 self.descriptionDone.append("%s=%d" % (m, counts[m])) 114 self.addCompleteLog(m, "".join(summaries[m])) 115 self.setProperty("pyflakes-%s" % m, counts[m], "pyflakes") 116 self.setProperty("pyflakes-total", sum(counts.values()), "pyflakes")
117 118
119 - def evaluateCommand(self, cmd):
120 if cmd.rc != 0: 121 return FAILURE 122 for m in self.flunkingIssues: 123 if self.getProperty("pyflakes-%s" % m): 124 return FAILURE 125 if self.getProperty("pyflakes-total"): 126 return WARNINGS 127 return SUCCESS
128
129 -class PyLint(ShellCommand):
130 '''A command that knows about pylint output. 131 It's a good idea to add --output-format=parseable to your 132 command, since it includes the filename in the message. 133 ''' 134 name = "pylint" 135 description = ["running", "pylint"] 136 descriptionDone = ["pylint"] 137 138 # Using the default text output, the message format is : 139 # MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE 140 # with --output-format=parseable it is: (the outer brackets are literal) 141 # FILE_NAME:LINE_NUM: [MESSAGE_TYPE[, OBJECT]] MESSAGE 142 # message type consists of the type char and 4 digits 143 # The message types: 144 145 MESSAGES = { 146 'C': "convention", # for programming standard violation 147 'R': "refactor", # for bad code smell 148 'W': "warning", # for python specific problems 149 'E': "error", # for much probably bugs in the code 150 'F': "fatal", # error prevented pylint from further processing. 151 'I': "info", 152 } 153 154 flunkingIssues = ["F", "E"] # msg categories that cause FAILURE 155 156 _re_groupname = 'errtype' 157 _msgtypes_re_str = '(?P<%s>[%s])' % (_re_groupname, ''.join(MESSAGES.keys())) 158 _default_line_re = re.compile(r'%s\d{4}: *\d+:.+' % _msgtypes_re_str) 159 _parseable_line_re = re.compile(r'[^:]+:\d+: \[%s\d{4}[,\]] .+' % _msgtypes_re_str) 160
161 - def createSummary(self, log):
162 counts = {} 163 summaries = {} 164 for m in self.MESSAGES: 165 counts[m] = 0 166 summaries[m] = [] 167 168 line_re = None # decide after first match 169 for line in StringIO(log.getText()).readlines(): 170 if not line_re: 171 # need to test both and then decide on one 172 if self._parseable_line_re.match(line): 173 line_re = self._parseable_line_re 174 elif self._default_line_re.match(line): 175 line_re = self._default_line_re 176 else: # no match yet 177 continue 178 mo = line_re.match(line) 179 if mo: 180 msgtype = mo.group(self._re_groupname) 181 assert msgtype in self.MESSAGES 182 summaries[msgtype].append(line) 183 counts[msgtype] += 1 184 185 self.descriptionDone = self.descriptionDone[:] 186 for msg, fullmsg in self.MESSAGES.items(): 187 if counts[msg]: 188 self.descriptionDone.append("%s=%d" % (fullmsg, counts[msg])) 189 self.addCompleteLog(fullmsg, "".join(summaries[msg])) 190 self.setProperty("pylint-%s" % fullmsg, counts[msg]) 191 self.setProperty("pylint-total", sum(counts.values()))
192
193 - def evaluateCommand(self, cmd):
194 if cmd.rc != 0: 195 return FAILURE 196 for msg in self.flunkingIssues: 197 if self.getProperty("pylint-%s" % self.MESSAGES[msg]): 198 return FAILURE 199 if self.getProperty("pylint-total"): 200 return WARNINGS 201 return SUCCESS
202