Patchwork [7,of,9,changegroup-apis] changegroup: add and use getunbundler() to changegroupemitter

mail settings
Submitter Gregory Szorc
Date Aug. 1, 2016, 6:18 p.m.
Message ID <707393be6c674cded252.1470075504@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/16022/
State Changes Requested
Delegated to: Pierre-Yves David
Headers show


Gregory Szorc - Aug. 1, 2016, 6:18 p.m.
# HG changeset patch
# User Gregory Szorc <>
# Date 1469909170 25200
#      Sat Jul 30 13:06:10 2016 -0700
# Node ID 707393be6c674cded25255e4fa19d9b791b56f46
# Parent  39ff601b7117aecdd41ec1cc1a3539063c100e99
changegroup: add and use getunbundler() to changegroupemitter

There were multiple uses of a similar pattern of obtaining changegroup
data then converting it to an unbundler. We factor the common code
into the changegroupemitter class.

This API may change in patches ahead. The main goal of this patch is
to pave the road for further removal of the low-level changegroup
retrieval functions in


diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -909,40 +909,35 @@  def _changegroupinfo(repo, nodes, source
         repo.ui.status(_("%d changesets found\n") % len(nodes))
     if repo.ui.debugflag:
         repo.ui.debug("list of changesets:\n")
         for node in nodes:
             repo.ui.debug("%s\n" % hex(node))
 def getsubset(repo, outgoing, bundler, source, fastpath=False):
     emitter = changegroupemitter.fromoutgoing(repo, outgoing)
-    data = emitter.emitchangegroupdata(bundler.version, source,
-                                       bundler._bundlecaps,
-                                       fastpathlinkrev=fastpath)
-    return getunbundler(bundler.version, util.chunkbuffer(data), None,
-                        {'clcount': emitter.changesetcount})
+    return emitter.getunbundler(bundler.version, source,
+                                bundler._bundlecaps,
+                                fastpathlinkrev=fastpath)
 def changegroupsubset(repo, roots, heads, source, version='01'):
     """Compute a changegroup consisting of all the nodes that are
     descendants of any of the roots and ancestors of any of the heads.
     Return a chunkbuffer object whose read() method will return
     successive changegroup chunks.
     It is fairly complex as determining which filenodes and which
     manifest nodes need to be included for the changeset to be complete
     is non-trivial.
     Another wrinkle is doing the reverse, figuring out which changeset in
     the changegroup a particular filenode or manifestnode belongs to.
     emitter = changegroupemitter.fromrootsandheads(repo, roots, heads)
-    data = emitter.emitchangegroupdata(version, source)
-    return getunbundler(version, util.chunkbuffer(data), None,
-                        {'clcount': emitter.changesetcount})
+    return emitter.getunbundler(version, source)
 def getlocalchangegroup(repo, source, outgoing, bundlecaps=None,
     """Like getbundle, but taking a discovery.outgoing as an argument.
     This is only implemented for local repos and reuses potentially
     precomputed sets in outgoing."""
     if not outgoing.missing:
@@ -1124,8 +1119,23 @@  class changegroupemitter(object):
         bundler = getbundler(version, self._repo, bundlecaps=bundlecaps)
         self._repo.hook('preoutgoing', throw=True, source=source)
         _changegroupinfo(self._repo, self._nodes, source)
         return bundler.generate(self._commonrevs, self._nodes,
                                 fastpathlinkrev, source)
+    def getunbundler(self, version, source, bundlecaps=None,
+                     fastpathlinkrev=False):
+        """Obtain an unbundler for this changegroup.
+        Returns an instance of ``cgNunpacker`` or None if the changegroup
+        is empty.
+        """
+        data = self.emitchangegroupdata(version, source, bundlecaps=bundlecaps,
+                                        fastpathlinkrev=fastpathlinkrev)
+        if not data:
+            return None
+        return getunbundler(version, util.chunkbuffer(data), None,
+                            {'clcount': self.changesetcount})