|
# This file is part of Buildbot. Buildbot is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # 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 General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # Copyright Buildbot Team Members
""" I represent a collection of output status for a L{buildbot.process.step.BuildStep}.
Statistics contain any information gleaned from a step that is not in the form of a logfile. As an example, steps that run tests might gather statistics about the number of passed, failed, or skipped tests.
@type progress: L{buildbot.status.progress.StepProgress} @cvar progress: tracks ETA for the step @type text: list of strings @cvar text: list of short texts that describe the command and its status @type text2: list of strings @cvar text2: list of short texts added to the overall build description @type logs: dict of string -> L{buildbot.status.logfile.LogFile} @ivar logs: logs of steps @type statistics: dict @ivar statistics: results from running this step """ # note that these are created when the Build is set up, before each # corresponding BuildStep has started.
"""Returns a short string with the name of this step. This string may have spaces in it."""
"""Returns a list of tuples (name, current, target).""" ret = [] metrics = self.progress.progress.keys() metrics.sort() for m in metrics: t = (m, self.progress.progress[m], self.progress.expectations[m]) ret.append(t) return ret
return self.skipped
return self.hidden
d = defer.succeed(self) else:
# while the step is running, the following methods make sense. # Afterwards they return None
return None # already finished return self.progress.remaining()
# Once you know the step has finished, the following methods are legal. # Before this step has finished, they all return None.
"""Returns a list of strings which describe the step. These are intended to be displayed in a narrow column. If more space is available, the caller should join them together with spaces before presenting them to the user."""
"""Return a tuple describing the results of the step. 'result' is one of the constants in L{buildbot.status.builder}: SUCCESS, WARNINGS, FAILURE, or SKIPPED. 'strings' is an optional list of strings that the step wants to append to the overall build's results. These strings are usually more terse than the ones returned by getText(): in particular, successful Steps do not usually contribute any text to the overall build.
@rtype: tuple of int, list of strings @returns: (result, strings) """
"""Return true if this step has a value for the given statistic. """ return self.statistics.has_key(name)
"""Return the given statistic, if present """ return self.statistics.get(name, default)
# subscription interface
# will get logStarted, logFinished, stepETAUpdate assert receiver not in self.watchers self.watchers.append(receiver) self.sendETAUpdate(receiver, updateInterval)
self.updates[receiver] = None # they might unsubscribe during stepETAUpdate receiver.stepETAUpdate(self.build, self, self.getETA(), self.getExpectations()) if receiver in self.watchers: self.updates[receiver] = reactor.callLater(updateInterval, self.sendETAUpdate, receiver, updateInterval)
if receiver in self.watchers: self.watchers.remove(receiver) if receiver in self.updates: if self.updates[receiver] is not None: self.updates[receiver].cancel() del self.updates[receiver]
# methods to be invoked by the BuildStep
log.msg("BuildStepStatus.setColor is no longer supported -- ignoring color %s" % (color,))
self.progress = stepprogress
self.hidden = hidden
receiver = w.logStarted(self.build, self, log) if receiver: log.subscribe(receiver, True) d = log.waitUntilFinished() d.addCallback(lambda log: log.unsubscribe(receiver))
assert self.started # addLog before stepStarted won't notify watchers logfilename = self.build.generateLogfileName(self.name, name) log = HTMLLogFile(self, name, logfilename, html) self.logs.append(log) for w in self.watchers: w.logStarted(self.build, self, log) w.logFinished(self.build, self, log)
for w in self.watchers: w.logFinished(self.build, self, log)
self.urls[name] = url
self.text = text for w in self.watchers: w.stepTextChanged(self.build, self, text) self.text2 = text for w in self.watchers: w.stepText2Changed(self.build, self, text)
"""Set the given statistic. Usually called by subclasses. """ self.statistics[name] = value
self.skipped = skipped
self.finished = util.now() self.results = results cld = [] # deferreds for log compression logCompressionLimit = self.master.config.logCompressionLimit for loog in self.logs: if not loog.isFinished(): loog.finish() # if log compression is on, and it's a real LogFile, # HTMLLogFiles aren't files if logCompressionLimit is not False and \ isinstance(loog, LogFile): if os.path.getsize(loog.getFilename()) > logCompressionLimit: loog_deferred = loog.compressLog() if loog_deferred: cld.append(loog_deferred)
for r in self.updates.keys(): if self.updates[r] is not None: self.updates[r].cancel() del self.updates[r]
watchers = self.finishedWatchers self.finishedWatchers = [] for w in watchers: w.callback(self) if cld: return defer.DeferredList(cld)
# filter out logs that have been deleted self.logs = [ l for l in self.logs if l.hasContents() ]
return self.waitingForLocks
self.waitingForLocks = waiting
# persistence
d = styles.Versioned.__getstate__(self) del d['build'] # filled in when loading if d.has_key('progress'): del d['progress'] del d['watchers'] del d['finishedWatchers'] del d['updates'] del d['master'] return d
# self.build must be filled in by our parent
# point the logs to this object
self.build = build self.master = master for loog in self.logs: loog.step = self loog.master = master
if not hasattr(self, "urls"): self.urls = {} self.wasUpgraded = True
if not hasattr(self, "statistics"): self.statistics = {} self.wasUpgraded = True
self.step_number = 0
self.hidden = False
# Constant
# Transient self.build.builder.status.getURLForThing(l)] for l in self.getLogs()]
|