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

Source Code for Module buildbot.changes.manager

  1  # ***** BEGIN LICENSE BLOCK ***** 
  2  # Version: MPL 1.1/GPL 2.0/LGPL 2.1 
  3  # 
  4  # The contents of this file are subject to the Mozilla Public License Version 
  5  # 1.1 (the "License"); you may not use this file except in compliance with 
  6  # the License. You may obtain a copy of the License at 
  7  # http://www.mozilla.org/MPL/ 
  8  # 
  9  # Software distributed under the License is distributed on an "AS IS" basis, 
 10  # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 11  # for the specific language governing rights and limitations under the 
 12  # License. 
 13  # 
 14  # The Original Code is Mozilla-specific Buildbot steps. 
 15  # 
 16  # The Initial Developer of the Original Code is 
 17  # Mozilla Foundation. 
 18  # Portions created by the Initial Developer are Copyright (C) 2009 
 19  # the Initial Developer. All Rights Reserved. 
 20  # 
 21  # Contributor(s): 
 22  #   Brian Warner <warner@lothar.com> 
 23  # 
 24  # Alternatively, the contents of this file may be used under the terms of 
 25  # either the GNU General Public License Version 2 or later (the "GPL"), or 
 26  # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 
 27  # in which case the provisions of the GPL or the LGPL are applicable instead 
 28  # of those above. If you wish to allow use of your version of this file only 
 29  # under the terms of either the GPL or the LGPL, and not to allow others to 
 30  # use your version of this file under the terms of the MPL, indicate your 
 31  # decision by deleting the provisions above and replace them with the notice 
 32  # and other provisions required by the GPL or the LGPL. If you do not delete 
 33  # the provisions above, a recipient may use your version of this file under 
 34  # the terms of any one of the MPL, the GPL or the LGPL. 
 35  # 
 36  # ***** END LICENSE BLOCK ***** 
 37   
 38  import time 
 39   
 40  from zope.interface import implements 
 41  from twisted.python import log 
 42  from twisted.internet import defer 
 43  from twisted.application import service 
 44   
 45  from buildbot import interfaces, util 
 46   
47 -class ChangeManager(service.MultiService):
48 49 """This is the master-side service which receives file change 50 notifications from a VCS. It keeps a log of these changes, enough to 51 provide for the HTML waterfall display, and to tell 52 temporarily-disconnected bots what they missed while they were 53 offline. 54 55 Change notifications come from two different kinds of sources. The first 56 is a PB service (servicename='changemaster', perspectivename='change'), 57 which provides a remote method called 'addChange', which should be 58 called with a dict that has keys 'filename' and 'comments'. 59 60 The second is a list of objects derived from the 61 L{buildbot.changes.base.ChangeSource} class. These are added with 62 .addSource(), which also sets the .changemaster attribute in the source 63 to point at the ChangeMaster. When the application begins, these will 64 be started with .start() . At shutdown time, they will be terminated 65 with .stop() . They must be persistable. They are expected to call 66 self.changemaster.addChange() with Change objects. 67 68 There are several different variants of the second type of source: 69 70 - L{buildbot.changes.mail.MaildirSource} watches a maildir for CVS 71 commit mail. It uses DNotify if available, or polls every 10 72 seconds if not. It parses incoming mail to determine what files 73 were changed. 74 75 - L{buildbot.changes.freshcvs.FreshCVSSource} makes a PB 76 connection to the CVSToys 'freshcvs' daemon and relays any 77 changes it announces. 78 79 """ 80 81 implements(interfaces.IEventSource) 82 83 changeHorizon = None 84 lastPruneChanges = None 85 name = "changemanager" 86
87 - def __init__(self):
88 service.MultiService.__init__(self) 89 self._cache = util.LRUCache() 90 self.lastPruneChanges = 0 91 self.changeHorizon = 0
92
93 - def addSource(self, source):
94 assert interfaces.IChangeSource.providedBy(source) 95 assert service.IService.providedBy(source) 96 source.setServiceParent(self)
97
98 - def removeSource(self, source):
99 assert source in self 100 return defer.maybeDeferred(source.disownServiceParent)
101
102 - def addChange(self, change):
103 """Deliver a file change event. The event should be a Change object. 104 This method will timestamp the object as it is received.""" 105 msg = ("adding change, who %s, %d files, rev=%s, branch=%s, repository=%s, " 106 "comments %s, category %s, project %s" % (change.who, len(change.files), 107 change.revision, change.branch, change.repository, 108 change.comments, change.category, change.project)) 109 log.msg(msg.encode('utf-8', 'replace')) 110 111 # this sets change.number, if it wasn't already set (by the 112 # migration-from-pickle code). It also fires a notification which 113 # wakes up the Schedulers. 114 self.parent.addChange(change) 115 116 self.pruneChanges(change.number)
117
118 - def pruneChanges(self, last_added_changeid):
119 # this is an expensive operation, so only do it once per second, in case 120 # addChanges is called frequently 121 if not self.changeHorizon or self.lastPruneChanges > time.time() - 1: 122 return 123 self.lastPruneChanges = time.time() 124 125 ids = self.parent.db.getChangeIdsLessThanIdNow(last_added_changeid - self.changeHorizon + 1) 126 for changeid in ids: 127 log.msg("removing change with id %s" % changeid) 128 self.parent.db.removeChangeNow(changeid)
129 130 # IEventSource methods 131
132 - def eventGenerator(self, branches=[], categories=[], committers=[], minTime=0):
133 return self.parent.db.changeEventGenerator(branches, categories, 134 committers, minTime)
135
136 - def getChangeNumberedNow(self, changeid, t=None):
137 return self.parent.db.getChangeNumberedNow(changeid, t)
138 - def getChangeByNumber(self, changeid):
139 return self.parent.db.getChangeByNumber(changeid)
140 - def getChangesGreaterThan(self, last_changeid, t=None):
141 return self.parent.db.getChangesGreaterThan(last_changeid, t)
142 - def getChangesByNumber(self, changeids):
143 return self.parent.db.getChangesByNumber(changeids)
144 - def getLatestChangeNumberNow(self, branch=None, t=None):
146