diff mercurial/localrepo.py @ 13741:b51bf961b3cb

wireproto: add getbundle() function getbundle(common, heads) -> bundle Returns the changegroup for all ancestors of heads which are not ancestors of common. For both sets, the heads are included in the set. Intended to eventually supercede changegroupsubset and changegroup. Uses heads of common region to exclude unwanted changesets instead of bases of desired region, which is more useful and easier to implement. Designed to be extensible with new optional arguments (which will have to be guarded by corresponding capabilities).
author Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
date Wed, 23 Mar 2011 16:02:11 +0100
parents e615765fdcc7
children 7abab875e647
line wrap: on
line diff
--- a/mercurial/localrepo.py	Wed Mar 23 12:38:36 2011 -0500
+++ b/mercurial/localrepo.py	Wed Mar 23 16:02:11 2011 +0100
@@ -21,7 +21,7 @@
 
 class localrepository(repo.repository):
     capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
-                        'known'))
+                        'known', 'getbundle'))
     supportedformats = set(('revlogv1', 'parentdelta'))
     supported = supportedformats | set(('store', 'fncache', 'shared',
                                         'dotencode'))
@@ -1443,16 +1443,41 @@
         Another wrinkle is doing the reverse, figuring out which changeset in
         the changegroup a particular filenode or manifestnode belongs to.
         """
+        cl = self.changelog
+        if not bases:
+            bases = [nullid]
+        csets, bases, heads = cl.nodesbetween(bases, heads)
+        # We assume that all ancestors of bases are known
+        common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
+        return self._changegroupsubset(common, csets, heads, source)
+
+    def getbundle(self, source, heads=None, common=None):
+        """Like changegroupsubset, but returns the set difference between the
+        ancestors of heads and the ancestors common.
+
+        If heads is None, use the local heads. If common is None, use [nullid].
+
+        The nodes in common might not all be known locally due to the way the
+        current discovery protocol works.
+        """
+        cl = self.changelog
+        if common:
+            nm = cl.nodemap
+            common = [n for n in common if n in nm]
+        else:
+            common = [nullid]
+        if not heads:
+            heads = cl.heads()
+        common, missing = cl.findcommonmissing(common, heads)
+        return self._changegroupsubset(common, missing, heads, source)
+
+    def _changegroupsubset(self, commonrevs, csets, heads, source):
 
         cl = self.changelog
         mf = self.manifest
         mfs = {} # needed manifests
         fnodes = {} # needed file nodes
 
-        if not bases:
-            bases = [nullid]
-        csets, bases, heads = cl.nodesbetween(bases, heads)
-
         # can we go through the fast path ?
         heads.sort()
         if heads == sorted(self.heads()):
@@ -1462,9 +1487,6 @@
         self.hook('preoutgoing', throw=True, source=source)
         self.changegroupinfo(csets, source)
 
-        # We assume that all ancestors of bases are known
-        commonrevs = set(cl.ancestors(*[cl.rev(n) for n in bases]))
-
         # A function generating function that sets up the initial environment
         # the inner function.
         def filenode_collector(changedfiles):