Mercurial > hg
changeset 20997:d7df4b7378ae
bundle2: produce a bundle2 reply
We do not know yet what kind of data future features and extensions will need to
exchange. To handle that, bundle2 allows to send arbitrary content to the
server. As a consequence, we need to be able to reply arbitrary content to the
client. And, we can use bundle2 to transmit those arbitrary data.
When a client will push a bundle2 to the server, the server will reply with a
bundle2 itself.
This changeset installs the first stone of this logic and test it.
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Fri, 04 Apr 2014 14:24:11 -0700 |
parents | ed3c5e18a047 |
children | 93a3c5b58635 |
files | mercurial/bundle2.py tests/test-bundle2.t |
diffstat | 2 files changed, 71 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/bundle2.py Fri Apr 11 08:24:59 2014 -0700 +++ b/mercurial/bundle2.py Fri Apr 04 14:24:11 2014 -0700 @@ -254,6 +254,7 @@ self.ui = repo.ui self.records = unbundlerecords() self.gettransaction = transactiongetter + self.reply = None class TransactionUnavailable(RuntimeError): pass @@ -278,6 +279,9 @@ """ op = bundleoperation(repo, transactiongetter) # todo: + # - only create reply bundle if requested. + op.reply = bundle20(op.ui) + # todo: # - replace this is a init function soon. # - exception catching unbundler.params
--- a/tests/test-bundle2.t Fri Apr 11 08:24:59 2014 -0700 +++ b/tests/test-bundle2.t Fri Apr 04 14:24:11 2014 -0700 @@ -33,6 +33,13 @@ > verses += 1 > op.records.add('song', {'verses': verses}) > + > @bundle2.parthandler('test:ping') + > def pinghandler(op, part): + > op.ui.write('received ping request (id %i)\n' % part.id) + > if op.reply is not None: + > op.reply.addpart(bundle2.part('test:pong', + > [('in-reply-to', str(part.id))])) + > > @command('bundle2', > [('', 'param', [], 'stream level parameter'), > ('', 'unknown', False, 'include an unknown mandatory part in the bundle'), @@ -83,6 +90,9 @@ > part = bundle2.part('test:UNKNOWN', > data='some random content') > bundler.addpart(part) + > if opts['parts']: + > part = bundle2.part('test:ping') + > bundler.addpart(part) > > if path is None: > file = sys.stdout @@ -93,7 +103,7 @@ > file.write(chunk) > > @command('unbundle2', [], '') - > def cmdunbundle2(ui, repo): + > def cmdunbundle2(ui, repo, replypath=None): > """process a bundle2 stream from stdin on the current repo""" > try: > tr = None @@ -116,6 +126,10 @@ > ui.write('%i total verses sung\n' % totalverses) > for rec in op.records['changegroup']: > ui.write('addchangegroup return: %i\n' % rec['return']) + > if op.reply is not None and replypath is not None: + > file = open(replypath, 'w') + > for chunk in op.reply.getchunks(): + > file.write(chunk) > > @command('statbundle2', [], '') > def cmdstatbundle2(ui, repo): @@ -318,6 +332,7 @@ bundle part: "test:empty" bundle part: "test:song" bundle part: "test:math" + bundle part: "test:ping" end of bundle $ cat ../parts.hg2 @@ -325,12 +340,12 @@ test:empty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11 (esc) test:empty\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10 test:song\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko (esc) Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko - Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00+ test:math\x00\x00\x00\x03\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x00 (no-eol) (esc) + Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00+ test:math\x00\x00\x00\x03\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x10 test:ping\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc) $ hg statbundle2 < ../parts.hg2 options count: 0 - parts count: 4 + parts count: 5 :test:empty: mandatory: 0 advisory: 0 @@ -347,6 +362,10 @@ mandatory: 2 advisory: 1 payload: 2 bytes + :test:ping: + mandatory: 0 + advisory: 0 + payload: 0 bytes $ hg statbundle2 --debug < ../parts.hg2 start processing of HG20 stream @@ -375,9 +394,14 @@ part parameters: 3 payload chunk size: 2 payload chunk size: 0 + part header size: 16 + part type: "test:ping" + part id: "4" + part parameters: 0 + payload chunk size: 0 part header size: 0 end of bundle2 stream - parts count: 4 + parts count: 5 :test:empty: mandatory: 0 advisory: 0 @@ -394,6 +418,10 @@ mandatory: 2 advisory: 1 payload: 2 bytes + :test:ping: + mandatory: 0 + advisory: 0 + payload: 0 bytes Test actual unbundling of test part ======================================= @@ -434,11 +462,20 @@ payload chunk size: 2 payload chunk size: 0 ignoring unknown advisory part 'test:math' + part header size: 16 + part type: "test:ping" + part id: "4" + part parameters: 0 + payload chunk size: 0 + found a handler for part 'test:ping' + received ping request (id 4) part header size: 0 end of bundle2 stream 0 unread bytes 3 total verses sung +Unbundle with an unknown mandatory part +(should abort) $ hg bundle2 --parts --unknown ../unknown.hg2 @@ -451,6 +488,32 @@ abort: missing support for 'test:unknown' [255] +unbundle with a reply + + $ hg unbundle2 ../reply.hg2 < ../parts.hg2 + The choir starts singing: + Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko + Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko + Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko. + received ping request (id 4) + 0 unread bytes + 3 total verses sung + +The reply is a bundle + + $ cat ../reply.hg2 + HG20\x00\x00\x00\x1e test:pong\x00\x00\x00\x00\x01\x00\x0b\x01in-reply-to4\x00\x00\x00\x00\x00\x00 (no-eol) (esc) + +The reply is valid + + $ hg statbundle2 < ../reply.hg2 + options count: 0 + parts count: 1 + :test:pong: + mandatory: 1 + advisory: 0 + payload: 0 bytes + Support for changegroup ===================================