[Buildbot-devel] Cron-style scheduling
Dobes Vandermeer
dobesv at gmail.com
Sat Oct 29 00:48:44 UTC 2005
This is a first take on a cron-style scheduler. Insert it into
scheduler.py after class Periodic. To run a build once per weekday
(which I'm sure will be the most popular usage) at 3am, pass hour=3,
minute=0, dayOfWeek=range(5). Also to run every even five minutes,
pass minute=range(0,60,5).
Comments/suggestions appreciated!
def addTime(timetuple, secs):
return time.localtime(time.mktime(timetuple)+secs)
def findFirstValueAtLeast(values, value, default=None):
for v in values:
if v >= value: return v
return default
class CronStyleScheduler(BaseUpstreamScheduler):
""" Imitate "cron" scheduling.
Pass some subset of minute, hour, dayOfMonth, month, and dayOfWeek;
each may be a single number or a list of valid values.
For dayOfWeek and dayOfMonth, builds are triggered if the date matches
either of them. Month and day numbers start at 1, not zero.
"""
compare_attrs = ('name', 'builderNames',
'minute', 'hour', 'dayOfMonth', 'month',
'dayOfWeek', 'branch')
def __init__(self, name, builderNames, minute=None, hour=None,
dayOfMonth=None, month=None, dayOfWeek=None,
branch=None):
BaseUpstreamScheduler.__init__(self, name)
self.builderNames = builderNames
self.minute = minute
self.hour = hour
self.dayOfMonth = dayOfMonth
self.month = month
self.dayOfWeek = dayOfWeek
self.branch = branch
self.delayedRun = None
self.nextRunTime = None
def setTimer(self):
self.nextRunTime = self.calculateNextRunTime()
self.delayedRun = reactor.callLater(self.nextRunTime -
time.time(), self.doPeriodicBuild)
def startService(self):
BaseUpstreamScheduler.startService(self)
self.setTimer()
print 'CronStyleScheduler.__init__', self.name,
time.asctime(), 'next run',
time.asctime(time.localtime(self.nextRunTime))
def stopService(self):
BaseUpstreamScheduler.stopService(self)
self.delayedRun.cancel()
def calculateNextRunTime(self):
dateTime = time.localtime()
dateTime = addTime(dateTime, 60-dateTime[5]) # Remove seconds
by advancing to at least the next minue
# Now we just keep adding minutes until we find something that matches
# print 'minute', self.minute
# print 'hour', self.hour
# print 'dayOfMonth', self.dayOfMonth
# print 'month', self.month
# print 'dayOfWeek', self.dayOfWeek
# print 'dateTime', time.asctime(dateTime)
def isRunTime(timetuple):
def check(ourvalue, value):
if not ourvalue: return True
if isinstance(ourvalue, int): return value == ourvalue
return (value in ourvalue)
if not check(self.minute, timetuple[4]):
# print 'bad minute', timetuple[4], self.minute
return False
if not check(self.hour, timetuple[3]):
# print 'bad hour', timetuple[3], self.hour
return False
if not check(self.month, timetuple[1]):
# print 'bad month', timetuple[1], self.month
return False
if self.dayOfMonth and self.dayOfWeek: # Specified day(s)
of month AND day(s) of week
if not (check(self.dayOfMonth, timetuple[2]) or
check(self.dayOfWeek, timetuple[6])):
# print 'bad day'
return False
else:
if not check(self.dayOfMonth, timetuple[2]):
#print 'bad day of month'
return False
if not check(self.dayOfWeek, timetuple[6]):
#print 'bad day of week'
return False
return True
# It not an efficient algorithm, but it'll *work* for now
yearLimit = dateTime[0]+2
while not isRunTime(dateTime):
dateTime = addTime(dateTime, 60)
# print 'Trying', time.asctime(dateTime)
assert dateTime[0] < yearLimit, 'Something is wrong with this code'
return time.mktime(dateTime)
def listBuilderNames(self):
return self.builderNames
def getPendingBuildTimes(self):
# TODO: figure out when self.timer is going to fire next and report
# that
if self.nextRunTime is None: return []
return [self.nextRunTime]
def doPeriodicBuild(self):
# Schedule the next run
self.setTimer()
print 'CronStyleScheduler.doPeriodicBuild', self.name,
time.asctime(), 'next run',
time.asctime(time.localtime(self.nextRunTime))
# And trigger a build
bs = buildset.BuildSet(self.builderNames,
SourceStamp(branch=self.branch))
self.submit(bs)
def addChange(self, change):
pass
More information about the devel
mailing list