# HG changeset patch # User Eric Sumner # Date 2014-12-18 05:14:19 # Node ID 4440c7cc3728fb7d5c6e29df7348804be0fe3188 # Parent 200215cdf7aa9a75054ae7d4f840bb8c3551c23d bundle2.bundlepart: make mandatory part flag explicit in API This makes all bundle2 parts mandatory unless they are expressly made advisory via the keyword parameter or the bundlepart.mandatory property. diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -350,7 +350,8 @@ def _processpart(op, part): if output is not None: output = op.ui.popbuffer() if output: - outpart = op.reply.newpart('b2x:output', data=output) + outpart = op.reply.newpart('b2x:output', data=output, + mandatory=False) outpart.addparam('in-reply-to', str(part.id), mandatory=False) finally: # consume the part content to not corrupt the stream. @@ -588,7 +589,7 @@ class bundlepart(object): """ def __init__(self, parttype, mandatoryparams=(), advisoryparams=(), - data=''): + data='', mandatory=True): self.id = None self.type = parttype self._data = data @@ -605,6 +606,7 @@ class bundlepart(object): # - False: currently generated, # - True: generation done. self._generated = None + self.mandatory = mandatory # methods used to defines the part content def __setdata(self, data): @@ -642,9 +644,13 @@ class bundlepart(object): raise RuntimeError('part can only be consumed once') self._generated = False #### header + if self.mandatory: + parttype = self.type.upper() + else: + parttype = self.type.lower() ## parttype - header = [_pack(_fparttypesize, len(self.type)), - self.type, _pack(_fpartid, self.id), + header = [_pack(_fparttypesize, len(parttype)), + parttype, _pack(_fpartid, self.id), ] ## parameters # count @@ -681,7 +687,8 @@ class bundlepart(object): # backup exception data for later exc_info = sys.exc_info() msg = 'unexpected error: %s' % exc - interpart = bundlepart('b2x:error:abort', [('message', msg)]) + interpart = bundlepart('b2x:error:abort', [('message', msg)], + mandatory=False) interpart.id = 0 yield _pack(_fpayloadsize, -1) for chunk in interpart.getchunks(): @@ -930,7 +937,7 @@ def handlechangegroup(op, inpart): if op.reply is not None: # This is definitely not the final form of this # return. But one need to start somewhere. - part = op.reply.newpart('b2x:reply:changegroup') + part = op.reply.newpart('b2x:reply:changegroup', mandatory=False) part.addparam('in-reply-to', str(inpart.id), mandatory=False) part.addparam('return', '%i' % ret, mandatory=False) assert not inpart.read() diff --git a/tests/test-bundle2-format.t b/tests/test-bundle2-format.t --- a/tests/test-bundle2-format.t +++ b/tests/test-bundle2-format.t @@ -55,7 +55,8 @@ Create an extension to test bundle2 API > op.ui.write('received ping request (id %i)\n' % part.id) > if op.reply is not None and 'ping-pong' in op.reply.capabilities: > op.ui.write_err('replying to ping request (id %i)\n' % part.id) - > op.reply.newpart('test:pong', [('in-reply-to', str(part.id))]) + > op.reply.newpart('test:pong', [('in-reply-to', str(part.id))], + > mandatory=False) > > @bundle2.parthandler('test:debugreply') > def debugreply(op, part): @@ -108,32 +109,34 @@ Create an extension to test bundle2 API > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)] > outgoing = discovery.outgoing(repo.changelog, headcommon, headmissing) > cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None) - > bundler.newpart('b2x:changegroup', data=cg.getchunks()) + > bundler.newpart('b2x:changegroup', data=cg.getchunks(), + > mandatory=False) > > if opts['parts']: - > bundler.newpart('test:empty') + > bundler.newpart('test:empty', mandatory=False) > # add a second one to make sure we handle multiple parts - > bundler.newpart('test:empty') - > bundler.newpart('test:song', data=ELEPHANTSSONG) - > bundler.newpart('test:debugreply') + > bundler.newpart('test:empty', mandatory=False) + > bundler.newpart('test:song', data=ELEPHANTSSONG, mandatory=False) + > bundler.newpart('test:debugreply', mandatory=False) > mathpart = bundler.newpart('test:math') > mathpart.addparam('pi', '3.14') > mathpart.addparam('e', '2.72') > mathpart.addparam('cooking', 'raw', mandatory=False) > mathpart.data = '42' + > mathpart.mandatory = False > # advisory known part with unknown mandatory param - > bundler.newpart('test:song', [('randomparam','')]) + > bundler.newpart('test:song', [('randomparam','')], mandatory=False) > if opts['unknown']: > bundler.newpart('test:UNKNOWN', data='some random content') > if opts['unknownparams']: > bundler.newpart('test:SONG', [('randomparams', '')]) > if opts['parts']: - > bundler.newpart('test:ping') + > bundler.newpart('test:ping', mandatory=False) > if opts['genraise']: > def genraise(): > yield 'first line\n' > raise RuntimeError('Someone set up us the bomb!') - > bundler.newpart('b2x:output', data=genraise()) + > bundler.newpart('b2x:output', data=genraise(), mandatory=False) > > if path is None: > file = sys.stdout