[Buildbot-commits] buildbot/contrib svn_buildbot.py,1.10,1.11

Brian Warner warner at users.sourceforge.net
Wed Mar 22 20:53:33 UTC 2006


Update of /cvsroot/buildbot/buildbot/contrib
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6651/contrib

Modified Files:
	svn_buildbot.py 
Log Message:
rearrange, add an easy-to-change function to turn a repository-relative
pathname into a (branch, branch-relative-filename) tuple. Change this
function to handle the branch naming policy used by your Subversion
repository. Thanks to AllMyData.com for sponsoring this work.


Index: svn_buildbot.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/contrib/svn_buildbot.py,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- svn_buildbot.py	24 Nov 2005 21:57:29 -0000	1.10
+++ svn_buildbot.py	22 Mar 2006 20:53:30 -0000	1.11
@@ -46,7 +46,7 @@
     sys.stderr = f
     sys.stdout = f
 
-from twisted.internet import reactor
+from twisted.internet import defer, reactor
 from twisted.python import usage
 from twisted.spread import pb
 from twisted.cred import credentials
@@ -76,6 +76,9 @@
 patterns.  Excludes override includes, that is, patterns that match both an
 include and an exclude will be excluded.'''],
         ]
+    optFlags = [
+        ['dryrun', 'n', "Do not actually send changes"],
+        ]
 
     def __init__(self):
         usage.Options.__init__(self)
@@ -99,78 +102,149 @@
         if self._excludes:
             self['excludes'] = '(%s)' % ('|'.join(self._excludes),)
 
+def split_file_dummy(changed_file):
+    """Split the repository-relative filename into a tuple of (branchname,
+    branch_relative_filename). If you have no branches, this should just
+    return (None, changed_file).
+    """
+    return (None, changed_file)
 
-def main(opts):
-    repo = opts['repository']
-    print "Repo:", repo
-    rev_arg = ''
-    if opts['revision']:
-        rev_arg = '-r %s' % (opts['revision'],)
-    changed = commands.getoutput('svnlook changed %s "%s"' % (rev_arg, repo)
-                                 ).split('\n')
-    changed = [x[1:].strip() for x in changed]
-    message = commands.getoutput('svnlook log %s "%s"' % (rev_arg, repo))
-    who = commands.getoutput('svnlook author %s "%s"' % (rev_arg, repo))
-    revision = opts.get('revision')
-    if revision is not None:
-        revision = int(revision)
+# this version handles repository layouts that look like:
+#  trunk/files..                  -> trunk
+#  branches/branch1/files..       -> branches/branch1
+#  branches/branch2/files..       -> branches/branch2
+#
+def split_file_branches(changed_file):
+    pieces = changed_file.split(os.sep)
+    if pieces[0] == 'branches':
+        return (os.path.join(*pieces[:2]),
+                os.path.join(*pieces[2:]))
+    if pieces[0] == 'trunk':
+        return (pieces[0], os.path.join(*pieces[1:]))
+    ## there are other sibilings of 'trunk' and 'branches'. Pretend they are
+    ## all just funny-named branches, and let the Schedulers ignore them.
+    #return (pieces[0], os.path.join(*pieces[1:]))
 
-    # see if we even need to notify buildbot by looking at filters first
-    changestring = '\n'.join(changed)
-    fltpat = opts['includes']
-    if fltpat:
-        included = sets.Set(re.findall(fltpat, changestring))
-    else:
-        included = sets.Set(changed)
+    raise RuntimeError("cannot determine branch for '%s'" % changed_file)
 
-    expat = opts['excludes']
-    if expat:
-        excluded = sets.Set(re.findall(expat, changestring))
-    else:
-        excluded = sets.Set([])
-    if len(included.difference(excluded)) == 0:
-        print changestring
-        print """\
-Buildbot was not interested, no changes matched any of these filters:\n %s
-or all the changes matched these exclusions:\n %s\
-""" % (fltpat, expat)
-        sys.exit(0)
+split_file = split_file_dummy
 
-    pbcf = pb.PBClientFactory()
-    reactor.connectTCP(opts['bbserver'], int(opts['bbport']),
-                       pbcf)
 
-    def gotPersp(persp):
-        print "who", repr(who)
-        print "what", repr(changed)
-        print "why", repr(message)
-        print "new revision", repr(revision)
-        return persp.callRemote('addChange', {'who': who,
-                                              'files': changed,
-                                              'comments': message,
-                                              'revision': revision})
+class ChangeSender:
 
-    def quit(*why):
-        print "quitting! because", why
-        reactor.stop()
+    def getChanges(self, opts):
+        """Generate and stash a list of Change dictionaries, ready to be sent
+        to the buildmaster's PBChangeSource."""
 
+        # first we extract information about the files that were changed
+        repo = opts['repository']
+        print "Repo:", repo
+        rev_arg = ''
+        if opts['revision']:
+            rev_arg = '-r %s' % (opts['revision'],)
+        changed = commands.getoutput('svnlook changed %s "%s"' % (rev_arg,
+                                                                  repo)
+                                     ).split('\n')
+        changed = [x[1:].strip() for x in changed]
 
-    pbcf.login(credentials.UsernamePassword('change', 'changepw')
-               ).addCallback(gotPersp
-               ).addCallback(quit, "SUCCESS"
-               ).addErrback(quit, "FAILURE")
+        message = commands.getoutput('svnlook log %s "%s"' % (rev_arg, repo))
+        who = commands.getoutput('svnlook author %s "%s"' % (rev_arg, repo))
+        revision = opts.get('revision')
+        if revision is not None:
+            revision = int(revision)
 
-    # timeout of 60 seconds
-    reactor.callLater(60, quit, "TIMEOUT")
+        # see if we even need to notify buildbot by looking at filters first
+        changestring = '\n'.join(changed)
+        fltpat = opts['includes']
+        if fltpat:
+            included = sets.Set(re.findall(fltpat, changestring))
+        else:
+            included = sets.Set(changed)
 
-    reactor.run()
+        expat = opts['excludes']
+        if expat:
+            excluded = sets.Set(re.findall(expat, changestring))
+        else:
+            excluded = sets.Set([])
+        if len(included.difference(excluded)) == 0:
+            print changestring
+            print """\
+    Buildbot was not interested, no changes matched any of these filters:\n %s
+    or all the changes matched these exclusions:\n %s\
+    """ % (fltpat, expat)
+            sys.exit(0)
+
+        # now see which branches are involved
+        files_per_branch = {}
+        for f in changed:
+            branch, filename = split_file(f)
+            if files_per_branch.has_key(branch):
+                files_per_branch[branch].append(filename)
+            else:
+                files_per_branch[branch] = [filename]
+
+        # now create the Change dictionaries
+        changes = []
+        for branch in files_per_branch.keys():
+            d = {'who': who,
+                 'branch': branch,
+                 'files': files_per_branch[branch],
+                 'comments': message,
+                 'revision': revision}
+            changes.append(d)
+
+        return changes
+
+    def sendChanges(self, opts, changes):
+        pbcf = pb.PBClientFactory()
+        reactor.connectTCP(opts['bbserver'], int(opts['bbport']), pbcf)
+        d = pbcf.login(credentials.UsernamePassword('change', 'changepw'))
+        d.addCallback(self.sendAllChanges, changes)
+        return d
+
+    def sendAllChanges(self, remote, changes):
+        dl = [remote.callRemote('addChange', change)
+              for change in changes]
+        return defer.DeferredList(dl)
+
+    def run(self):
+        opts = Options()
+        try:
+            opts.parseOptions()
+        except usage.error, ue:
+            print opts
+            print "%s: %s" % (sys.argv[0], ue)
+            sys.exit()
+
+        changes = self.getChanges(opts)
+        if opts['dryrun']:
+            for i,c in enumerate(changes):
+                print "CHANGE #%d" % (i+1)
+                keys = c.keys()
+                keys.sort()
+                for k in keys:
+                    print "[%10s]: %s" % (k, c[k])
+            print "*NOT* sending any changes"
+            return
+
+        d = self.sendChanges(opts, changes)
+
+        def quit(*why):
+            print "quitting! because", why
+            reactor.stop()
+
+        def failed(f):
+            print "FAILURE"
+            print f
+            reactor.stop()
+
+        d.addCallback(quit, "SUCCESS")
+        d.addErrback(failed)
+        reactor.callLater(60, quit, "TIMEOUT")
+        reactor.run()
 
 if __name__ == '__main__':
-    opts = Options()
-    try:
-        opts.parseOptions()
-    except usage.error, ue:
-        print opts
-        print "%s: %s" % (sys.argv[0], ue)
-        sys.exit()
-    main(opts)
+    s = ChangeSender()
+    s.run()
+
+





More information about the Commits mailing list