##// 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 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 254 # For version 1 transports.
260 255 commands = commanddict()
261 256
262 257 # For version 2 transports.
263 258 commandsv2 = commanddict()
264 259
265 def wireprotocommand(name, args=None, transportpolicy=POLICY_V1_ONLY,
266 permission='push'):
260 def wireprotocommand(name, args=None, permission='push'):
267 261 """Decorator to declare a wire protocol command.
268 262
269 263 ``name`` is the name of the wire protocol command being provided.
270 264
271 265 ``args`` defines the named arguments accepted by the command. It is
272 ideally a dict mapping argument names to their types. For backwards
273 compatibility, it can be a space-delimited list of argument names. For
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.
266 a space-delimited list of argument names. ``*`` denotes a special value
267 that says to accept all named arguments.
280 268
281 269 ``permission`` defines the permission type needed to run this command.
282 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 272 because otherwise commands not declaring their permissions could modify
285 273 a repository that is supposed to be read-only.
286 274 """
287 if transportpolicy == POLICY_V1_ONLY:
288 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
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)
275 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
276 if v['version'] == 1}
298 277
299 278 # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to
300 279 # SSHv2.
@@ -307,40 +286,20 b' def wireprotocommand(name, args=None, tr'
307 286 'got %s; expected "push" or "pull"' %
308 287 permission)
309 288
310 if transportversion == 1:
311 if args is None:
312 args = ''
289 if args is None:
290 args = ''
313 291
314 if not isinstance(args, bytes):
315 raise error.ProgrammingError('arguments for version 1 commands '
316 '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')
292 if not isinstance(args, bytes):
293 raise error.ProgrammingError('arguments for version 1 commands '
294 'must be declared as bytes')
324 295
325 296 def register(func):
326 if transportversion == 1:
327 if name in commands:
328 raise error.ProgrammingError('%s command already registered '
329 'for version 1' % name)
330 commands[name] = commandentry(func, args=args,
331 transports=transports,
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)
297 if name in commands:
298 raise error.ProgrammingError('%s command already registered '
299 'for version 1' % name)
300 commands[name] = commandentry(func, args=args,
301 transports=transports,
302 permission=permission)
344 303
345 304 return func
346 305 return register
@@ -405,10 +405,43 b' def _capabilitiesv2(repo, proto):'
405 405
406 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 436 def register(func):
410 return wireproto.wireprotocommand(
411 *args, transportpolicy=wireproto.POLICY_V2_ONLY, **kwargs)(func)
437 if name in wireproto.commandsv2:
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 446 return register
414 447
@@ -16,6 +16,7 b' sendhttpv2peerhandshake() {'
16 16 cat > dummycommands.py << EOF
17 17 from mercurial import (
18 18 wireprototypes,
19 wireprotov2server,
19 20 wireproto,
20 21 )
21 22
@@ -23,8 +24,7 b' from mercurial import ('
23 24 def customreadonlyv1(repo, proto):
24 25 return wireprototypes.bytesresponse(b'customreadonly bytes response')
25 26
26 @wireproto.wireprotocommand('customreadonly', permission='pull',
27 transportpolicy=wireproto.POLICY_V2_ONLY)
27 @wireprotov2server.wireprotocommand('customreadonly', permission='pull')
28 28 def customreadonlyv2(repo, proto):
29 29 return wireprototypes.cborresponse(b'customreadonly bytes response')
30 30
@@ -32,8 +32,7 b' def customreadonlyv2(repo, proto):'
32 32 def customreadwrite(repo, proto):
33 33 return wireprototypes.bytesresponse(b'customreadwrite bytes response')
34 34
35 @wireproto.wireprotocommand('customreadwrite', permission='push',
36 transportpolicy=wireproto.POLICY_V2_ONLY)
35 @wireprotov2server.wireprotocommand('customreadwrite', permission='push')
37 36 def customreadwritev2(repo, proto):
38 37 return wireprototypes.cborresponse(b'customreadwrite bytes response')
39 38 EOF
General Comments 0
You need to be logged in to leave comments. Login now