2 from buildbot
.status
.builder
import SUCCESS
, FAILURE
, WARNINGS
3 from buildbot
.steps
.shell
import ShellCommand
8 StringIO
= cStringIO
.StringIO
10 from StringIO
import StringIO
13 class BuildEPYDoc(ShellCommand
):
15 command
= ["make", "epydocs"]
16 description
= ["building", "epydocs"]
17 descriptionDone
= ["epydoc"]
19 def createSummary(self
, log
):
24 for line
in StringIO(log
.getText()):
25 if line
.startswith("Error importing "):
27 if line
.find("Warning: ") != -1:
29 if line
.find("Error: ") != -1:
32 self
.descriptionDone
= self
.descriptionDone
[:]
34 self
.descriptionDone
.append("ierr=%d" % import_errors
)
36 self
.descriptionDone
.append("warn=%d" % warnings
)
38 self
.descriptionDone
.append("err=%d" % errors
)
40 self
.import_errors
= import_errors
41 self
.warnings
= warnings
44 def evaluateCommand(self
, cmd
):
47 if self
.warnings
or self
.errors
:
52 class PyFlakes(ShellCommand
):
54 command
= ["make", "pyflakes"]
55 description
= ["running", "pyflakes"]
56 descriptionDone
= ["pyflakes"]
57 flunkOnFailure
= False
58 flunkingIssues
= ["undefined"] # any pyflakes lines like this cause FAILURE
60 MESSAGES
= ("unused", "undefined", "redefs", "import*", "misc")
62 def createSummary(self
, log
):
65 for m
in self
.MESSAGES
:
70 for line
in StringIO(log
.getText()).readlines():
71 # the first few lines might contain echoed commands from a 'make
72 # pyflakes' step, so don't count these as warnings. Stop ignoring
73 # the initial lines as soon as we see one with a colon.
75 if line
.find(":") != -1:
76 # there's the colon, this is the first real line
78 # fall through and parse the line
80 # skip this line, keep skipping non-colon lines
82 if line
.find("imported but unused") != -1:
84 elif line
.find("*' used; unable to detect undefined names") != -1:
86 elif line
.find("undefined name") != -1:
88 elif line
.find("redefinition of unused") != -1:
92 summaries
[m
].append(line
)
95 self
.descriptionDone
= self
.descriptionDone
[:]
96 for m
in self
.MESSAGES
:
98 self
.descriptionDone
.append("%s=%d" % (m
, counts
[m
]))
99 self
.addCompleteLog(m
, "".join(summaries
[m
]))
100 self
.setProperty("pyflakes-%s" % m
, counts
[m
], "pyflakes")
101 self
.setProperty("pyflakes-total", sum(counts
.values()), "pyflakes")
104 def evaluateCommand(self
, cmd
):
107 for m
in self
.flunkingIssues
:
108 if self
.getProperty("pyflakes-%s" % m
):
110 if self
.getProperty("pyflakes-total"):
114 class PyLint(ShellCommand
):
115 '''A command that knows about pylint output.
116 It's a good idea to add --output-format=parseable to your
117 command, since it includes the filename in the message.
120 description
= ["running", "pylint"]
121 descriptionDone
= ["pylint"]
123 # Using the default text output, the message format is :
124 # MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE
125 # with --output-format=parseable it is: (the outer brackets are literal)
126 # FILE_NAME:LINE_NUM: [MESSAGE_TYPE[, OBJECT]] MESSAGE
127 # message type consists of the type char and 4 digits
131 'C': "convention", # for programming standard violation
132 'R': "refactor", # for bad code smell
133 'W': "warning", # for python specific problems
134 'E': "error", # for much probably bugs in the code
135 'F': "fatal", # error prevented pylint from further processing.
139 flunkingIssues
= ["F", "E"] # msg categories that cause FAILURE
141 _re_groupname
= 'errtype'
142 _msgtypes_re_str
= '(?P<%s>[%s])' % (_re_groupname
, ''.join(MESSAGES
.keys()))
143 _default_line_re
= re
.compile(r
'%s\d{4}: *\d+:.+' % _msgtypes_re_str
)
144 _parseable_line_re
= re
.compile(r
'[^:]+:\d+: \[%s\d{4}[,\]] .+' % _msgtypes_re_str
)
146 def createSummary(self
, log
):
149 for m
in self
.MESSAGES
:
153 line_re
= None # decide after first match
154 for line
in StringIO(log
.getText()).readlines():
156 # need to test both and then decide on one
157 if self
._parseable
_line
_re
.match(line
):
158 line_re
= self
._parseable
_line
_re
159 elif self
._default
_line
_re
.match(line
):
160 line_re
= self
._default
_line
_re
163 mo
= line_re
.match(line
)
165 msgtype
= mo
.group(self
._re
_groupname
)
166 assert msgtype
in self
.MESSAGES
167 summaries
[msgtype
].append(line
)
170 self
.descriptionDone
= self
.descriptionDone
[:]
171 for msg
, fullmsg
in self
.MESSAGES
.items():
173 self
.descriptionDone
.append("%s=%d" % (fullmsg
, counts
[msg
]))
174 self
.addCompleteLog(fullmsg
, "".join(summaries
[msg
]))
175 self
.setProperty("pylint-%s" % fullmsg
, counts
[msg
])
176 self
.setProperty("pylint-total", sum(counts
.values()))
178 def evaluateCommand(self
, cmd
):
181 for msg
in self
.flunkingIssues
:
182 if self
.getProperty("pylint-%s" % self
.MESSAGES
[msg
]):
184 if self
.getProperty("pylint-total"):