##// END OF EJS Templates
wireproto: make version 2 @wireprotocommand an independent function...
Gregory Szorc -
r37798:8acd3a9a default
parent child Browse files
Show More
@@ -251,32 +251,20 b' class commanddict(dict):'
251
251
252 return True
252 return True
253
253
254 # Constants specifying which transports a wire protocol command should be
255 # available on. For use with @wireprotocommand.
256 POLICY_V1_ONLY = 'v1-only'
257 POLICY_V2_ONLY = 'v2-only'
258
259 # For version 1 transports.
254 # For version 1 transports.
260 commands = commanddict()
255 commands = commanddict()
261
256
262 # For version 2 transports.
257 # For version 2 transports.
263 commandsv2 = commanddict()
258 commandsv2 = commanddict()
264
259
265 def wireprotocommand(name, args=None, transportpolicy=POLICY_V1_ONLY,
260 def wireprotocommand(name, args=None, permission='push'):
266 permission='push'):
267 """Decorator to declare a wire protocol command.
261 """Decorator to declare a wire protocol command.
268
262
269 ``name`` is the name of the wire protocol command being provided.
263 ``name`` is the name of the wire protocol command being provided.
270
264
271 ``args`` defines the named arguments accepted by the command. It is
265 ``args`` defines the named arguments accepted by the command. It is
272 ideally a dict mapping argument names to their types. For backwards
266 a space-delimited list of argument names. ``*`` denotes a special value
273 compatibility, it can be a space-delimited list of argument names. For
267 that says to accept all named arguments.
274 version 1 transports, ``*`` denotes a special value that says to accept
275 all named arguments.
276
277 ``transportpolicy`` is a POLICY_* constant denoting which transports
278 this wire protocol command should be exposed to. By default, commands
279 are exposed to all wire protocol transports.
280
268
281 ``permission`` defines the permission type needed to run this command.
269 ``permission`` defines the permission type needed to run this command.
282 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
270 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
@@ -284,17 +272,8 b' def wireprotocommand(name, args=None, tr'
284 because otherwise commands not declaring their permissions could modify
272 because otherwise commands not declaring their permissions could modify
285 a repository that is supposed to be read-only.
273 a repository that is supposed to be read-only.
286 """
274 """
287 if transportpolicy == POLICY_V1_ONLY:
275 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
288 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
276 if v['version'] == 1}
289 if v['version'] == 1}
290 transportversion = 1
291 elif transportpolicy == POLICY_V2_ONLY:
292 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
293 if v['version'] == 2}
294 transportversion = 2
295 else:
296 raise error.ProgrammingError('invalid transport policy value: %s' %
297 transportpolicy)
298
277
299 # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to
278 # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to
300 # SSHv2.
279 # SSHv2.
@@ -307,40 +286,20 b' def wireprotocommand(name, args=None, tr'
307 'got %s; expected "push" or "pull"' %
286 'got %s; expected "push" or "pull"' %
308 permission)
287 permission)
309
288
310 if transportversion == 1:
289 if args is None:
311 if args is None:
290 args = ''
312 args = ''
313
291
314 if not isinstance(args, bytes):
292 if not isinstance(args, bytes):
315 raise error.ProgrammingError('arguments for version 1 commands '
293 raise error.ProgrammingError('arguments for version 1 commands '
316 'must be declared as bytes')
294 'must be declared as bytes')
317 elif transportversion == 2:
318 if args is None:
319 args = {}
320
321 if not isinstance(args, dict):
322 raise error.ProgrammingError('arguments for version 2 commands '
323 'must be declared as dicts')
324
295
325 def register(func):
296 def register(func):
326 if transportversion == 1:
297 if name in commands:
327 if name in commands:
298 raise error.ProgrammingError('%s command already registered '
328 raise error.ProgrammingError('%s command already registered '
299 'for version 1' % name)
329 'for version 1' % name)
300 commands[name] = commandentry(func, args=args,
330 commands[name] = commandentry(func, args=args,
301 transports=transports,
331 transports=transports,
302 permission=permission)
332 permission=permission)
333 elif transportversion == 2:
334 if name in commandsv2:
335 raise error.ProgrammingError('%s command already registered '
336 'for version 2' % name)
337
338 commandsv2[name] = commandentry(func, args=args,
339 transports=transports,
340 permission=permission)
341 else:
342 raise error.ProgrammingError('unhandled transport version: %d' %
343 transportversion)
344
303
345 return func
304 return func
346 return register
305 return register
@@ -405,10 +405,43 b' def _capabilitiesv2(repo, proto):'
405
405
406 return proto.addcapabilities(repo, caps)
406 return proto.addcapabilities(repo, caps)
407
407
408 def wireprotocommand(*args, **kwargs):
408 def wireprotocommand(name, args=None, permission='push'):
409 """Decorator to declare a wire protocol command.
410
411 ``name`` is the name of the wire protocol command being provided.
412
413 ``args`` is a dict of argument names to example values.
414
415 ``permission`` defines the permission type needed to run this command.
416 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
417 respectively. Default is to assume command requires ``push`` permissions
418 because otherwise commands not declaring their permissions could modify
419 a repository that is supposed to be read-only.
420 """
421 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
422 if v['version'] == 2}
423
424 if permission not in ('push', 'pull'):
425 raise error.ProgrammingError('invalid wire protocol permission; '
426 'got %s; expected "push" or "pull"' %
427 permission)
428
429 if args is None:
430 args = {}
431
432 if not isinstance(args, dict):
433 raise error.ProgrammingError('arguments for version 2 commands '
434 'must be declared as dicts')
435
409 def register(func):
436 def register(func):
410 return wireproto.wireprotocommand(
437 if name in wireproto.commandsv2:
411 *args, transportpolicy=wireproto.POLICY_V2_ONLY, **kwargs)(func)
438 raise error.ProgrammingError('%s command already registered '
439 'for version 2' % name)
440
441 wireproto.commandsv2[name] = wireproto.commandentry(
442 func, args=args, transports=transports, permission=permission)
443
444 return func
412
445
413 return register
446 return register
414
447
@@ -16,6 +16,7 b' sendhttpv2peerhandshake() {'
16 cat > dummycommands.py << EOF
16 cat > dummycommands.py << EOF
17 from mercurial import (
17 from mercurial import (
18 wireprototypes,
18 wireprototypes,
19 wireprotov2server,
19 wireproto,
20 wireproto,
20 )
21 )
21
22
@@ -23,8 +24,7 b' from mercurial import ('
23 def customreadonlyv1(repo, proto):
24 def customreadonlyv1(repo, proto):
24 return wireprototypes.bytesresponse(b'customreadonly bytes response')
25 return wireprototypes.bytesresponse(b'customreadonly bytes response')
25
26
26 @wireproto.wireprotocommand('customreadonly', permission='pull',
27 @wireprotov2server.wireprotocommand('customreadonly', permission='pull')
27 transportpolicy=wireproto.POLICY_V2_ONLY)
28 def customreadonlyv2(repo, proto):
28 def customreadonlyv2(repo, proto):
29 return wireprototypes.cborresponse(b'customreadonly bytes response')
29 return wireprototypes.cborresponse(b'customreadonly bytes response')
30
30
@@ -32,8 +32,7 b' def customreadonlyv2(repo, proto):'
32 def customreadwrite(repo, proto):
32 def customreadwrite(repo, proto):
33 return wireprototypes.bytesresponse(b'customreadwrite bytes response')
33 return wireprototypes.bytesresponse(b'customreadwrite bytes response')
34
34
35 @wireproto.wireprotocommand('customreadwrite', permission='push',
35 @wireprotov2server.wireprotocommand('customreadwrite', permission='push')
36 transportpolicy=wireproto.POLICY_V2_ONLY)
37 def customreadwritev2(repo, proto):
36 def customreadwritev2(repo, proto):
38 return wireprototypes.cborresponse(b'customreadwrite bytes response')
37 return wireprototypes.cborresponse(b'customreadwrite bytes response')
39 EOF
38 EOF
General Comments 0
You need to be logged in to leave comments. Login now