diff options
Diffstat (limited to 'lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/build.py')
-rw-r--r-- | lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/build.py | 567 |
1 files changed, 0 insertions, 567 deletions
diff --git a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/build.py b/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/build.py deleted file mode 100644 index e30d685c..00000000 --- a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/build.py +++ /dev/null @@ -1,567 +0,0 @@ -# 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 - - -import types - -from zope.interface import implements -from twisted.python import log, components -from twisted.python.failure import Failure -from twisted.internet import defer, error - -from buildbot import interfaces -from buildbot.status.results import SUCCESS, WARNINGS, FAILURE, EXCEPTION, \ - RETRY, SKIPPED, worst_status -from buildbot.status.builder import Results -from buildbot.status.progress import BuildProgress -from buildbot.process import metrics, properties -from buildbot.util.eventual import eventually - - -class Build(properties.PropertiesMixin): - """I represent a single build by a single slave. Specialized Builders can - use subclasses of Build to hold status information unique to those build - processes. - - I control B{how} the build proceeds. The actual build is broken up into a - series of steps, saved in the .buildSteps[] array as a list of - L{buildbot.process.step.BuildStep} objects. Each step is a single remote - command, possibly a shell command. - - During the build, I put status information into my C{BuildStatus} - gatherer. - - After the build, I go away. - - I can be used by a factory by setting buildClass on - L{buildbot.process.factory.BuildFactory} - - @ivar requests: the list of L{BuildRequest}s that triggered me - @ivar build_status: the L{buildbot.status.build.BuildStatus} that - collects our status - """ - - implements(interfaces.IBuildControl) - - workdir = "build" - build_status = None - reason = "changes" - finished = False - results = None - stopped = False - set_runtime_properties = True - - def __init__(self, requests): - self.requests = requests - self.locks = [] - # build a source stamp - self.sources = requests[0].mergeSourceStampsWith(requests[1:]) - self.reason = requests[0].mergeReasons(requests[1:]) - - self.progress = None - self.currentStep = None - self.slaveEnvironment = {} - - self.terminate = False - - self._acquiringLock = None - - def setBuilder(self, builder): - """ - Set the given builder as our builder. - - @type builder: L{buildbot.process.builder.Builder} - """ - self.builder = builder - - def setLocks(self, lockList): - # convert all locks into their real forms - self.locks = [(self.builder.botmaster.getLockFromLockAccess(access), access) - for access in lockList ] - - def setSlaveEnvironment(self, env): - self.slaveEnvironment = env - - def getSourceStamp(self, codebase=''): - for source in self.sources: - if source.codebase == codebase: - return source - return None - - def getAllSourceStamps(self): - return list(self.sources) - - def allChanges(self): - for s in self.sources: - for c in s.changes: - yield c - - def allFiles(self): - # return a list of all source files that were changed - files = [] - for c in self.allChanges(): - for f in c.files: - files.append(f) - return files - - def __repr__(self): - return "<Build %s>" % (self.builder.name,) - - def blamelist(self): - blamelist = [] - for c in self.allChanges(): - if c.who not in blamelist: - blamelist.append(c.who) - for source in self.sources: - if source.patch_info: #Add patch author to blamelist - blamelist.append(source.patch_info[0]) - blamelist.sort() - return blamelist - - def changesText(self): - changetext = "" - for c in self.allChanges(): - changetext += "-" * 60 + "\n\n" + c.asText() + "\n" - # consider sorting these by number - return changetext - - def setStepFactories(self, step_factories): - """Set a list of 'step factories', which are tuples of (class, - kwargs), where 'class' is generally a subclass of step.BuildStep . - These are used to create the Steps themselves when the Build starts - (as opposed to when it is first created). By creating the steps - later, their __init__ method will have access to things like - build.allFiles() .""" - self.stepFactories = list(step_factories) - - useProgress = True - - def getSlaveCommandVersion(self, command, oldversion=None): - return self.slavebuilder.getSlaveCommandVersion(command, oldversion) - def getSlaveName(self): - return self.slavebuilder.slave.slavename - - def setupProperties(self): - props = interfaces.IProperties(self) - - # give the properties a reference back to this build - props.build = self - - # start with global properties from the configuration - master = self.builder.botmaster.master - props.updateFromProperties(master.config.properties) - - # from the SourceStamps, which have properties via Change - for change in self.allChanges(): - props.updateFromProperties(change.properties) - - # and finally, get any properties from requests (this is the path - # through which schedulers will send us properties) - for rq in self.requests: - props.updateFromProperties(rq.properties) - - # now set some properties of our own, corresponding to the - # build itself - props.setProperty("buildnumber", self.build_status.number, "Build") - - if self.sources and len(self.sources) == 1: - # old interface for backwards compatibility - source = self.sources[0] - props.setProperty("branch", source.branch, "Build") - props.setProperty("revision", source.revision, "Build") - props.setProperty("repository", source.repository, "Build") - props.setProperty("codebase", source.codebase, "Build") - props.setProperty("project", source.project, "Build") - - self.builder.setupProperties(props) - - def setupSlaveBuilder(self, slavebuilder): - self.slavebuilder = slavebuilder - - self.path_module = slavebuilder.slave.path_module - - # navigate our way back to the L{buildbot.buildslave.BuildSlave} - # object that came from the config, and get its properties - buildslave_properties = slavebuilder.slave.properties - self.getProperties().updateFromProperties(buildslave_properties) - if slavebuilder.slave.slave_basedir: - builddir = self.path_module.join( - slavebuilder.slave.slave_basedir, - self.builder.config.slavebuilddir) - self.setProperty("builddir", builddir, "slave") - self.setProperty("workdir", builddir, "slave (deprecated)") - - self.slavename = slavebuilder.slave.slavename - self.build_status.setSlavename(self.slavename) - - def startBuild(self, build_status, expectations, slavebuilder): - """This method sets up the build, then starts it by invoking the - first Step. It returns a Deferred which will fire when the build - finishes. This Deferred is guaranteed to never errback.""" - - # we are taking responsibility for watching the connection to the - # remote. This responsibility was held by the Builder until our - # startBuild was called, and will not return to them until we fire - # the Deferred returned by this method. - - log.msg("%s.startBuild" % self) - self.build_status = build_status - # now that we have a build_status, we can set properties - self.setupProperties() - self.setupSlaveBuilder(slavebuilder) - slavebuilder.slave.updateSlaveStatus(buildStarted=build_status) - - # then narrow SlaveLocks down to the right slave - self.locks = [(l.getLock(self.slavebuilder.slave), a) - for l, a in self.locks ] - self.remote = slavebuilder.remote - self.remote.notifyOnDisconnect(self.lostRemote) - - metrics.MetricCountEvent.log('active_builds', 1) - - d = self.deferred = defer.Deferred() - def _uncount_build(res): - metrics.MetricCountEvent.log('active_builds', -1) - return res - d.addBoth(_uncount_build) - - def _release_slave(res, slave, bs): - self.slavebuilder.buildFinished() - slave.updateSlaveStatus(buildFinished=bs) - return res - d.addCallback(_release_slave, self.slavebuilder.slave, build_status) - - try: - self.setupBuild(expectations) # create .steps - except: - # the build hasn't started yet, so log the exception as a point - # event instead of flunking the build. - # TODO: associate this failure with the build instead. - # this involves doing - # self.build_status.buildStarted() from within the exception - # handler - log.msg("Build.setupBuild failed") - log.err(Failure()) - self.builder.builder_status.addPointEvent(["setupBuild", - "exception"]) - self.finished = True - self.results = EXCEPTION - self.deferred = None - d.callback(self) - return d - - self.build_status.buildStarted(self) - self.acquireLocks().addCallback(self._startBuild_2) - return d - - @staticmethod - def canStartWithSlavebuilder(lockList, slavebuilder): - for lock, access in lockList: - slave_lock = lock.getLock(slavebuilder.slave) - if not slave_lock.isAvailable(None, access): - return False - return True - - def acquireLocks(self, res=None): - self._acquiringLock = None - if not self.locks: - return defer.succeed(None) - if self.stopped: - return defer.succeed(None) - log.msg("acquireLocks(build %s, locks %s)" % (self, self.locks)) - for lock, access in self.locks: - if not lock.isAvailable(self, access): - log.msg("Build %s waiting for lock %s" % (self, lock)) - d = lock.waitUntilMaybeAvailable(self, access) - d.addCallback(self.acquireLocks) - self._acquiringLock = (lock, access, d) - return d - # all locks are available, claim them all - for lock, access in self.locks: - lock.claim(self, access) - return defer.succeed(None) - - def _startBuild_2(self, res): - self.startNextStep() - - def setupBuild(self, expectations): - # create the actual BuildSteps. If there are any name collisions, we - # add a count to the loser until it is unique. - self.steps = [] - self.stepStatuses = {} - stepnames = {} - sps = [] - - for factory in self.stepFactories: - step = factory.buildStep() - step.setBuild(self) - step.setBuildSlave(self.slavebuilder.slave) - if callable (self.workdir): - step.setDefaultWorkdir (self.workdir (self.sources)) - else: - step.setDefaultWorkdir (self.workdir) - name = step.name - if stepnames.has_key(name): - count = stepnames[name] - count += 1 - stepnames[name] = count - name = step.name + "_%d" % count - else: - stepnames[name] = 0 - step.name = name - self.steps.append(step) - - # tell the BuildStatus about the step. This will create a - # BuildStepStatus and bind it to the Step. - step_status = self.build_status.addStepWithName(name) - step.setStepStatus(step_status) - - sp = None - if self.useProgress: - # XXX: maybe bail if step.progressMetrics is empty? or skip - # progress for that one step (i.e. "it is fast"), or have a - # separate "variable" flag that makes us bail on progress - # tracking - sp = step.setupProgress() - if sp: - sps.append(sp) - - # Create a buildbot.status.progress.BuildProgress object. This is - # called once at startup to figure out how to build the long-term - # Expectations object, and again at the start of each build to get a - # fresh BuildProgress object to track progress for that individual - # build. TODO: revisit at-startup call - - if self.useProgress: - self.progress = BuildProgress(sps) - if self.progress and expectations: - self.progress.setExpectationsFrom(expectations) - - # we are now ready to set up our BuildStatus. - # pass all sourcestamps to the buildstatus - self.build_status.setSourceStamps(self.sources) - self.build_status.setReason(self.reason) - self.build_status.setBlamelist(self.blamelist()) - self.build_status.setProgress(self.progress) - - # gather owners from build requests - owners = [r.properties['owner'] for r in self.requests - if r.properties.has_key('owner')] - if owners: self.setProperty('owners', owners, self.reason) - - self.results = [] # list of FAILURE, SUCCESS, WARNINGS, SKIPPED - self.result = SUCCESS # overall result, may downgrade after each step - self.text = [] # list of text string lists (text2) - - def getNextStep(self): - """This method is called to obtain the next BuildStep for this build. - When it returns None (or raises a StopIteration exception), the build - is complete.""" - if not self.steps: - return None - if not self.remote: - return None - if self.terminate or self.stopped: - # Run any remaining alwaysRun steps, and skip over the others - while True: - s = self.steps.pop(0) - if s.alwaysRun: - return s - if not self.steps: - return None - else: - return self.steps.pop(0) - - def startNextStep(self): - try: - s = self.getNextStep() - except StopIteration: - s = None - if not s: - return self.allStepsDone() - self.currentStep = s - d = defer.maybeDeferred(s.startStep, self.remote) - d.addCallback(self._stepDone, s) - d.addErrback(self.buildException) - - def _stepDone(self, results, step): - self.currentStep = None - if self.finished: - return # build was interrupted, don't keep building - terminate = self.stepDone(results, step) # interpret/merge results - if terminate: - self.terminate = True - return self.startNextStep() - - def stepDone(self, result, step): - """This method is called when the BuildStep completes. It is passed a - status object from the BuildStep and is responsible for merging the - Step's results into those of the overall Build.""" - - terminate = False - text = None - if type(result) == types.TupleType: - result, text = result - assert type(result) == type(SUCCESS) - log.msg(" step '%s' complete: %s" % (step.name, Results[result])) - self.results.append(result) - if text: - self.text.extend(text) - if not self.remote: - terminate = True - - possible_overall_result = result - if result == FAILURE: - if not step.flunkOnFailure: - possible_overall_result = SUCCESS - if step.warnOnFailure: - possible_overall_result = WARNINGS - if step.flunkOnFailure: - possible_overall_result = FAILURE - if step.haltOnFailure: - terminate = True - elif result == WARNINGS: - if not step.warnOnWarnings: - possible_overall_result = SUCCESS - else: - possible_overall_result = WARNINGS - if step.flunkOnWarnings: - possible_overall_result = FAILURE - elif result in (EXCEPTION, RETRY): - terminate = True - - # if we skipped this step, then don't adjust the build status - if result != SKIPPED: - self.result = worst_status(self.result, possible_overall_result) - - return terminate - - def lostRemote(self, remote=None): - # the slave went away. There are several possible reasons for this, - # and they aren't necessarily fatal. For now, kill the build, but - # TODO: see if we can resume the build when it reconnects. - log.msg("%s.lostRemote" % self) - self.remote = None - if self.currentStep: - # this should cause the step to finish. - log.msg(" stopping currentStep", self.currentStep) - self.currentStep.interrupt(Failure(error.ConnectionLost())) - else: - self.result = RETRY - self.text = ["lost", "remote"] - self.stopped = True - if self._acquiringLock: - lock, access, d = self._acquiringLock - lock.stopWaitingUntilAvailable(self, access, d) - d.callback(None) - - def stopBuild(self, reason="<no reason given>"): - # the idea here is to let the user cancel a build because, e.g., - # they realized they committed a bug and they don't want to waste - # the time building something that they know will fail. Another - # reason might be to abandon a stuck build. We want to mark the - # build as failed quickly rather than waiting for the slave's - # timeout to kill it on its own. - - log.msg(" %s: stopping build: %s" % (self, reason)) - if self.finished: - return - # TODO: include 'reason' in this point event - self.builder.builder_status.addPointEvent(['interrupt']) - self.stopped = True - if self.currentStep: - self.currentStep.interrupt(reason) - - self.result = EXCEPTION - - if self._acquiringLock: - lock, access, d = self._acquiringLock - lock.stopWaitingUntilAvailable(self, access, d) - d.callback(None) - - def allStepsDone(self): - if self.result == FAILURE: - text = ["failed"] - elif self.result == WARNINGS: - text = ["warnings"] - elif self.result == EXCEPTION: - text = ["exception"] - elif self.result == RETRY: - text = ["retry"] - else: - text = ["build", "successful"] - text.extend(self.text) - return self.buildFinished(text, self.result) - - def buildException(self, why): - log.msg("%s.buildException" % self) - log.err(why) - # try to finish the build, but since we've already faced an exception, - # this may not work well. - try: - self.buildFinished(["build", "exception"], EXCEPTION) - except: - log.err(Failure(), 'while finishing a build with an exception') - - def buildFinished(self, text, results): - """This method must be called when the last Step has completed. It - marks the Build as complete and returns the Builder to the 'idle' - state. - - It takes two arguments which describe the overall build status: - text, results. 'results' is one of SUCCESS, WARNINGS, or FAILURE. - - If 'results' is SUCCESS or WARNINGS, we will permit any dependant - builds to start. If it is 'FAILURE', those builds will be - abandoned.""" - - self.finished = True - if self.remote: - self.remote.dontNotifyOnDisconnect(self.lostRemote) - self.remote = None - self.results = results - - log.msg(" %s: build finished" % self) - self.build_status.setText(text) - self.build_status.setResults(results) - self.build_status.buildFinished() - if self.progress and results == SUCCESS: - # XXX: also test a 'timing consistent' flag? - log.msg(" setting expectations for next time") - self.builder.setExpectations(self.progress) - eventually(self.releaseLocks) - self.deferred.callback(self) - self.deferred = None - - def releaseLocks(self): - if self.locks: - log.msg("releaseLocks(%s): %s" % (self, self.locks)) - for lock, access in self.locks: - if lock.isOwner(self, access): - lock.release(self, access) - else: - # This should only happen if we've been interrupted - assert self.stopped - - # IBuildControl - - def getStatus(self): - return self.build_status - - # stopBuild is defined earlier - -components.registerAdapter( - lambda build : interfaces.IProperties(build.build_status), - Build, interfaces.IProperties) |