Show More
@@ -26,6 +26,7 b' test-backwards-remove.t' | |||
|
26 | 26 | test-bad-extension.t |
|
27 | 27 | test-bad-pull.t |
|
28 | 28 | test-basic.t |
|
29 | test-batching.py | |
|
29 | 30 | test-bdiff.py |
|
30 | 31 | test-bheads.t |
|
31 | 32 | test-bisect.t |
@@ -11,25 +11,28 b' import contextlib' | |||
|
11 | 11 | |
|
12 | 12 | from mercurial import ( |
|
13 | 13 | localrepo, |
|
14 | pycompat, | |
|
14 | 15 | wireprotov1peer, |
|
16 | ) | |
|
15 | 17 | |
|
16 | ) | |
|
18 | def bprint(*bs): | |
|
19 | print(*[pycompat.sysstr(b) for b in bs]) | |
|
17 | 20 | |
|
18 | 21 | # equivalent of repo.repository |
|
19 | 22 | class thing(object): |
|
20 | 23 | def hello(self): |
|
21 | return "Ready." | |
|
24 | return b"Ready." | |
|
22 | 25 | |
|
23 | 26 | # equivalent of localrepo.localrepository |
|
24 | 27 | class localthing(thing): |
|
25 | 28 | def foo(self, one, two=None): |
|
26 | 29 | if one: |
|
27 | return "%s and %s" % (one, two,) | |
|
28 | return "Nope" | |
|
30 | return b"%s and %s" % (one, two,) | |
|
31 | return b"Nope" | |
|
29 | 32 | def bar(self, b, a): |
|
30 | return "%s und %s" % (b, a,) | |
|
33 | return b"%s und %s" % (b, a,) | |
|
31 | 34 | def greet(self, name=None): |
|
32 | return "Hello, %s" % name | |
|
35 | return b"Hello, %s" % name | |
|
33 | 36 | |
|
34 | 37 | @contextlib.contextmanager |
|
35 | 38 | def commandexecutor(self): |
@@ -43,27 +46,27 b' class localthing(thing):' | |||
|
43 | 46 | def use(it): |
|
44 | 47 | |
|
45 | 48 | # Direct call to base method shared between client and server. |
|
46 | print(it.hello()) | |
|
49 | bprint(it.hello()) | |
|
47 | 50 | |
|
48 | 51 | # Direct calls to proxied methods. They cause individual roundtrips. |
|
49 | print(it.foo("Un", two="Deux")) | |
|
50 | print(it.bar("Eins", "Zwei")) | |
|
52 | bprint(it.foo(b"Un", two=b"Deux")) | |
|
53 | bprint(it.bar(b"Eins", b"Zwei")) | |
|
51 | 54 | |
|
52 | 55 | # Batched call to a couple of proxied methods. |
|
53 | 56 | |
|
54 | 57 | with it.commandexecutor() as e: |
|
55 | ffoo = e.callcommand('foo', {'one': 'One', 'two': 'Two'}) | |
|
56 | fbar = e.callcommand('bar', {'b': 'Eins', 'a': 'Zwei'}) | |
|
57 | fbar2 = e.callcommand('bar', {'b': 'Uno', 'a': 'Due'}) | |
|
58 | ffoo = e.callcommand(b'foo', {b'one': b'One', b'two': b'Two'}) | |
|
59 | fbar = e.callcommand(b'bar', {b'b': b'Eins', b'a': b'Zwei'}) | |
|
60 | fbar2 = e.callcommand(b'bar', {b'b': b'Uno', b'a': b'Due'}) | |
|
58 | 61 | |
|
59 | print(ffoo.result()) | |
|
60 | print(fbar.result()) | |
|
61 | print(fbar2.result()) | |
|
62 | bprint(ffoo.result()) | |
|
63 | bprint(fbar.result()) | |
|
64 | bprint(fbar2.result()) | |
|
62 | 65 | |
|
63 | 66 | # local usage |
|
64 | 67 | mylocal = localthing() |
|
65 | 68 | print() |
|
66 | print("== Local") | |
|
69 | bprint(b"== Local") | |
|
67 | 70 | use(mylocal) |
|
68 | 71 | |
|
69 | 72 | # demo remoting; mimicks what wireproto and HTTP/SSH do |
@@ -72,16 +75,16 b' use(mylocal)' | |||
|
72 | 75 | |
|
73 | 76 | def escapearg(plain): |
|
74 | 77 | return (plain |
|
75 | .replace(':', '::') | |
|
76 | .replace(',', ':,') | |
|
77 | .replace(';', ':;') | |
|
78 | .replace('=', ':=')) | |
|
78 | .replace(b':', b'::') | |
|
79 | .replace(b',', b':,') | |
|
80 | .replace(b';', b':;') | |
|
81 | .replace(b'=', b':=')) | |
|
79 | 82 | def unescapearg(escaped): |
|
80 | 83 | return (escaped |
|
81 | .replace(':=', '=') | |
|
82 | .replace(':;', ';') | |
|
83 | .replace(':,', ',') | |
|
84 | .replace('::', ':')) | |
|
84 | .replace(b':=', b'=') | |
|
85 | .replace(b':;', b';') | |
|
86 | .replace(b':,', b',') | |
|
87 | .replace(b'::', b':')) | |
|
85 | 88 | |
|
86 | 89 | # server side |
|
87 | 90 | |
@@ -90,27 +93,28 b' class server(object):' | |||
|
90 | 93 | def __init__(self, local): |
|
91 | 94 | self.local = local |
|
92 | 95 | def _call(self, name, args): |
|
93 | args = dict(arg.split('=', 1) for arg in args) | |
|
96 | args = dict(arg.split(b'=', 1) for arg in args) | |
|
94 | 97 | return getattr(self, name)(**args) |
|
95 | 98 | def perform(self, req): |
|
96 | print("REQ:", req) | |
|
97 | name, args = req.split('?', 1) | |
|
98 | args = args.split('&') | |
|
99 | vals = dict(arg.split('=', 1) for arg in args) | |
|
100 | res = getattr(self, name)(**vals) | |
|
101 | print(" ->", res) | |
|
99 | bprint(b"REQ:", req) | |
|
100 | name, args = req.split(b'?', 1) | |
|
101 | args = args.split(b'&') | |
|
102 | vals = dict(arg.split(b'=', 1) for arg in args) | |
|
103 | res = getattr(self, pycompat.sysstr(name))(**pycompat.strkwargs(vals)) | |
|
104 | bprint(b" ->", res) | |
|
102 | 105 | return res |
|
103 | 106 | def batch(self, cmds): |
|
104 | 107 | res = [] |
|
105 | for pair in cmds.split(';'): | |
|
106 | name, args = pair.split(':', 1) | |
|
108 | for pair in cmds.split(b';'): | |
|
109 | name, args = pair.split(b':', 1) | |
|
107 | 110 | vals = {} |
|
108 | for a in args.split(','): | |
|
111 | for a in args.split(b','): | |
|
109 | 112 | if a: |
|
110 | n, v = a.split('=') | |
|
113 | n, v = a.split(b'=') | |
|
111 | 114 | vals[n] = unescapearg(v) |
|
112 |
res.append(escapearg(getattr(self, name)( |
|
|
113 | return ';'.join(res) | |
|
115 | res.append(escapearg(getattr(self, pycompat.sysstr(name))( | |
|
116 | **pycompat.strkwargs(vals)))) | |
|
117 | return b';'.join(res) | |
|
114 | 118 | def foo(self, one, two): |
|
115 | 119 | return mangle(self.local.foo(unmangle(one), unmangle(two))) |
|
116 | 120 | def bar(self, b, a): |
@@ -124,25 +128,25 b' myserver = server(mylocal)' | |||
|
124 | 128 | # equivalent of wireproto.encode/decodelist, that is, type-specific marshalling |
|
125 | 129 | # here we just transform the strings a bit to check we're properly en-/decoding |
|
126 | 130 | def mangle(s): |
|
127 | return ''.join(chr(ord(c) + 1) for c in s) | |
|
131 | return b''.join(pycompat.bytechr(ord(c) + 1) for c in pycompat.bytestr(s)) | |
|
128 | 132 | def unmangle(s): |
|
129 | return ''.join(chr(ord(c) - 1) for c in s) | |
|
133 | return b''.join(pycompat.bytechr(ord(c) - 1) for c in pycompat.bytestr(s)) | |
|
130 | 134 | |
|
131 | 135 | # equivalent of wireproto.wirerepository and something like http's wire format |
|
132 | 136 | class remotething(thing): |
|
133 | 137 | def __init__(self, server): |
|
134 | 138 | self.server = server |
|
135 | 139 | def _submitone(self, name, args): |
|
136 | req = name + '?' + '&'.join(['%s=%s' % (n, v) for n, v in args]) | |
|
140 | req = name + b'?' + b'&'.join([b'%s=%s' % (n, v) for n, v in args]) | |
|
137 | 141 | return self.server.perform(req) |
|
138 | 142 | def _submitbatch(self, cmds): |
|
139 | 143 | req = [] |
|
140 | 144 | for name, args in cmds: |
|
141 | args = ','.join(n + '=' + escapearg(v) for n, v in args) | |
|
142 | req.append(name + ':' + args) | |
|
143 | req = ';'.join(req) | |
|
144 | res = self._submitone('batch', [('cmds', req,)]) | |
|
145 | for r in res.split(';'): | |
|
145 | args = b','.join(n + b'=' + escapearg(v) for n, v in args) | |
|
146 | req.append(name + b':' + args) | |
|
147 | req = b';'.join(req) | |
|
148 | res = self._submitone(b'batch', [(b'cmds', req,)]) | |
|
149 | for r in res.split(b';'): | |
|
146 | 150 | yield r |
|
147 | 151 | |
|
148 | 152 | @contextlib.contextmanager |
@@ -155,7 +159,7 b' class remotething(thing):' | |||
|
155 | 159 | |
|
156 | 160 | @wireprotov1peer.batchable |
|
157 | 161 | def foo(self, one, two=None): |
|
158 | encargs = [('one', mangle(one),), ('two', mangle(two),)] | |
|
162 | encargs = [(b'one', mangle(one),), (b'two', mangle(two),)] | |
|
159 | 163 | encresref = wireprotov1peer.future() |
|
160 | 164 | yield encargs, encresref |
|
161 | 165 | yield unmangle(encresref.value) |
@@ -163,18 +167,18 b' class remotething(thing):' | |||
|
163 | 167 | @wireprotov1peer.batchable |
|
164 | 168 | def bar(self, b, a): |
|
165 | 169 | encresref = wireprotov1peer.future() |
|
166 | yield [('b', mangle(b),), ('a', mangle(a),)], encresref | |
|
170 | yield [(b'b', mangle(b),), (b'a', mangle(a),)], encresref | |
|
167 | 171 | yield unmangle(encresref.value) |
|
168 | 172 | |
|
169 | 173 | # greet is coded directly. It therefore does not support batching. If it |
|
170 | 174 | # does appear in a batch, the batch is split around greet, and the call to |
|
171 | 175 | # greet is done in its own roundtrip. |
|
172 | 176 | def greet(self, name=None): |
|
173 | return unmangle(self._submitone('greet', [('name', mangle(name),)])) | |
|
177 | return unmangle(self._submitone(b'greet', [(b'name', mangle(name),)])) | |
|
174 | 178 | |
|
175 | 179 | # demo remote usage |
|
176 | 180 | |
|
177 | 181 | myproxy = remotething(myserver) |
|
178 | 182 | print() |
|
179 | print("== Remote") | |
|
183 | bprint(b"== Remote") | |
|
180 | 184 | use(myproxy) |
General Comments 0
You need to be logged in to leave comments.
Login now