diff options
Diffstat (limited to 'lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/timed.py')
-rw-r--r-- | lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/timed.py | 410 |
1 files changed, 0 insertions, 410 deletions
diff --git a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/timed.py b/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/timed.py deleted file mode 100644 index e735ca93..00000000 --- a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/timed.py +++ /dev/null @@ -1,410 +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 - -from zope.interface import implements - -from buildbot import util -from buildbot.interfaces import ITriggerableScheduler -from buildbot.process import buildstep, properties -from buildbot.schedulers import base -from twisted.internet import defer, reactor -from twisted.python import log -from buildbot import config -from buildbot.changes import filter -# Import croniter if available. -# This is only required for Nightly schedulers, -# so fail gracefully if it isn't present. -try: - from buildbot.util import croniter -except ImportError: - # Pyflakes doesn't like a redefinition here - # Instead, we check if croniter is defined when we need it - pass - -class Timed(base.BaseScheduler): - """ - Parent class for timed schedulers. This takes care of the (surprisingly - subtle) mechanics of ensuring that each timed actuation runs to completion - before the service stops. - """ - - compare_attrs = base.BaseScheduler.compare_attrs - - def __init__(self, name, builderNames, properties={}, **kwargs): - base.BaseScheduler.__init__(self, name, builderNames, properties, - **kwargs) - - # tracking for when to start the next build - self.lastActuated = None - - # A lock to make sure that each actuation occurs without interruption. - # This lock governs actuateAt, actuateAtTimer, and actuateOk - self.actuationLock = defer.DeferredLock() - self.actuateOk = False - self.actuateAt = None - self.actuateAtTimer = None - - self._reactor = reactor # patched by tests - - def startService(self): - base.BaseScheduler.startService(self) - - # no need to lock this; nothing else can run before the service is started - self.actuateOk = True - - # get the scheduler's last_build time (note: only done at startup) - d = self.getState('last_build', None) - def set_last(lastActuated): - self.lastActuated = lastActuated - d.addCallback(set_last) - - # schedule the next build - d.addCallback(lambda _ : self.scheduleNextBuild()) - - # give subclasses a chance to start up - d.addCallback(lambda _ : self.startTimedSchedulerService()) - - # startService does not return a Deferred, so handle errors with a traceback - d.addErrback(log.err, "while initializing %s '%s'" % - (self.__class__.__name__, self.name)) - - def startTimedSchedulerService(self): - """Hook for subclasses to participate in the L{startService} process; - can return a Deferred""" - - def stopService(self): - # shut down any pending actuation, and ensure that we wait for any - # current actuation to complete by acquiring the lock. This ensures - # that no build will be scheduled after stopService is complete. - def stop_actuating(): - self.actuateOk = False - self.actuateAt = None - if self.actuateAtTimer: - self.actuateAtTimer.cancel() - self.actuateAtTimer = None - d = self.actuationLock.run(stop_actuating) - - # and chain to the parent class - d.addCallback(lambda _ : base.BaseScheduler.stopService(self)) - return d - - ## Scheduler methods - - def getPendingBuildTimes(self): - # take the latest-calculated value of actuateAt as a reasonable - # estimate - return [ self.actuateAt ] - - ## Timed methods - - def startBuild(self): - """The time has come to start a new build. Returns a Deferred. - Override in subclasses.""" - raise NotImplementedError - - def getNextBuildTime(self, lastActuation): - """ - Called by to calculate the next time to actuate a BuildSet. Override - in subclasses. To trigger a fresh call to this method, use - L{rescheduleNextBuild}. - - @param lastActuation: the time of the last actuation, or None for never - - @returns: a Deferred firing with the next time a build should occur (in - the future), or None for never. - """ - raise NotImplementedError - - def scheduleNextBuild(self): - """ - Schedule the next build, re-invoking L{getNextBuildTime}. This can be - called at any time, and it will avoid contention with builds being - started concurrently. - - @returns: Deferred - """ - return self.actuationLock.run(self._scheduleNextBuild_locked) - - ## utilities - - def now(self): - "Similar to util.now, but patchable by tests" - return util.now(self._reactor) - - def _scheduleNextBuild_locked(self): - # clear out the existing timer - if self.actuateAtTimer: - self.actuateAtTimer.cancel() - self.actuateAtTimer = None - - # calculate the new time - d = self.getNextBuildTime(self.lastActuated) - - # set up the new timer - def set_timer(actuateAt): - now = self.now() - self.actuateAt = max(actuateAt, now) - if actuateAt is not None: - untilNext = self.actuateAt - now - if untilNext == 0: - log.msg(("%s: missed scheduled build time, so building " - "immediately") % self.name) - self.actuateAtTimer = self._reactor.callLater(untilNext, - self._actuate) - d.addCallback(set_timer) - - return d - - def _actuate(self): - # called from the timer when it's time to start a build - self.actuateAtTimer = None - self.lastActuated = self.actuateAt - - @defer.inlineCallbacks - def set_state_and_start(): - # bail out if we shouldn't be actuating anymore - if not self.actuateOk: - return - - # mark the last build time - self.actuateAt = None - yield self.setState('last_build', self.lastActuated) - - # start the build - yield self.startBuild() - - # schedule the next build (noting the lock is already held) - yield self._scheduleNextBuild_locked() - d = self.actuationLock.run(set_state_and_start) - - # this function can't return a deferred, so handle any failures via - # log.err - d.addErrback(log.err, 'while actuating') - - -class Periodic(Timed): - compare_attrs = Timed.compare_attrs + ('periodicBuildTimer', 'branch',) - - def __init__(self, name, builderNames, periodicBuildTimer, - branch=None, properties={}, onlyImportant=False): - Timed.__init__(self, name=name, builderNames=builderNames, - properties=properties) - if periodicBuildTimer <= 0: - config.error( - "periodicBuildTimer must be positive") - self.periodicBuildTimer = periodicBuildTimer - self.branch = branch - self.reason = "The Periodic scheduler named '%s' triggered this build" % self.name - - def getNextBuildTime(self, lastActuated): - if lastActuated is None: - return defer.succeed(self.now()) # meaning "ASAP" - else: - return defer.succeed(lastActuated + self.periodicBuildTimer) - - def startBuild(self): - return self.addBuildsetForLatest(reason=self.reason, branch=self.branch) - -class NightlyBase(Timed): - compare_attrs = (Timed.compare_attrs - + ('minute', 'hour', 'dayOfMonth', 'month', 'dayOfWeek')) - - def __init__(self, name, builderNames, minute=0, hour='*', - dayOfMonth='*', month='*', dayOfWeek='*', - properties={}, codebases=base.BaseScheduler.DefaultCodebases): - Timed.__init__(self, name=name, builderNames=builderNames, - properties=properties, codebases=codebases) - - self.minute = minute - self.hour = hour - self.dayOfMonth = dayOfMonth - self.month = month - self.dayOfWeek = dayOfWeek - - try: - croniter - except NameError: - config.error("python-dateutil required for scheduler %s '%s'." % - (self.__class__.__name__, self.name)) - - def _timeToCron(self, time, isDayOfWeek = False): - if isinstance(time, int): - if isDayOfWeek: - time = (time + 1) % 7 # Convert from Mon = 0 format to Sun = 0 format for use in croniter - return time - - if isinstance(time, basestring): - return time - - if isDayOfWeek: - time = [ (t + 1) % 7 for t in time ] # Conversion for croniter (see above) - - return ','.join([ str(s) for s in time ]) # Convert the list to a string - - def getNextBuildTime(self, lastActuated): - dateTime = lastActuated or self.now() - sched = '%s %s %s %s %s' % (self._timeToCron(self.minute), - self._timeToCron(self.hour), - self._timeToCron(self.dayOfMonth), - self._timeToCron(self.month), - self._timeToCron(self.dayOfWeek, True)) - cron = croniter.croniter(sched, dateTime) - nextdate = cron.get_next(float) - return defer.succeed(nextdate) - -class Nightly(NightlyBase): - compare_attrs = (NightlyBase.compare_attrs - + ('branch', 'onlyIfChanged', 'fileIsImportant', - 'change_filter', 'onlyImportant',)) - - class NoBranch: pass - def __init__(self, name, builderNames, minute=0, hour='*', - dayOfMonth='*', month='*', dayOfWeek='*', - branch=NoBranch, fileIsImportant=None, onlyIfChanged=False, - properties={}, change_filter=None, onlyImportant=False, - codebases = base.BaseScheduler.DefaultCodebases): - NightlyBase.__init__(self, name=name, builderNames=builderNames, - minute=minute, hour=hour, dayOfWeek=dayOfWeek, dayOfMonth=dayOfMonth, - properties=properties, codebases=codebases) - - # If True, only important changes will be added to the buildset. - self.onlyImportant = onlyImportant - - if fileIsImportant and not callable(fileIsImportant): - config.error( - "fileIsImportant must be a callable") - - if branch is Nightly.NoBranch: - config.error( - "Nightly parameter 'branch' is required") - - self.branch = branch - self.onlyIfChanged = onlyIfChanged - self.fileIsImportant = fileIsImportant - self.change_filter = filter.ChangeFilter.fromSchedulerConstructorArgs( - change_filter=change_filter) - self.reason = "The Nightly scheduler named '%s' triggered this build" % self.name - - def startTimedSchedulerService(self): - if self.onlyIfChanged: - return self.startConsumingChanges(fileIsImportant=self.fileIsImportant, - change_filter=self.change_filter, - onlyImportant=self.onlyImportant) - else: - return self.master.db.schedulers.flushChangeClassifications(self.objectid) - - def gotChange(self, change, important): - # both important and unimportant changes on our branch are recorded, as - # we will include all such changes in any buildsets we start. Note - # that we must check the branch here because it is not included in the - # change filter. - if change.branch != self.branch: - return defer.succeed(None) # don't care about this change - return self.master.db.schedulers.classifyChanges( - self.objectid, { change.number : important }) - - @defer.inlineCallbacks - def startBuild(self): - scheds = self.master.db.schedulers - # if onlyIfChanged is True, then we will skip this build if no - # important changes have occurred since the last invocation - if self.onlyIfChanged: - classifications = \ - yield scheds.getChangeClassifications(self.objectid) - - # see if we have any important changes - for imp in classifications.itervalues(): - if imp: - break - else: - log.msg(("Nightly Scheduler <%s>: skipping build " + - "- No important changes on configured branch") % self.name) - return - - changeids = sorted(classifications.keys()) - yield self.addBuildsetForChanges(reason=self.reason, - changeids=changeids) - - max_changeid = changeids[-1] # (changeids are sorted) - yield scheds.flushChangeClassifications(self.objectid, - less_than=max_changeid+1) - else: - # start a build of the latest revision, whatever that is - yield self.addBuildsetForLatest(reason=self.reason, - branch=self.branch) - -class NightlyTriggerable(NightlyBase): - implements(ITriggerableScheduler) - def __init__(self, name, builderNames, minute=0, hour='*', - dayOfMonth='*', month='*', dayOfWeek='*', - properties={}, codebases=base.BaseScheduler.DefaultCodebases): - NightlyBase.__init__(self, name=name, builderNames=builderNames, minute=minute, hour=hour, - dayOfWeek=dayOfWeek, dayOfMonth=dayOfMonth, properties=properties, codebases=codebases) - - self._lastTrigger = None - self.reason = "The NightlyTriggerable scheduler named '%s' triggered this build" % self.name - - def startService(self): - NightlyBase.startService(self) - - # get the scheduler's lastTrigger time (note: only done at startup) - d = self.getState('lastTrigger', None) - def setLast(lastTrigger): - try: - if lastTrigger: - assert isinstance(lastTrigger[0], dict) - self._lastTrigger = (lastTrigger[0], properties.Properties.fromDict(lastTrigger[1])) - except: - # If the lastTrigger isn't of the right format, ignore it - log.msg("NightlyTriggerable Scheduler <%s>: bad lastTrigger: %r" % (self.name, lastTrigger)) - d.addCallback(setLast) - - def trigger(self, sourcestamps, set_props=None): - """Trigger this scheduler with the given sourcestamp ID. Returns a - deferred that will fire when the buildset is finished.""" - self._lastTrigger = (sourcestamps, set_props) - - # record the trigger in the db - if set_props: - propsDict = set_props.asDict() - else: - propsDict = {} - d = self.setState('lastTrigger', - (sourcestamps, propsDict)) - - ## Trigger expects a callback with the success of the triggered - ## build, if waitForFinish is True. - ## Just return SUCCESS, to indicate that the trigger was succesful, - ## don't want for the nightly to run. - return d.addCallback(lambda _: buildstep.SUCCESS) - - @defer.inlineCallbacks - def startBuild(self): - if self._lastTrigger is None: - defer.returnValue(None) - - (sourcestamps, set_props) = self._lastTrigger - self._lastTrigger = None - yield self.setState('lastTrigger', None) - - # properties for this buildset are composed of our own properties, - # potentially overridden by anything from the triggering build - props = properties.Properties() - props.updateFromProperties(self.properties) - if set_props: - props.updateFromProperties(set_props) - - yield self.addBuildsetForSourceStampSetDetails(reason=self.reason, sourcestamps=sourcestamps, - properties=props) |