1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 from __future__ import with_statement
17
18 import os, urllib
19 from cPickle import load
20 from twisted.python import log
21 from twisted.persisted import styles
22 from twisted.internet import defer
23 from twisted.application import service
24 from zope.interface import implements
25 from buildbot import config, interfaces, util
26 from buildbot.util import bbcollections
27 from buildbot.util.eventual import eventually
28 from buildbot.changes import changes
29 from buildbot.status import buildset, builder, buildrequest
30
31 -class Status(config.ReconfigurableServiceMixin, service.MultiService):
32 implements(interfaces.IStatus)
33
50
51
52
69
70 @defer.inlineCallbacks
93
95 if self._buildset_completion_sub:
96 self._buildset_completion_sub.unsubscribe()
97 self._buildset_completion_sub = None
98 if self._buildset_sub:
99 self._buildset_sub.unsubscribe()
100 self._buildset_sub = None
101 if self._build_request_sub:
102 self._build_request_sub.unsubscribe()
103 self._build_request_sub = None
104 if self._change_sub:
105 self._change_sub.unsubscribe()
106 self._change_sub = None
107
108 return service.MultiService.stopService(self)
109
110
111
112 @property
115
118
121
122
123
130
132
133
134
135 return self
136
139
141 prefix = self.getBuildbotURL()
142 return prefix + "builders/%s/builds/%d" % (
143 urllib.quote(builder_name, safe=''),
144 build_number)
145
147 prefix = self.getBuildbotURL()
148 if not prefix:
149 return None
150 if interfaces.IStatus.providedBy(thing):
151 return prefix
152 if interfaces.ISchedulerStatus.providedBy(thing):
153 pass
154 if interfaces.IBuilderStatus.providedBy(thing):
155 bldr = thing
156 return prefix + "builders/%s" % (
157 urllib.quote(bldr.getName(), safe=''),
158 )
159 if interfaces.IBuildStatus.providedBy(thing):
160 build = thing
161 bldr = build.getBuilder()
162 return self.getURLForBuild(bldr.getName(), build.getNumber())
163
164 if interfaces.IBuildStepStatus.providedBy(thing):
165 step = thing
166 build = step.getBuild()
167 bldr = build.getBuilder()
168 return prefix + "builders/%s/builds/%d/steps/%s" % (
169 urllib.quote(bldr.getName(), safe=''),
170 build.getNumber(),
171 urllib.quote(step.getName(), safe=''))
172
173
174
175 if interfaces.ISlaveStatus.providedBy(thing):
176 slave = thing
177 return prefix + "buildslaves/%s" % (
178 urllib.quote(slave.getName(), safe=''),
179 )
180
181
182 if interfaces.IStatusEvent.providedBy(thing):
183
184 if isinstance(thing, changes.Change):
185 change = thing
186 return "%schanges/%d" % (prefix, change.number)
187
188 if interfaces.IStatusLog.providedBy(thing):
189 loog = thing
190 step = loog.getStep()
191 build = step.getBuild()
192 bldr = build.getBuilder()
193
194 logs = step.getLogs()
195 for i in range(len(logs)):
196 if loog is logs[i]:
197 break
198 else:
199 return None
200 return prefix + "builders/%s/builds/%d/steps/%s/logs/%s" % (
201 urllib.quote(bldr.getName(), safe=''),
202 build.getNumber(),
203 urllib.quote(step.getName(), safe=''),
204 urllib.quote(loog.getName(), safe=''))
205
207 return list(self.master.change_svc)
208
216 d.addCallback(chdict2change)
217 return d
218
221
233
235 """
236 @rtype: L{BuilderStatus}
237 """
238 return self.botmaster.builders[name].builder_status
239
242
245
251 d.addCallback(make_status_objects)
252 return d
253
254 - def generateFinishedBuilds(self, builders=[], branches=[],
255 num_builds=None, finished_before=None,
256 max_search=200):
257
258 def want_builder(bn):
259 if builders:
260 return bn in builders
261 return True
262 builder_names = [bn
263 for bn in self.getBuilderNames()
264 if want_builder(bn)]
265
266
267
268
269 sources = []
270 for bn in builder_names:
271 b = self.getBuilder(bn)
272 g = b.generateFinishedBuilds(branches,
273 finished_before=finished_before,
274 max_search=max_search)
275 sources.append(g)
276
277
278 next_build = [None] * len(sources)
279
280 def refill():
281 for i,g in enumerate(sources):
282 if next_build[i]:
283
284 continue
285 if not g:
286
287 continue
288 try:
289 next_build[i] = g.next()
290 except StopIteration:
291 next_build[i] = None
292 sources[i] = None
293
294 got = 0
295 while True:
296 refill()
297
298 candidates = [(i, b, b.getTimes()[1])
299 for i,b in enumerate(next_build)
300 if b is not None]
301 candidates.sort(lambda x,y: cmp(x[2], y[2]))
302 if not candidates:
303 return
304
305
306 i, build, finshed_time = candidates[-1]
307 next_build[i] = None
308 got += 1
309 yield build
310 if num_builds is not None:
311 if got >= num_builds:
312 return
313
320
321
322
323
328
329 - def builderAdded(self, name, basedir, category=None, description=None):
330 """
331 @rtype: L{BuilderStatus}
332 """
333 filename = os.path.join(self.basedir, basedir, "builder")
334 log.msg("trying to load status pickle from %s" % filename)
335 builder_status = None
336 try:
337 with open(filename, "rb") as f:
338 builder_status = load(f)
339 builder_status.master = self.master
340
341
342
343
344
345
346 versioneds = styles.versionedsToUpgrade
347 styles.doUpgrade()
348 if True in [ hasattr(o, 'wasUpgraded') for o in versioneds.values() ]:
349 log.msg("re-writing upgraded builder pickle")
350 builder_status.saveYourself()
351
352 except IOError:
353 log.msg("no saved status pickle, creating a new one")
354 except:
355 log.msg("error while loading status pickle, creating a new one")
356 log.msg("error follows:")
357 log.err()
358 if not builder_status:
359 builder_status = builder.BuilderStatus(name, category, self.master,
360 description)
361 builder_status.addPointEvent(["builder", "created"])
362 log.msg("added builder %s in category %s" % (name, category))
363
364
365 builder_status.category = category
366 builder_status.description = description
367 builder_status.master = self.master
368 builder_status.basedir = os.path.join(self.basedir, basedir)
369 builder_status.name = name
370 builder_status.status = self
371
372 if not os.path.isdir(builder_status.basedir):
373 os.makedirs(builder_status.basedir)
374 builder_status.determineNextBuildNumber()
375
376 builder_status.setBigState("offline")
377
378 for t in self.watchers:
379 self.announceNewBuilder(t, name, builder_status)
380
381 return builder_status
382
387
392
397
402
404 result = {}
405
406 result['title'] = self.getTitle()
407 result['titleURL'] = self.getTitleURL()
408 result['buildbotURL'] = self.getBuildbotURL()
409
410
411 return result
412
414 if brid in self._buildreq_observers:
415 for o in self._buildreq_observers[brid]:
416 eventually(o, build_status)
417
419 self._buildreq_observers.add(brid, observer)
420
422 self._buildreq_observers.discard(brid, observer)
423
425 d = defer.Deferred()
426 self._buildset_finished_waiters.add(bsid, d)
427 self._maybeBuildsetFinished(bsid)
428 return d
429
441 d.addCallback(do_notifies)
442 d.addErrback(log.err, 'while notifying for buildset finishes')
443
445
446 self._builder_observers.add(buildername, watcher)
447
449 self._builder_observers.discard(buildername, watcher)
450
459 d.addCallback(do_notifies)
460 d.addErrback(log.err, 'while notifying buildsetSubmitted')
461
463 self._maybeBuildsetFinished(bsid)
464
466 buildername = notif['buildername']
467 if buildername in self._builder_observers:
468 brs = buildrequest.BuildRequestStatus(buildername,
469 notif['brid'], self)
470 for observer in self._builder_observers[buildername]:
471 if hasattr(observer, 'requestSubmitted'):
472 eventually(observer.requestSubmitted, brs)
473