[PATCH 2 of 5] localrepo: collect changelog, manifest, file nodes needed in shallow clone

Vishakh H vsh426 at gmail.com
Tue Jun 29 11:15:03 CDT 2010


# HG changeset patch
# User Vishakh H <vsh426 at gmail.com>
# Date 1277827720 -19800
# Branch stable
# Node ID 9fd45a923518181e097bec605b19070a517b58dd
# Parent  0e714c59e28b68feb51c84f9d77a91db9d6a0661
localrepo: collect changelog, manifest, file nodes needed in shallow clone

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1175,7 +1175,7 @@
 
         return r
 
-    def pull(self, remote, heads=None, force=False):
+    def pull(self, remote, heads=None, shallowroot=None, force=False):
         lock = self.lock()
         try:
             tmp = discovery.findcommonincoming(self, remote, heads=heads,
@@ -1191,14 +1191,15 @@
                 # issue1320, avoid a race if remote changed after discovery
                 heads = rheads
 
-            if heads is None:
+            if heads is None and shallowroot is None:
                 cg = remote.changegroup(fetch, 'pull')
             else:
                 if not remote.capable('changegroupsubset'):
                     raise util.Abort(_("Partial pull cannot be done because "
                                        "other repository doesn't support "
                                        "changegroupsubset."))
-                cg = remote.changegroupsubset(fetch, heads, 'pull')
+                cg = remote.changegroupsubset(fetch, heads, 'pull',
+                                              shallowroot=shallowroot)
             return self.addchangegroup(cg, 'pull', remote.url(), lock=lock)
         finally:
             lock.release()
@@ -1268,7 +1269,8 @@
             for node in nodes:
                 self.ui.debug("%s\n" % hex(node))
 
-    def changegroupsubset(self, bases, heads, source, extranodes=None):
+    def changegroupsubset(self, bases, heads, source, extranodes=None,
+                          shallowroot=None):
         """Compute a changegroup consisting of all the nodes that are
         descendents of any of the bases and ancestors of any of the heads.
         Return a chunkbuffer object whose read() method will return
@@ -1298,7 +1300,7 @@
             bases = [nullid]
         msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
 
-        if extranodes is None:
+        if extranodes is None and shallowroot is None:
             # can we go through the fast path ?
             heads.sort()
             allheads = self.heads()
@@ -1342,6 +1344,15 @@
         msng_mnfst_set = {}
         # Nor do we know which filenodes are missing.
         msng_filenode_set = {}
+        # revs needed in shallow clone
+        if shallowroot is not None:
+            sh_cl = set([shallowroot])
+            sh_mnfst = [cl.read(shallowroot)[0]]
+            sh_filenode = {}
+        else:
+            sh_cl = None
+            sh_mnfst = None
+            sh_filenode = {}
 
         junk = mnfst.index[len(mnfst) - 1] # Get around a bug in lazyindex
         junk = None
@@ -1376,7 +1387,7 @@
             # the first manifest that references it belongs to.
             def collect_msng_filenodes(mnfstnode):
                 r = mnfst.rev(mnfstnode)
-                if r - 1 in mnfst.parentrevs(r):
+                if r - 1 in mnfst.parentrevs(r) and mnfstnode not in sh_mnfst:
                     # If the previous rev is one of the parents,
                     # we only need to see a diff.
                     deltamf = mnfst.readdelta(mnfstnode)
@@ -1406,6 +1417,10 @@
                             clnode = msng_mnfst_set[mnfstnode]
                             ndset = msng_filenode_set.setdefault(f, {})
                             ndset.setdefault(fnode, clnode)
+                    if sh_mnfst is not None and mnfstnode in sh_mnfst:
+                        # Get all important filenodes
+                        for f in m:
+                            sh_filenode.setdefault(f, []).append(m[f])
             return collect_msng_filenodes
 
         # We have a list of filenodes we think we need for a file, lets remove
@@ -1440,12 +1455,19 @@
                 if node not in nodes:
                     nodes[node] = linknode
 
+        #find nodes to punch
+        def prune_shallow(nodes, sh_nodes):
+            if shallowroot is not None:
+                return [n for n in nodes if n not in sh_nodes]
+            return None
+
         # Now that we have all theses utility functions to help out and
         # logically divide up the task, generate the group.
         def gengroup():
             # The set of changed files starts empty.
             changedfiles = {}
-            collect = changegroup.collector(cl, msng_mnfst_set, changedfiles)
+            collect = changegroup.collector(cl, msng_mnfst_set, changedfiles,
+                                sh_cl, sh_mnfst)
 
             # Create a changenode group generator that will call our functions
             # back to lookup the owning changenode and collect information.
@@ -1474,10 +1496,12 @@
             msng_mnfst_lst = msng_mnfst_set.keys()
             # Sort the manifestnodes by revision number.
             msng_mnfst_lst.sort(key=mnfst.rev)
+            sh_nodes = prune_shallow(msng_mnfst_lst, sh_mnfst)
             # Create a generator for the manifestnodes that calls our lookup
             # and data collection functions back.
             group = mnfst.group(msng_mnfst_lst, lookup_manifest_link,
-                                filenode_collector(changedfiles))
+                                filenode_collector(changedfiles),
+                                shallownodes=sh_nodes)
             cnt = 0
             for chnk in group:
                 yield chnk
@@ -1517,11 +1541,14 @@
                     yield fname
                     # Sort the filenodes by their revision #
                     msng_filenode_lst.sort(key=filerevlog.rev)
+                    sh_nodes = prune_shallow(msng_filenode_lst,
+                                             sh_filenode.get(fname, []))
                     # Create a group generator and only pass in a changenode
                     # lookup function as we need to collect no information
                     # from filenodes.
                     group = filerevlog.group(msng_filenode_lst,
-                                             lookup_filenode_link_func(fname))
+                                             lookup_filenode_link_func(fname),
+                                             shallownodes=sh_nodes)
                     for chnk in group:
                         self.ui.progress(
                             _('bundling files'), cnt, item=fname, unit=_('chunks'))
@@ -1829,7 +1856,7 @@
         self.invalidate()
         return len(self.heads()) + 1
 
-    def clone(self, remote, heads=[], stream=False):
+    def clone(self, remote, heads=[], shallowroot=None, stream=False):
         '''clone remote repository.
 
         keyword arguments:
@@ -1846,7 +1873,7 @@
 
         if stream and not heads and remote.capable('stream'):
             return self.stream_in(remote)
-        return self.pull(remote, heads)
+        return self.pull(remote, heads, shallowroot)
 
     def pushkey(self, namespace, key, old, new):
         return pushkey.push(self, namespace, key, old, new)


More information about the Mercurial-devel mailing list