Package buildbot :: Package changes :: Module manager
[frames] | no frames]

Source Code for Module buildbot.changes.manager

  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 time 
 17   
 18  from zope.interface import implements 
 19  from twisted.python import log 
 20  from twisted.internet import defer 
 21  from twisted.application import service 
 22   
 23  from buildbot import interfaces, util 
 24   
25 -class ChangeManager(service.MultiService):
26 27 """This is the master-side service which receives file change 28 notifications from a VCS. It keeps a log of these changes, enough to 29 provide for the HTML waterfall display, and to tell 30 temporarily-disconnected bots what they missed while they were 31 offline. 32 33 Change notifications come from two different kinds of sources. The first 34 is a PB service (servicename='changemaster', perspectivename='change'), 35 which provides a remote method called 'addChange', which should be 36 called with a dict that has keys 'filename' and 'comments'. 37 38 The second is a list of objects derived from the 39 L{buildbot.changes.base.ChangeSource} class. These are added with 40 .addSource(), which also sets the .changemaster attribute in the source 41 to point at the ChangeMaster. When the application begins, these will 42 be started with .start() . At shutdown time, they will be terminated 43 with .stop() . They must be persistable. They are expected to call 44 self.changemaster.addChange() with Change objects. 45 46 There are several different variants of the second type of source: 47 48 - L{buildbot.changes.mail.MaildirSource} watches a maildir for CVS 49 commit mail. It uses DNotify if available, or polls every 10 50 seconds if not. It parses incoming mail to determine what files 51 were changed. 52 53 """ 54 55 implements(interfaces.IEventSource) 56 57 changeHorizon = None 58 lastPruneChanges = None 59 name = "changemanager" 60
61 - def __init__(self):
62 service.MultiService.__init__(self) 63 self._cache = util.LRUCache() 64 self.lastPruneChanges = 0 65 self.changeHorizon = 0
66
67 - def addSource(self, source):
68 assert interfaces.IChangeSource.providedBy(source) 69 assert service.IService.providedBy(source) 70 source.setServiceParent(self)
71
72 - def removeSource(self, source):
73 assert source in self 74 return defer.maybeDeferred(source.disownServiceParent)
75
76 - def addChange(self, change):
77 """Deliver a file change event. The event should be a Change object. 78 This method will timestamp the object as it is received.""" 79 msg = ("adding change, who %s, %d files, rev=%s, branch=%s, repository=%s, " 80 "comments %s, category %s, project %s" % (change.who, len(change.files), 81 change.revision, change.branch, change.repository, 82 change.comments, change.category, change.project)) 83 log.msg(msg.encode('utf-8', 'replace')) 84 85 # this sets change.number, if it wasn't already set (by the 86 # migration-from-pickle code). It also fires a notification which 87 # wakes up the Schedulers. 88 self.parent.addChange(change) 89 90 self.pruneChanges(change.number)
91
92 - def pruneChanges(self, last_added_changeid):
93 # this is an expensive operation, so only do it once per second, in case 94 # addChanges is called frequently 95 if not self.changeHorizon or self.lastPruneChanges > time.time() - 1: 96 return 97 self.lastPruneChanges = time.time() 98 99 ids = self.parent.db.getChangeIdsLessThanIdNow(last_added_changeid - self.changeHorizon + 1) 100 for changeid in ids: 101 log.msg("removing change with id %s" % changeid) 102 self.parent.db.removeChangeNow(changeid)
103 104 # IEventSource methods 105
106 - def eventGenerator(self, branches=[], categories=[], committers=[], minTime=0):
107 return self.parent.db.changeEventGenerator(branches, categories, 108 committers, minTime)
109
110 - def getChangeNumberedNow(self, changeid, t=None):
111 return self.parent.db.getChangeNumberedNow(changeid, t)
112 - def getChangeByNumber(self, changeid):
113 return self.parent.db.getChangeByNumber(changeid)
114 - def getChangesGreaterThan(self, last_changeid, t=None):
115 return self.parent.db.getChangesGreaterThan(last_changeid, t)
116 - def getChangesByNumber(self, changeids):
117 return self.parent.db.getChangesByNumber(changeids)
118 - def getLatestChangeNumberNow(self, branch=None, t=None):
120