Mercurial > public > mercurial-scm > hg
comparison mercurial/wireproto.py @ 36609:abc3b9801563
wireproto: allow wire protocol commands to declare transport support
Currently, wire protocol commands are exposed on all transports.
Some wire protocol commands are only supported or sensical on some
transports. In the future, new wire protocol commands may only be
available on new transports and legacy wire protocol commands may
not be available to newer transports.
This commit introduces a mechanism to allow @wireprotocommand to
declare transports for which they should not be available. The
mechanism for determining if a wire protocol command is available
for a given transport instance has been taught to take this knowledge
into account.
To help implement this feature, we add a dict to wireprototypes
declaring all wire transports and their metadata. There's probably
room to refactor the constants used to identify the wire protocols.
But that can be in another commit.
Differential Revision: https://phab.mercurial-scm.org/D2483
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 02 Mar 2018 09:47:37 -0500 |
parents | 1c16324fdf05 |
children | 6906547c8476 |
comparison
equal
deleted
inserted
replaced
36608:1151c731686e | 36609:abc3b9801563 |
---|---|
590 | 590 |
591 return compengines | 591 return compengines |
592 | 592 |
593 class commandentry(object): | 593 class commandentry(object): |
594 """Represents a declared wire protocol command.""" | 594 """Represents a declared wire protocol command.""" |
595 def __init__(self, func, args=''): | 595 def __init__(self, func, args='', transports=None): |
596 self.func = func | 596 self.func = func |
597 self.args = args | 597 self.args = args |
598 self.transports = transports or set() | |
598 | 599 |
599 def _merge(self, func, args): | 600 def _merge(self, func, args): |
600 """Merge this instance with an incoming 2-tuple. | 601 """Merge this instance with an incoming 2-tuple. |
601 | 602 |
602 This is called when a caller using the old 2-tuple API attempts | 603 This is called when a caller using the old 2-tuple API attempts |
603 to replace an instance. The incoming values are merged with | 604 to replace an instance. The incoming values are merged with |
604 data not captured by the 2-tuple and a new instance containing | 605 data not captured by the 2-tuple and a new instance containing |
605 the union of the two objects is returned. | 606 the union of the two objects is returned. |
606 """ | 607 """ |
607 return commandentry(func, args=args) | 608 return commandentry(func, args=args, transports=set(self.transports)) |
608 | 609 |
609 # Old code treats instances as 2-tuples. So expose that interface. | 610 # Old code treats instances as 2-tuples. So expose that interface. |
610 def __iter__(self): | 611 def __iter__(self): |
611 yield self.func | 612 yield self.func |
612 yield self.args | 613 yield self.args |
638 # doing this aren't aware of the new API that uses objects to store | 639 # doing this aren't aware of the new API that uses objects to store |
639 # command entries, we automatically merge old state with new. | 640 # command entries, we automatically merge old state with new. |
640 if k in self: | 641 if k in self: |
641 v = self[k]._merge(v[0], v[1]) | 642 v = self[k]._merge(v[0], v[1]) |
642 else: | 643 else: |
643 v = commandentry(v[0], args=v[1]) | 644 # Use default values from @wireprotocommand. |
645 v = commandentry(v[0], args=v[1], | |
646 transports=set(wireprototypes.TRANSPORTS)) | |
644 else: | 647 else: |
645 raise ValueError('command entries must be commandentry instances ' | 648 raise ValueError('command entries must be commandentry instances ' |
646 'or 2-tuples') | 649 'or 2-tuples') |
647 | 650 |
648 return super(commanddict, self).__setitem__(k, v) | 651 return super(commanddict, self).__setitem__(k, v) |
649 | 652 |
650 def commandavailable(self, command, proto): | 653 def commandavailable(self, command, proto): |
651 """Determine if a command is available for the requested protocol.""" | 654 """Determine if a command is available for the requested protocol.""" |
652 # For now, commands are available for all protocols. So do a simple | 655 assert proto.name in wireprototypes.TRANSPORTS |
653 # membership test. | 656 |
654 return command in self | 657 entry = self.get(command) |
658 | |
659 if not entry: | |
660 return False | |
661 | |
662 if proto.name not in entry.transports: | |
663 return False | |
664 | |
665 return True | |
666 | |
667 # Constants specifying which transports a wire protocol command should be | |
668 # available on. For use with @wireprotocommand. | |
669 POLICY_ALL = 'all' | |
670 POLICY_V1_ONLY = 'v1-only' | |
671 POLICY_V2_ONLY = 'v2-only' | |
655 | 672 |
656 commands = commanddict() | 673 commands = commanddict() |
657 | 674 |
658 def wireprotocommand(name, args=''): | 675 def wireprotocommand(name, args='', transportpolicy=POLICY_ALL): |
659 """Decorator to declare a wire protocol command. | 676 """Decorator to declare a wire protocol command. |
660 | 677 |
661 ``name`` is the name of the wire protocol command being provided. | 678 ``name`` is the name of the wire protocol command being provided. |
662 | 679 |
663 ``args`` is a space-delimited list of named arguments that the command | 680 ``args`` is a space-delimited list of named arguments that the command |
664 accepts. ``*`` is a special value that says to accept all arguments. | 681 accepts. ``*`` is a special value that says to accept all arguments. |
682 | |
683 ``transportpolicy`` is a POLICY_* constant denoting which transports | |
684 this wire protocol command should be exposed to. By default, commands | |
685 are exposed to all wire protocol transports. | |
665 """ | 686 """ |
687 if transportpolicy == POLICY_ALL: | |
688 transports = set(wireprototypes.TRANSPORTS) | |
689 elif transportpolicy == POLICY_V1_ONLY: | |
690 transports = {k for k, v in wireprototypes.TRANSPORTS.items() | |
691 if v['version'] == 1} | |
692 elif transportpolicy == POLICY_V2_ONLY: | |
693 transports = {k for k, v in wireprototypes.TRANSPORTS.items() | |
694 if v['version'] == 2} | |
695 else: | |
696 raise error.Abort(_('invalid transport policy value: %s') % | |
697 transportpolicy) | |
698 | |
666 def register(func): | 699 def register(func): |
667 commands[name] = commandentry(func, args=args) | 700 commands[name] = commandentry(func, args=args, transports=transports) |
668 return func | 701 return func |
669 return register | 702 return register |
670 | 703 |
671 @wireprotocommand('batch', 'cmds *') | 704 @wireprotocommand('batch', 'cmds *') |
672 def batch(repo, proto, cmds, others): | 705 def batch(repo, proto, cmds, others): |