diff options
Diffstat (limited to 'buildbot/buildbot/changes/freshcvs.py')
-rw-r--r-- | buildbot/buildbot/changes/freshcvs.py | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/buildbot/buildbot/changes/freshcvs.py b/buildbot/buildbot/changes/freshcvs.py new file mode 100644 index 0000000..53a2ac4 --- /dev/null +++ b/buildbot/buildbot/changes/freshcvs.py @@ -0,0 +1,144 @@ + +import os.path + +from zope.interface import implements +from twisted.cred import credentials +from twisted.spread import pb +from twisted.application.internet import TCPClient +from twisted.python import log + +import cvstoys.common # to make sure VersionedPatch gets registered + +from buildbot.interfaces import IChangeSource +from buildbot.pbutil import ReconnectingPBClientFactory +from buildbot.changes.changes import Change +from buildbot import util + +class FreshCVSListener(pb.Referenceable): + def remote_notify(self, root, files, message, user): + try: + self.source.notify(root, files, message, user) + except Exception, e: + print "notify failed" + log.err() + + def remote_goodbye(self, message): + pass + +class FreshCVSConnectionFactory(ReconnectingPBClientFactory): + + def gotPerspective(self, perspective): + log.msg("connected to FreshCVS daemon") + ReconnectingPBClientFactory.gotPerspective(self, perspective) + self.source.connected = True + # TODO: freshcvs-1.0.10 doesn't handle setFilter correctly, it will + # be fixed in the upcoming 1.0.11 . I haven't been able to test it + # to make sure the failure mode is survivable, so I'll just leave + # this out for now. + return + if self.source.prefix is not None: + pathfilter = "^%s" % self.source.prefix + d = perspective.callRemote("setFilter", + None, pathfilter, None) + # ignore failures, setFilter didn't work in 1.0.10 and this is + # just an optimization anyway + d.addErrback(lambda f: None) + + def clientConnectionLost(self, connector, reason): + ReconnectingPBClientFactory.clientConnectionLost(self, connector, + reason) + self.source.connected = False + +class FreshCVSSourceNewcred(TCPClient, util.ComparableMixin): + """This source will connect to a FreshCVS server associated with one or + more CVS repositories. Each time a change is committed to a repository, + the server will send us a message describing the change. This message is + used to build a Change object, which is then submitted to the + ChangeMaster. + + This class handles freshcvs daemons which use newcred. CVSToys-1.0.9 + does not, later versions might. + """ + + implements(IChangeSource) + compare_attrs = ["host", "port", "username", "password", "prefix"] + + changemaster = None # filled in when we're added + connected = False + + def __init__(self, host, port, user, passwd, prefix=None): + self.host = host + self.port = port + self.username = user + self.password = passwd + if prefix is not None and not prefix.endswith("/"): + log.msg("WARNING: prefix '%s' should probably end with a slash" \ + % prefix) + self.prefix = prefix + self.listener = l = FreshCVSListener() + l.source = self + self.factory = f = FreshCVSConnectionFactory() + f.source = self + self.creds = credentials.UsernamePassword(user, passwd) + f.startLogin(self.creds, client=l) + TCPClient.__init__(self, host, port, f) + + def __repr__(self): + return "<FreshCVSSource where=%s, prefix=%s>" % \ + ((self.host, self.port), self.prefix) + + def describe(self): + online = "" + if not self.connected: + online = " [OFFLINE]" + return "freshcvs %s:%s%s" % (self.host, self.port, online) + + def notify(self, root, files, message, user): + pathnames = [] + isdir = 0 + for f in files: + if not isinstance(f, (cvstoys.common.VersionedPatch, + cvstoys.common.Directory)): + continue + pathname, filename = f.pathname, f.filename + #r1, r2 = getattr(f, 'r1', None), getattr(f, 'r2', None) + if isinstance(f, cvstoys.common.Directory): + isdir = 1 + path = os.path.join(pathname, filename) + log.msg("FreshCVS notify '%s'" % path) + if self.prefix: + if path.startswith(self.prefix): + path = path[len(self.prefix):] + else: + continue + pathnames.append(path) + if pathnames: + # now() is close enough: FreshCVS *is* realtime, after all + when=util.now() + c = Change(user, pathnames, message, isdir, when=when) + self.parent.addChange(c) + +class FreshCVSSourceOldcred(FreshCVSSourceNewcred): + """This is for older freshcvs daemons (from CVSToys-1.0.9 and earlier). + """ + + def __init__(self, host, port, user, passwd, + serviceName="cvstoys.notify", prefix=None): + self.host = host + self.port = port + self.prefix = prefix + self.listener = l = FreshCVSListener() + l.source = self + self.factory = f = FreshCVSConnectionFactory() + f.source = self + f.startGettingPerspective(user, passwd, serviceName, client=l) + TCPClient.__init__(self, host, port, f) + + def __repr__(self): + return "<FreshCVSSourceOldcred where=%s, prefix=%s>" % \ + ((self.host, self.port), self.prefix) + +# this is suitable for CVSToys-1.0.10 and later. If you run CVSToys-1.0.9 or +# earlier, use FreshCVSSourceOldcred instead. +FreshCVSSource = FreshCVSSourceNewcred + |