711 permission='push'): |
711 permission='push'): |
712 """Decorator to declare a wire protocol command. |
712 """Decorator to declare a wire protocol command. |
713 |
713 |
714 ``name`` is the name of the wire protocol command being provided. |
714 ``name`` is the name of the wire protocol command being provided. |
715 |
715 |
716 ``args`` is a space-delimited list of named arguments that the command |
716 ``args`` defines the named arguments accepted by the command. It is |
717 accepts. ``*`` is a special value that says to accept all arguments. |
717 ideally a dict mapping argument names to their types. For backwards |
|
718 compatibility, it can be a space-delimited list of argument names. For |
|
719 version 1 transports, ``*`` denotes a special value that says to accept |
|
720 all named arguments. |
718 |
721 |
719 ``transportpolicy`` is a POLICY_* constant denoting which transports |
722 ``transportpolicy`` is a POLICY_* constant denoting which transports |
720 this wire protocol command should be exposed to. By default, commands |
723 this wire protocol command should be exposed to. By default, commands |
721 are exposed to all wire protocol transports. |
724 are exposed to all wire protocol transports. |
722 |
725 |
750 if permission not in ('push', 'pull'): |
753 if permission not in ('push', 'pull'): |
751 raise error.ProgrammingError('invalid wire protocol permission; ' |
754 raise error.ProgrammingError('invalid wire protocol permission; ' |
752 'got %s; expected "push" or "pull"' % |
755 'got %s; expected "push" or "pull"' % |
753 permission) |
756 permission) |
754 |
757 |
|
758 if 1 in transportversions and not isinstance(args, bytes): |
|
759 raise error.ProgrammingError('arguments for version 1 commands must ' |
|
760 'be declared as bytes') |
|
761 |
|
762 if isinstance(args, bytes): |
|
763 dictargs = {arg: b'legacy' for arg in args.split()} |
|
764 elif isinstance(args, dict): |
|
765 dictargs = args |
|
766 else: |
|
767 raise ValueError('args must be bytes or a dict') |
|
768 |
755 def register(func): |
769 def register(func): |
756 if 1 in transportversions: |
770 if 1 in transportversions: |
757 if name in commands: |
771 if name in commands: |
758 raise error.ProgrammingError('%s command already registered ' |
772 raise error.ProgrammingError('%s command already registered ' |
759 'for version 1' % name) |
773 'for version 1' % name) |
762 permission=permission) |
776 permission=permission) |
763 if 2 in transportversions: |
777 if 2 in transportversions: |
764 if name in commandsv2: |
778 if name in commandsv2: |
765 raise error.ProgrammingError('%s command already registered ' |
779 raise error.ProgrammingError('%s command already registered ' |
766 'for version 2' % name) |
780 'for version 2' % name) |
767 commandsv2[name] = commandentry(func, args=args, |
781 |
|
782 commandsv2[name] = commandentry(func, args=dictargs, |
768 transports=transports, |
783 transports=transports, |
769 permission=permission) |
784 permission=permission) |
770 |
785 |
771 return func |
786 return func |
772 return register |
787 return register |
1302 'compression': compression, |
1317 'compression': compression, |
1303 } |
1318 } |
1304 |
1319 |
1305 for command, entry in commandsv2.items(): |
1320 for command, entry in commandsv2.items(): |
1306 caps['commands'][command] = { |
1321 caps['commands'][command] = { |
1307 'args': sorted(entry.args.split()) if entry.args else [], |
1322 'args': entry.args, |
1308 'permissions': [entry.permission], |
1323 'permissions': [entry.permission], |
1309 } |
1324 } |
1310 |
1325 |
1311 return proto.addcapabilities(repo, caps) |
1326 return proto.addcapabilities(repo, caps) |
1312 |
1327 |
1323 def capabilitiesv2(repo, proto): |
1338 def capabilitiesv2(repo, proto): |
1324 caps = _capabilitiesv2(repo, proto) |
1339 caps = _capabilitiesv2(repo, proto) |
1325 |
1340 |
1326 return wireprototypes.cborresponse(caps) |
1341 return wireprototypes.cborresponse(caps) |
1327 |
1342 |
1328 @wireprotocommand('heads', args='publiconly', permission='pull', |
1343 @wireprotocommand('heads', |
|
1344 args={ |
|
1345 'publiconly': False, |
|
1346 }, |
|
1347 permission='pull', |
1329 transportpolicy=POLICY_V2_ONLY) |
1348 transportpolicy=POLICY_V2_ONLY) |
1330 def headsv2(repo, proto, publiconly=False): |
1349 def headsv2(repo, proto, publiconly=False): |
1331 if publiconly: |
1350 if publiconly: |
1332 repo = repo.filtered('immutable') |
1351 repo = repo.filtered('immutable') |
1333 |
1352 |
1334 return wireprototypes.cborresponse(repo.heads()) |
1353 return wireprototypes.cborresponse(repo.heads()) |
1335 |
1354 |
1336 @wireprotocommand('known', 'nodes', permission='pull', |
1355 @wireprotocommand('known', |
|
1356 args={ |
|
1357 'nodes': [b'deadbeef'], |
|
1358 }, |
|
1359 permission='pull', |
1337 transportpolicy=POLICY_V2_ONLY) |
1360 transportpolicy=POLICY_V2_ONLY) |
1338 def knownv2(repo, proto, nodes=None): |
1361 def knownv2(repo, proto, nodes=None): |
1339 nodes = nodes or [] |
1362 nodes = nodes or [] |
1340 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes)) |
1363 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes)) |
1341 return wireprototypes.cborresponse(result) |
1364 return wireprototypes.cborresponse(result) |
1342 |
1365 |
1343 @wireprotocommand('listkeys', 'namespace', permission='pull', |
1366 @wireprotocommand('listkeys', |
|
1367 args={ |
|
1368 'namespace': b'ns', |
|
1369 }, |
|
1370 permission='pull', |
1344 transportpolicy=POLICY_V2_ONLY) |
1371 transportpolicy=POLICY_V2_ONLY) |
1345 def listkeysv2(repo, proto, namespace=None): |
1372 def listkeysv2(repo, proto, namespace=None): |
1346 keys = repo.listkeys(encoding.tolocal(namespace)) |
1373 keys = repo.listkeys(encoding.tolocal(namespace)) |
1347 keys = {encoding.fromlocal(k): encoding.fromlocal(v) |
1374 keys = {encoding.fromlocal(k): encoding.fromlocal(v) |
1348 for k, v in keys.iteritems()} |
1375 for k, v in keys.iteritems()} |