Trees | Indices | Help |
|
---|
|
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 os 17 from zope.interface import implements 18 from twisted.persisted import styles 19 from twisted.python import log 20 from twisted.internet import reactor, defer 21 from buildbot import interfaces, util 22 from buildbot.status.logfile import LogFile, HTMLLogFile 2325 """ 26 I represent a collection of output status for a 27 L{buildbot.process.step.BuildStep}. 28 29 Statistics contain any information gleaned from a step that is 30 not in the form of a logfile. As an example, steps that run 31 tests might gather statistics about the number of passed, failed, 32 or skipped tests. 33 34 @type progress: L{buildbot.status.progress.StepProgress} 35 @cvar progress: tracks ETA for the step 36 @type text: list of strings 37 @cvar text: list of short texts that describe the command and its status 38 @type text2: list of strings 39 @cvar text2: list of short texts added to the overall build description 40 @type logs: dict of string -> L{buildbot.status.logfile.LogFile} 41 @ivar logs: logs of steps 42 @type statistics: dict 43 @ivar statistics: results from running this step 44 """ 45 # note that these are created when the Build is set up, before each 46 # corresponding BuildStep has started. 47 implements(interfaces.IBuildStepStatus, interfaces.IStatusEvent) 48 49 persistenceVersion = 4 50 persistenceForgets = ( 'wasUpgraded', ) 51 52 started = None 53 finished = None 54 progress = None 55 text = [] 56 results = None 57 text2 = [] 58 watchers = [] 59 updates = {} 60 finishedWatchers = [] 61 statistics = {} 62 step_number = None 63 hidden = False 6438266 assert interfaces.IBuildStatus(parent) 67 self.build = parent 68 self.step_number = step_number 69 self.hidden = False 70 self.logs = [] 71 self.urls = {} 72 self.watchers = [] 73 self.updates = {} 74 self.finishedWatchers = [] 75 self.statistics = {} 76 self.skipped = False 77 78 self.master = master 79 80 self.waitingForLocks = False8183 """Returns a short string with the name of this step. This string 84 may have spaces in it.""" 85 return self.name8688 return self.build89 9294 """Returns a list of tuples (name, current, target).""" 95 if not self.progress: 96 return [] 97 ret = [] 98 metrics = self.progress.progress.keys() 99 metrics.sort() 100 for m in metrics: 101 t = (m, self.progress.progress[m], self.progress.expectations[m]) 102 ret.append(t) 103 return ret104106 return self.logs107109 return self.urls.copy()110112 return (self.started is not None)113 116118 return (self.finished is not None)119121 return self.hidden122124 if self.finished: 125 d = defer.succeed(self) 126 else: 127 d = defer.Deferred() 128 self.finishedWatchers.append(d) 129 return d130 131 # while the step is running, the following methods make sense. 132 # Afterwards they return None 133135 if self.started is None: 136 return None # not started yet 137 if self.finished is not None: 138 return None # already finished 139 if not self.progress: 140 return None # no way to predict 141 return self.progress.remaining()142 143 # Once you know the step has finished, the following methods are legal. 144 # Before this step has finished, they all return None. 145147 """Returns a list of strings which describe the step. These are 148 intended to be displayed in a narrow column. If more space is 149 available, the caller should join them together with spaces before 150 presenting them to the user.""" 151 return self.text152154 """Return a tuple describing the results of the step. 155 'result' is one of the constants in L{buildbot.status.builder}: 156 SUCCESS, WARNINGS, FAILURE, or SKIPPED. 157 'strings' is an optional list of strings that the step wants to 158 append to the overall build's results. These strings are usually 159 more terse than the ones returned by getText(): in particular, 160 successful Steps do not usually contribute any text to the 161 overall build. 162 163 @rtype: tuple of int, list of strings 164 @returns: (result, strings) 165 """ 166 return (self.results, self.text2)167169 """Return true if this step has a value for the given statistic. 170 """ 171 return self.statistics.has_key(name)172 177 178 # subscription interface 179181 # will get logStarted, logFinished, stepETAUpdate 182 assert receiver not in self.watchers 183 self.watchers.append(receiver) 184 self.sendETAUpdate(receiver, updateInterval)185187 self.updates[receiver] = None 188 # they might unsubscribe during stepETAUpdate 189 receiver.stepETAUpdate(self.build, self, 190 self.getETA(), self.getExpectations()) 191 if receiver in self.watchers: 192 self.updates[receiver] = reactor.callLater(updateInterval, 193 self.sendETAUpdate, 194 receiver, 195 updateInterval)196198 if receiver in self.watchers: 199 self.watchers.remove(receiver) 200 if receiver in self.updates: 201 if self.updates[receiver] is not None: 202 self.updates[receiver].cancel() 203 del self.updates[receiver]204 205 206 # methods to be invoked by the BuildStep 207209 self.name = stepname210212 log.msg("BuildStepStatus.setColor is no longer supported -- ignoring color %s" % (color,))213215 self.progress = stepprogress216 219 224226 assert self.started # addLog before stepStarted won't notify watchers 227 logfilename = self.build.generateLogfileName(self.name, name) 228 log = LogFile(self, name, logfilename) 229 self.logs.append(log) 230 for w in self.watchers: 231 receiver = w.logStarted(self.build, self, log) 232 if receiver: 233 log.subscribe(receiver, True) 234 d = log.waitUntilFinished() 235 d.addCallback(lambda log: log.unsubscribe(receiver)) 236 d = log.waitUntilFinished() 237 d.addCallback(self.logFinished) 238 return log239241 assert self.started # addLog before stepStarted won't notify watchers 242 logfilename = self.build.generateLogfileName(self.name, name) 243 log = HTMLLogFile(self, name, logfilename, html) 244 self.logs.append(log) 245 for w in self.watchers: 246 w.logStarted(self.build, self, log) 247 w.logFinished(self.build, self, log)248 252254 self.urls[name] = url255 264266 """Set the given statistic. Usually called by subclasses. 267 """ 268 self.statistics[name] = value269 272274 self.finished = util.now() 275 self.results = results 276 cld = [] # deferreds for log compression 277 logCompressionLimit = self.master.config.logCompressionLimit 278 for loog in self.logs: 279 if not loog.isFinished(): 280 loog.finish() 281 # if log compression is on, and it's a real LogFile, 282 # HTMLLogFiles aren't files 283 if logCompressionLimit is not False and \ 284 isinstance(loog, LogFile): 285 if os.path.getsize(loog.getFilename()) > logCompressionLimit: 286 loog_deferred = loog.compressLog() 287 if loog_deferred: 288 cld.append(loog_deferred) 289 290 for r in self.updates.keys(): 291 if self.updates[r] is not None: 292 self.updates[r].cancel() 293 del self.updates[r] 294 295 watchers = self.finishedWatchers 296 self.finishedWatchers = [] 297 for w in watchers: 298 w.callback(self) 299 if cld: 300 return defer.DeferredList(cld)301303 # filter out logs that have been deleted 304 self.logs = [ l for l in self.logs if l.hasContents() ]305 308 311 312 # persistence 313315 d = styles.Versioned.__getstate__(self) 316 del d['build'] # filled in when loading 317 if d.has_key('progress'): 318 del d['progress'] 319 del d['watchers'] 320 del d['finishedWatchers'] 321 del d['updates'] 322 del d['master'] 323 return d324326 styles.Versioned.__setstate__(self, d) 327 # self.build must be filled in by our parent 328 329 # point the logs to this object 330 self.watchers = [] 331 self.finishedWatchers = [] 332 self.updates = {}333335 self.build = build 336 self.master = master 337 for loog in self.logs: 338 loog.step = self 339 loog.master = master340 345 350 355 360362 result = {} 363 # Constant 364 result['name'] = self.getName() 365 366 # Transient 367 result['text'] = self.getText() 368 result['results'] = self.getResults() 369 result['isStarted'] = self.isStarted() 370 result['isFinished'] = self.isFinished() 371 result['statistics'] = self.statistics 372 result['times'] = self.getTimes() 373 result['expectations'] = self.getExpectations() 374 result['eta'] = self.getETA() 375 result['urls'] = self.getURLs() 376 result['step_number'] = self.step_number 377 result['hidden'] = self.hidden 378 result['logs'] = [[l.getName(), 379 self.build.builder.status.getURLForThing(l)] 380 for l in self.getLogs()] 381 return result
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Sun Mar 25 19:40:45 2012 | http://epydoc.sourceforge.net |