Ticket #76: buildbot-hgpoller.patch

File buildbot-hgpoller.patch, 4.2 kB (added by TedMielczarek, 1 year ago)

hgpoller.py (unified diff)

  • old-trunk/buildbot/changes/hgpoller.py

    old new  
     1import time 
     2import rfc822 
     3from urllib import urlopen 
     4from xml.dom import minidom, Node 
     5 
     6from twisted.python import log, failure 
     7from twisted.internet import defer, reactor 
     8from twisted.internet.task import LoopingCall 
     9 
     10from buildbot.changes import base, changes 
     11 
     12class HgPoller(base.ChangeSource): 
     13    """This source will poll a Mercurial server over HTTP using 
     14    the built-in RSS feed for changes and submit them to the 
     15    change master.""" 
     16 
     17    compare_attrs = ['hgURL', 'branch', 'pollInterval'] 
     18    parent = None 
     19    loop = None 
     20    volatile = ['loop'] 
     21    working = False 
     22     
     23    def __init__(self, hgURL, branch, pollInterval=30): 
     24        """ 
     25        @type   hgURL:          string 
     26        @param  hgURL:          The base URL of the Hg repo 
     27                                (e.g. http://hg.mozilla.org/) 
     28        @type   branch:         string 
     29        @param  branch:         The branch to check (e.g. mozilla-central) 
     30        @type   pollInterval:   int 
     31        @param  pollInterval:   The time (in seconds) between queries for 
     32                                changes 
     33        """ 
     34         
     35        self.hgURL = hgURL 
     36        self.branch = branch 
     37        self.pollInterval = pollInterval 
     38        self.lastChange = time.time() 
     39        self.lastPoll = time.time() 
     40 
     41    def startService(self): 
     42        self.loop = LoopingCall(self.poll) 
     43        base.ChangeSource.startService(self) 
     44        reactor.callLater(0, self.loop.start, self.pollInterval) 
     45 
     46    def stopService(self): 
     47        self.loop.stop() 
     48        return base.ChangeSource.stopService(self) 
     49     
     50    def describe(self): 
     51        return "Getting changes from the Mercurial repo at %s%s" % \ 
     52               (self.hgURL, self.branch) 
     53     
     54    def poll(self): 
     55        if self.working: 
     56            log.msg("Not polling because last poll is still working") 
     57        else: 
     58            self.working = True 
     59            d = self._get_changes() 
     60            d.addCallback(self._process_changes) 
     61            d.addCallbacks(self._finished_ok, self._finished_failure) 
     62 
     63    def _finished_ok(self, res): 
     64        assert self.working 
     65        self.working = False 
     66 
     67        return res 
     68 
     69    def _finished_failure(self, res): 
     70        log.msg("Hg poll failed: %s" % res) 
     71        assert self.working 
     72        self.working = False 
     73        return None 
     74 
     75    def _make_url(self): 
     76        return "%s%s/?rss-log" % (self.hgURL, self.branch) 
     77     
     78    def _get_changes(self): 
     79        url = self._make_url() 
     80        log.msg("Polling Hg server at %s" % url) 
     81         
     82        self.lastPoll = time.time() 
     83        return defer.maybeDeferred(urlopen, url) 
     84 
     85    def _parse_changes(self, query): 
     86        dom = minidom.parseString(query.read()) 
     87        items = dom.getElementsByTagName("item") 
     88        changes = [] 
     89        for i in items: 
     90            d = dict() 
     91            for k in ["description", "link", "author", "pubDate"]: 
     92                d[k] = i.getElementsByTagName(k)[0].firstChild.wholeText 
     93            # strip out HTML newlines 
     94            d["description"] = d["description"].replace("<br/>","") 
     95            # need to parse date with timezone, and turn into a UTC timestamp 
     96            d["pubDate"] = rfc822.mktime_tz(rfc822.parsedate_tz(d["pubDate"]) ) 
     97            changes.append(d) 
     98        changes = [c for c in changes if c["pubDate"] > self.lastChange] 
     99        changes.reverse() # want t hem in reverse chronological order 
     100        return changes 
     101     
     102    def _process_changes(self, query): 
     103        change_list = self._parse_changes(query) 
     104        for change in change_list: 
     105            c = changes.Change(who = change["author"], 
     106                               files = [], # sucks 
     107                               comments = change["description"], 
     108                               when = change["pubDate"], 
     109                               branch = self.branch) 
     110            self.parent.addChange(c) 
     111        self.lastChange = max(self.lastPoll, *[c["pubDate"] for c in 
     112                                                   change_list]) 
     113