Mercurial > public > mercurial-scm > hg
comparison mercurial/wireproto.py @ 37541:3e5e37204b32
wireproto: disallow commands handlers for multiple transport versions
I think it will be more trouble than it is worth to code version 1
and version 2 command handlers to the same interface. It will feel
awkward to shoehorn functionality into e.g. the version 1 protocol
handler interface. This would likely constrain the ability for version
2 to evolve.
Previous commits introduced a clean separation between command handlers
for version 1 and version 2 transports. This commit reinforces that
separation by dropping support for having a single command handler
service both version 1 and version 2 transports.
Differential Revision: https://phab.mercurial-scm.org/D3208
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 09 Apr 2018 11:33:38 -0700 |
parents | 693cb3768943 |
children | 3a2367e6c6f2 |
comparison
equal
deleted
inserted
replaced
37540:693cb3768943 | 37541:3e5e37204b32 |
---|---|
695 | 695 |
696 return True | 696 return True |
697 | 697 |
698 # Constants specifying which transports a wire protocol command should be | 698 # Constants specifying which transports a wire protocol command should be |
699 # available on. For use with @wireprotocommand. | 699 # available on. For use with @wireprotocommand. |
700 POLICY_ALL = 'all' | |
701 POLICY_V1_ONLY = 'v1-only' | 700 POLICY_V1_ONLY = 'v1-only' |
702 POLICY_V2_ONLY = 'v2-only' | 701 POLICY_V2_ONLY = 'v2-only' |
703 | 702 |
704 # For version 1 transports. | 703 # For version 1 transports. |
705 commands = commanddict() | 704 commands = commanddict() |
706 | 705 |
707 # For version 2 transports. | 706 # For version 2 transports. |
708 commandsv2 = commanddict() | 707 commandsv2 = commanddict() |
709 | 708 |
710 def wireprotocommand(name, args='', transportpolicy=POLICY_V1_ONLY, | 709 def wireprotocommand(name, args=None, transportpolicy=POLICY_V1_ONLY, |
711 permission='push'): | 710 permission='push'): |
712 """Decorator to declare a wire protocol command. | 711 """Decorator to declare a wire protocol command. |
713 | 712 |
714 ``name`` is the name of the wire protocol command being provided. | 713 ``name`` is the name of the wire protocol command being provided. |
715 | 714 |
727 Can be ``push`` or ``pull``. These roughly map to read-write and read-only, | 726 Can be ``push`` or ``pull``. These roughly map to read-write and read-only, |
728 respectively. Default is to assume command requires ``push`` permissions | 727 respectively. Default is to assume command requires ``push`` permissions |
729 because otherwise commands not declaring their permissions could modify | 728 because otherwise commands not declaring their permissions could modify |
730 a repository that is supposed to be read-only. | 729 a repository that is supposed to be read-only. |
731 """ | 730 """ |
732 if transportpolicy == POLICY_ALL: | 731 if transportpolicy == POLICY_V1_ONLY: |
733 transports = set(wireprototypes.TRANSPORTS) | |
734 transportversions = {1, 2} | |
735 elif transportpolicy == POLICY_V1_ONLY: | |
736 transports = {k for k, v in wireprototypes.TRANSPORTS.items() | 732 transports = {k for k, v in wireprototypes.TRANSPORTS.items() |
737 if v['version'] == 1} | 733 if v['version'] == 1} |
738 transportversions = {1} | 734 transportversion = 1 |
739 elif transportpolicy == POLICY_V2_ONLY: | 735 elif transportpolicy == POLICY_V2_ONLY: |
740 transports = {k for k, v in wireprototypes.TRANSPORTS.items() | 736 transports = {k for k, v in wireprototypes.TRANSPORTS.items() |
741 if v['version'] == 2} | 737 if v['version'] == 2} |
742 transportversions = {2} | 738 transportversion = 2 |
743 else: | 739 else: |
744 raise error.ProgrammingError('invalid transport policy value: %s' % | 740 raise error.ProgrammingError('invalid transport policy value: %s' % |
745 transportpolicy) | 741 transportpolicy) |
746 | 742 |
747 # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to | 743 # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to |
753 if permission not in ('push', 'pull'): | 749 if permission not in ('push', 'pull'): |
754 raise error.ProgrammingError('invalid wire protocol permission; ' | 750 raise error.ProgrammingError('invalid wire protocol permission; ' |
755 'got %s; expected "push" or "pull"' % | 751 'got %s; expected "push" or "pull"' % |
756 permission) | 752 permission) |
757 | 753 |
758 if 1 in transportversions and not isinstance(args, bytes): | 754 if transportversion == 1: |
759 raise error.ProgrammingError('arguments for version 1 commands must ' | 755 if args is None: |
760 'be declared as bytes') | 756 args = '' |
761 | 757 |
762 if isinstance(args, bytes): | 758 if not isinstance(args, bytes): |
763 dictargs = {arg: b'legacy' for arg in args.split()} | 759 raise error.ProgrammingError('arguments for version 1 commands ' |
764 elif isinstance(args, dict): | 760 'must be declared as bytes') |
765 dictargs = args | 761 elif transportversion == 2: |
766 else: | 762 if args is None: |
767 raise ValueError('args must be bytes or a dict') | 763 args = {} |
764 | |
765 if not isinstance(args, dict): | |
766 raise error.ProgrammingError('arguments for version 2 commands ' | |
767 'must be declared as dicts') | |
768 | 768 |
769 def register(func): | 769 def register(func): |
770 if 1 in transportversions: | 770 if transportversion == 1: |
771 if name in commands: | 771 if name in commands: |
772 raise error.ProgrammingError('%s command already registered ' | 772 raise error.ProgrammingError('%s command already registered ' |
773 'for version 1' % name) | 773 'for version 1' % name) |
774 commands[name] = commandentry(func, args=args, | 774 commands[name] = commandentry(func, args=args, |
775 transports=transports, | 775 transports=transports, |
776 permission=permission) | 776 permission=permission) |
777 if 2 in transportversions: | 777 elif transportversion == 2: |
778 if name in commandsv2: | 778 if name in commandsv2: |
779 raise error.ProgrammingError('%s command already registered ' | 779 raise error.ProgrammingError('%s command already registered ' |
780 'for version 2' % name) | 780 'for version 2' % name) |
781 | 781 |
782 commandsv2[name] = commandentry(func, args=dictargs, | 782 commandsv2[name] = commandentry(func, args=args, |
783 transports=transports, | 783 transports=transports, |
784 permission=permission) | 784 permission=permission) |
785 else: | |
786 raise error.ProgrammingError('unhandled transport version: %d' % | |
787 transportversion) | |
785 | 788 |
786 return func | 789 return func |
787 return register | 790 return register |
788 | 791 |
789 # TODO define a more appropriate permissions type to use for this. | 792 # TODO define a more appropriate permissions type to use for this. |