diff --git a/contrib/shrink-revlog.py b/contrib/shrink-revlog.py --- a/contrib/shrink-revlog.py +++ b/contrib/shrink-revlog.py @@ -119,7 +119,7 @@ def writerevs(ui, r1, r2, order, tr): try: bundler = changegroup.bundle10() bundler.start(lookup) - group = util.chunkbuffer(r1.group(order, bundler)) + group = util.chunkbuffer(bundler.group(order, r1)) group = changegroup.unbundle10(group, "UN") r2.addgroup(group, unlookup, tr) finally: diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py --- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -7,7 +7,7 @@ from i18n import _ from node import nullrev -import mdiff, util +import mdiff, util, dagutil import struct, os, bz2, zlib, tempfile _BUNDLE10_DELTA_HEADER = "20s20s20s20s" @@ -231,8 +231,49 @@ class bundle10(object): self._lookup = lookup def close(self): return closechunk() + def fileheader(self, fname): return chunkheader(len(fname)) + fname + + def group(self, nodelist, revlog, reorder=None): + """Calculate a delta group, yielding a sequence of changegroup chunks + (strings). + + Given a list of changeset revs, return a set of deltas and + metadata corresponding to nodes. The first delta is + first parent(nodelist[0]) -> nodelist[0], the receiver is + guaranteed to have this parent as it has all history before + these changesets. In the case firstparent is nullrev the + changegroup starts with a full revision. + """ + + # if we don't have any revisions touched by these changesets, bail + if len(nodelist) == 0: + yield self.close() + return + + # for generaldelta revlogs, we linearize the revs; this will both be + # much quicker and generate a much smaller bundle + if (revlog._generaldelta and reorder is not False) or reorder: + dag = dagutil.revlogdag(revlog) + revs = set(revlog.rev(n) for n in nodelist) + revs = dag.linearize(revs) + else: + revs = sorted([revlog.rev(n) for n in nodelist]) + + # add the parent of the first rev + p = revlog.parentrevs(revs[0])[0] + revs.insert(0, p) + + # build deltas + for r in xrange(len(revs) - 1): + prev, curr = revs[r], revs[r + 1] + for c in self.revchunk(revlog, curr, prev): + yield c + + yield self.close() + + def revchunk(self, revlog, rev, prev): node = revlog.node(rev) p1, p2 = revlog.parentrevs(rev) diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -2092,7 +2092,7 @@ class localrepository(object): # Create a changenode group generator that will call our functions # back to lookup the owning changenode and collect information. count[:] = [0, len(csets)] - for chunk in cl.group(csets, bundler, reorder=reorder): + for chunk in bundler.group(csets, cl, reorder=reorder): yield chunk progress(_bundling, None) @@ -2101,7 +2101,7 @@ class localrepository(object): for f in changedfiles: fnodes[f] = {} count[:] = [0, len(mfs)] - for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder): + for chunk in bundler.group(prune(mf, mfs), mf, reorder=reorder): yield chunk progress(_bundling, None) @@ -2121,7 +2121,7 @@ class localrepository(object): if nodelist: count[0] += 1 yield bundler.fileheader(fname) - for chunk in filerevlog.group(nodelist, bundler, reorder): + for chunk in bundler.group(nodelist, filerevlog, reorder): yield chunk # Signal that no more groups are left. @@ -2201,12 +2201,12 @@ class localrepository(object): # construct a list of all changed files count[:] = [0, len(nodes)] - for chunk in cl.group(nodes, bundler, reorder=reorder): + for chunk in bundler.group(nodes, cl, reorder=reorder): yield chunk progress(_bundling, None) count[:] = [0, len(mfs)] - for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder): + for chunk in bundler.group(gennodelst(mf), mf, reorder=reorder): yield chunk progress(_bundling, None) @@ -2221,7 +2221,7 @@ class localrepository(object): if nodelist: count[0] += 1 yield bundler.fileheader(fname) - for chunk in filerevlog.group(nodelist, bundler, reorder): + for chunk in bundler.group(nodelist, filerevlog, reorder): yield chunk yield bundler.close() progress(_bundling, None) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -14,7 +14,7 @@ and O(changes) merge between branches. # import stuff from node for others to import from revlog from node import bin, hex, nullid, nullrev from i18n import _ -import ancestor, mdiff, parsers, error, util, dagutil +import ancestor, mdiff, parsers, error, util import struct, zlib, errno _pack = struct.pack @@ -1143,44 +1143,6 @@ class revlog(object): self._basecache = (curr, chainbase) return node - def group(self, nodelist, bundler, reorder=None): - """Calculate a delta group, yielding a sequence of changegroup chunks - (strings). - - Given a list of changeset revs, return a set of deltas and - metadata corresponding to nodes. The first delta is - first parent(nodelist[0]) -> nodelist[0], the receiver is - guaranteed to have this parent as it has all history before - these changesets. In the case firstparent is nullrev the - changegroup starts with a full revision. - """ - - # if we don't have any revisions touched by these changesets, bail - if len(nodelist) == 0: - yield bundler.close() - return - - # for generaldelta revlogs, we linearize the revs; this will both be - # much quicker and generate a much smaller bundle - if (self._generaldelta and reorder is not False) or reorder: - dag = dagutil.revlogdag(self) - revs = set(self.rev(n) for n in nodelist) - revs = dag.linearize(revs) - else: - revs = sorted([self.rev(n) for n in nodelist]) - - # add the parent of the first rev - p = self.parentrevs(revs[0])[0] - revs.insert(0, p) - - # build deltas - for r in xrange(len(revs) - 1): - prev, curr = revs[r], revs[r + 1] - for c in bundler.revchunk(self, curr, prev): - yield c - - yield bundler.close() - def addgroup(self, bundle, linkmapper, transaction): """ add a delta group