diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -179,8 +179,6 @@ urlreq = util.urlreq _fpayloadsize = '>i' _fpartparamcount = '>BB' -_fphasesentry = struct.Struct('>i20s') - preferedchunksize = 4096 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]') @@ -1480,11 +1478,8 @@ def _addpartsfromopts(ui, repo, bundler, if opts.get('phases', False): headsbyphase = phases.subsetphaseheads(repo, outgoing.missing) - phasedata = [] - for phase in phases.allphases: - for head in headsbyphase[phase]: - phasedata.append(_fphasesentry.pack(phase, head)) - bundler.newpart('phase-heads', data=''.join(phasedata)) + phasedata = phases.binaryencode(headsbyphase) + bundler.newpart('phase-heads', data=phasedata) def addparttagsfnodescache(repo, bundler, outgoing): # we include the tags fnode cache for the bundle changeset @@ -1843,14 +1838,14 @@ def handlepushkey(op, inpart): def _readphaseheads(inpart): headsbyphase = [[] for i in phases.allphases] - entrysize = _fphasesentry.size + entrysize = phases._fphasesentry.size while True: entry = inpart.read(entrysize) if len(entry) < entrysize: if entry: raise error.Abort(_('bad phase-heads bundle part')) break - phase, node = _fphasesentry.unpack(entry) + phase, node = phases._fphasesentry.unpack(entry) headsbyphase[phase].append(node) return headsbyphase diff --git a/mercurial/phases.py b/mercurial/phases.py --- a/mercurial/phases.py +++ b/mercurial/phases.py @@ -103,6 +103,7 @@ Note: old client behave as a publishing from __future__ import absolute_import import errno +import struct from .i18n import _ from .node import ( @@ -119,6 +120,8 @@ from . import ( util, ) +_fphasesentry = struct.Struct('>i20s') + allphases = public, draft, secret = range(3) trackedphases = allphases[1:] phasenames = ['public', 'draft', 'secret'] @@ -154,6 +157,18 @@ def _readroots(repo, phasedefaults=None) dirty = True return roots, dirty +def binaryencode(phasemapping): + """encode a 'phase -> nodes' mapping into a binary stream + + Since phases are integer the mapping is actually a python list: + [[PUBLIC_HEADS], [DRAFTS_HEADS], [SECRET_HEADS]] + """ + binarydata = [] + for phase, nodes in enumerate(phasemapping): + for head in nodes: + binarydata.append(_fphasesentry.pack(phase, head)) + return ''.join(binarydata) + def _trackphasechange(data, rev, old, new): """add a phase move the dictionnary