| 1 |
# -*- test-case-name: buildbot.test.test_bzrpoller -*- |
|---|
| 2 |
|
|---|
| 3 |
from zope.interface import implements |
|---|
| 4 |
from twisted.python import log |
|---|
| 5 |
from twisted.application import service, internet |
|---|
| 6 |
|
|---|
| 7 |
from buildbot import util, interfaces |
|---|
| 8 |
from buildbot.changes.changes import Change |
|---|
| 9 |
|
|---|
| 10 |
from bzrlib.branch import Branch |
|---|
| 11 |
|
|---|
| 12 |
class BzrPoller(service.MultiService, util.ComparableMixin): |
|---|
| 13 |
"""This source will poll a Bzr repository for changes and submit them to |
|---|
| 14 |
the change master.""" |
|---|
| 15 |
implements(interfaces.IChangeSource) |
|---|
| 16 |
|
|---|
| 17 |
compare_attrs = ["location", "pollinterval"] |
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
parent = None # filled in when we're added |
|---|
| 21 |
last_change = None |
|---|
| 22 |
loop = None |
|---|
| 23 |
working = False |
|---|
| 24 |
|
|---|
| 25 |
def __init__(self, location, pollinterval=10*60): |
|---|
| 26 |
""" |
|---|
| 27 |
@type location: string |
|---|
| 28 |
@param location: the URL of the branch that this poller should watch. |
|---|
| 29 |
This is typically an http: or sftp: URL. |
|---|
| 30 |
|
|---|
| 31 |
@type pollinterval: int |
|---|
| 32 |
@param pollinterval: interval in seconds between polls. The default |
|---|
| 33 |
is 600 seconds (10 minutes). Smaller values |
|---|
| 34 |
decrease the latency between the time a change |
|---|
| 35 |
is recorded and the time the buildbot notices |
|---|
| 36 |
it, but it also increases the system load. |
|---|
| 37 |
""" |
|---|
| 38 |
service.MultiService.__init__(self) |
|---|
| 39 |
|
|---|
| 40 |
self.location = location |
|---|
| 41 |
|
|---|
| 42 |
self.pollinterval = pollinterval |
|---|
| 43 |
self.overrun_counter = 0 |
|---|
| 44 |
timer = internet.TimerService(pollinterval, self.poll) |
|---|
| 45 |
timer.setServiceParent(self) |
|---|
| 46 |
|
|---|
| 47 |
def describe(self): |
|---|
| 48 |
return "BzrPoller watching %s" % self.location |
|---|
| 49 |
|
|---|
| 50 |
def poll(self): |
|---|
| 51 |
log.msg("BzrPoller polling") |
|---|
| 52 |
# location="http://bazaar-vcs.org/bzr/bzr.dev" |
|---|
| 53 |
b = Branch.open_containing(self.url)[0] |
|---|
| 54 |
# this is subclass of bzrlib.branch.Branch |
|---|
| 55 |
current_revision = b.revno() |
|---|
| 56 |
# NOTE: b.revision_history() does network IO, and is blocking. |
|---|
| 57 |
revisions = b.revision_history()[last_revno:] # each is an id string |
|---|
| 58 |
changes = [] |
|---|
| 59 |
for r in revisions: |
|---|
| 60 |
rev = b.repository.get_revision(r) |
|---|
| 61 |
# bzrlib.revision.Revision |
|---|
| 62 |
who = rev.committer |
|---|
| 63 |
comments = rev.message |
|---|
| 64 |
when = rev.timestamp |
|---|
| 65 |
# rev.timezone, interesting. Not sure it's used. |
|---|
| 66 |
|
|---|
| 67 |
d = b.repository.get_revision_delta(r) |
|---|
| 68 |
# this is a delta.TreeDelta |
|---|
| 69 |
files = ([f[0] for f in d.added] + |
|---|
| 70 |
[f[0] for f in d.removed] + |
|---|
| 71 |
[f[1] for f in d.renamed] + |
|---|
| 72 |
[f[0] for f in d.modified] |
|---|
| 73 |
) |
|---|
| 74 |
|
|---|
| 75 |
# revision= ? |
|---|
| 76 |
# branch= ? |
|---|
| 77 |
c = Change(who=rev.committer, |
|---|
| 78 |
files=files, |
|---|
| 79 |
comments=rev.message, |
|---|
| 80 |
when=rev.timestamp, |
|---|
| 81 |
) |
|---|
| 82 |
changes.append(c) |
|---|
| 83 |
for c in changes: |
|---|
| 84 |
self.parent.addChange(c) |
|---|
| 85 |
log.msg("BzrPoller finished polling, %d changes found" % len(changes)) |
|---|