-
Notifications
You must be signed in to change notification settings - Fork 3
/
step_iface.py
232 lines (192 loc) · 8.1 KB
/
step_iface.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2011 P. Christeas <xrg@hellug.gr>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from buildbot.process.buildstep import LoggingBuildStep, LoggedRemoteCommand
from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS #, EXCEPTION, SKIPPED
from buildbot.status.builder import TestResult
from openerp_libclient.tools import ustr
import re
from twisted.python import log as twisted_log
""" BuildStep interface classes
"""
try:
import cStringIO
StringIO = cStringIO.StringIO
except ImportError:
from StringIO import StringIO
class StepOE:
"""Mix-in class for BuildbotOE-aware Steps
By mixing this class in a Buildstep, master-keeper will know that it
needs to supply the `keeper_conf` dict automatically to the keyword
arguments of the step.
TODO doc for keeper_conf
"""
def __init__(self, **kwargs):
assert 'keeper_conf' in kwargs
if kwargs.get('workdir',False):
self.workdir = kwargs['workdir']
elif kwargs.get('keeper_conf'):
self.workdir = None
components = kwargs['keeper_conf']['builder'].get('components',{})
for comp in components.values():
if comp['is_rolling']:
if comp.get('dest_path'):
self.workdir = comp['dest_path']
break
else:
if len(components) > 1:
# we have to override the default 'build' one
self.workdir = '.'
else:
if not hasattr(self, 'workdir'):
self.workdir = None
def setDefaultWorkdir(self, workdir):
if not self.workdir:
self.workdir = workdir
class StdErrRemoteCommand(LoggedRemoteCommand):
"""Variation of LoggedRemoteCommand that separates stderr
"""
def addStderr(self, data):
self.logs['stderr'].addStderr(data)
class LoggedOEmixin(StepOE):
"""mix-in that handles regex-parsed logs (w. component parts)
known_strs is a list of 2-3 item tuples of the form:
(regex_str, severity, field_dict)
"""
known_strs = [] #: please define them in subclasses!
_test_name = None
def __init__(self, **kwargs):
assert isinstance(self, LoggingBuildStep)
StepOE.__init__(self, **kwargs)
self.part_subs = kwargs.get('part_subs')
if kwargs.get('keeper_conf'):
if not self.part_subs:
self.part_subs = kwargs['keeper_conf']['builder'].get('component_parts',[])
#note: we are NOT keeping the keeper_conf, because we don't want to keep
# its memory referenced
self.addFactoryArguments(part_subs=self.part_subs)
self.build_result = SUCCESS
self.last_msgs = [self.name]
self.known_res = []
for kns in self.known_strs:
rec = re.compile(kns[0])
sev = kns[1]
if len(kns) > 2:
fdict = kns[2]
else:
fdict = {}
self.known_res.append((rec, sev, fdict))
def createSummary(self, log):
""" Try to read the file-lint.sh output and parse results
"""
severity = SUCCESS
repo_reges = []
for comp, rege_str, subst in self.part_subs:
repo_reges.append((re.compile(rege_str), subst))
t_results= {}
last_msgs = []
last_module = None
clean_name = self.name.lower().replace(' ', '_')
test_name = 'rest'
for line in StringIO(log.getText()).readlines():
for rem, sev, fdict in self.known_res:
m = rem.match(line)
if not m:
continue
mgd = m.groupdict()
fname = mgd.get('fname',fdict.get('fname',''))
msg = ustr(mgd.get('msg',False) \
or fdict.get('msg', False) \
or line.strip())
module = None
if 'module' in mgd:
module = m.group('module')
else:
for rege, subst in repo_reges:
mf = rege.match(fname)
if mf:
module = mf.expand(subst)
break
else:
if fname and fdict.get('module_from_fname', False):
# Try to get the cleanest part of the filename, as module name
module = fname.split('.',1)[0].replace('/','_').replace(' ','_').strip()
if not module:
module = fdict.get('module', last_module or clean_name)
else:
if fdict.get('module_persist', False):
last_module = module
else:
last_module = None
# test name, detail after the module
if 'test_name' in mgd:
test_name = mgd['test_name']
elif 'test_name' in fdict:
test_name = fdict['test_name']
module = (module, test_name)
if module not in t_results:
t_results[module] = TestResult(name=module,
results=SUCCESS,
text='', logs={'stdout': u''})
if t_results[module].results < sev:
t_results[module].results = sev
if sev > severity:
severity = sev
last_msgs = [msg,] # and discard lower msgs
elif sev == severity:
last_msgs.append(msg)
if fdict.get('call'):
try:
fn = fdict['call']
fn(self, line, module, mgd, fdict)
except Exception:
twisted_log.err(None, "failed to call %r" % fdict['call'])
pass
if fdict.get('short', False):
tline = msg
else:
if line.endswith('\r\n'):
line = line[:-2] + '\n'
tline = ustr(line)
if not tline.endswith('\n'):
tline += '\n'
if sev > SUCCESS:
t_results[module].text += ustr(tline)
if fdict.get('stdout', True):
t_results[module].logs['stdout'] += ustr(line)
break # don't attempt more matching of the same line
# use t_results
for tr in t_results.values():
if self.build_result < tr.results:
self.build_result = tr.results
# and, after it's clean..
self.build.build_status.addTestResult(tr)
self.build_result = severity
if last_msgs:
self.last_msgs = [self.name,] + last_msgs
self.build.builder.db.builds.saveTResults(self.build, self.name,
self.build_result, t_results.values())
def getText2(self, cmd, results):
return self.last_msgs
# Pools for openerp step. They are defined here, because this module
# won't reload upon reconfiguration
ports_pool = None
dbnames_pool = None
#eof