comparison mercurial/dispatch.py @ 35225:7ce0ba3a1c32

dispatch: replace _earlygetopt(strip=True) with new parser The execution order in cmdalias.__init__() is adjusted to set stripped args to self.givenargs, which is no longer updated in place.
author Yuya Nishihara <yuya@tcha.org>
date Thu, 23 Nov 2017 23:18:56 +0900
parents 6e6d0a5b88e6
children 08f28f58f863
comparison
equal deleted inserted replaced
35224:6e6d0a5b88e6 35225:7ce0ba3a1c32
464 args = pycompat.shlexsplit(self.definition) 464 args = pycompat.shlexsplit(self.definition)
465 except ValueError as inst: 465 except ValueError as inst:
466 self.badalias = (_("error in definition for alias '%s': %s") 466 self.badalias = (_("error in definition for alias '%s': %s")
467 % (self.name, inst)) 467 % (self.name, inst))
468 return 468 return
469 earlyopts, args = _earlysplitopts(args)
470 if earlyopts:
471 self.badalias = (_("error in definition for alias '%s': %s may "
472 "only be given on the command line")
473 % (self.name, '/'.join(zip(*earlyopts)[0])))
474 return
469 self.cmdname = cmd = args.pop(0) 475 self.cmdname = cmd = args.pop(0)
470 self.givenargs = args 476 self.givenargs = args
471
472 for invalidarg in commands.earlyoptflags:
473 if _earlygetopt([invalidarg], args):
474 self.badalias = (_("error in definition for alias '%s': %s may "
475 "only be given on the command line")
476 % (self.name, invalidarg))
477 return
478 477
479 try: 478 try:
480 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1] 479 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
481 if len(tableentry) > 2: 480 if len(tableentry) > 2:
482 self.fn, self.opts, self.help = tableentry 481 self.fn, self.opts, self.help = tableentry
649 fancyopts.fancyopts(args, commands.globalopts, options, 648 fancyopts.fancyopts(args, commands.globalopts, options,
650 gnu=not ui.plain('strictflags'), early=True, 649 gnu=not ui.plain('strictflags'), early=True,
651 optaliases={'repository': ['repo']}) 650 optaliases={'repository': ['repo']})
652 return options 651 return options
653 652
654 def _earlygetopt(aliases, args, strip=True): 653 def _earlysplitopts(args):
655 """Return list of values for an option (or aliases). 654 """Split args into a list of possible early options and remainder args"""
656 655 shortoptions = 'R:'
657 The values are listed in the order they appear in args. 656 # TODO: perhaps 'debugger' should be included
658 The options and values are removed from args if strip=True. 657 longoptions = ['cwd=', 'repository=', 'repo=', 'config=']
659 658 return fancyopts.earlygetopt(args, shortoptions, longoptions,
660 >>> args = [b'x', b'--cwd', b'foo', b'y'] 659 gnu=True, keepsep=True)
661 >>> _earlygetopt([b'--cwd'], args), args
662 (['foo'], ['x', 'y'])
663
664 >>> args = [b'x', b'--cwd=bar', b'y']
665 >>> _earlygetopt([b'--cwd'], args), args
666 (['bar'], ['x', 'y'])
667
668 >>> args = [b'x', b'--cwd=bar', b'y']
669 >>> _earlygetopt([b'--cwd'], args, strip=False), args
670 (['bar'], ['x', '--cwd=bar', 'y'])
671
672 >>> args = [b'x', b'-R', b'foo', b'y']
673 >>> _earlygetopt([b'-R'], args), args
674 (['foo'], ['x', 'y'])
675
676 >>> args = [b'x', b'-R', b'foo', b'y']
677 >>> _earlygetopt([b'-R'], args, strip=False), args
678 (['foo'], ['x', '-R', 'foo', 'y'])
679
680 >>> args = [b'x', b'-Rbar', b'y']
681 >>> _earlygetopt([b'-R'], args), args
682 (['bar'], ['x', 'y'])
683
684 >>> args = [b'x', b'-Rbar', b'y']
685 >>> _earlygetopt([b'-R'], args, strip=False), args
686 (['bar'], ['x', '-Rbar', 'y'])
687
688 >>> args = [b'x', b'-R=bar', b'y']
689 >>> _earlygetopt([b'-R'], args), args
690 (['=bar'], ['x', 'y'])
691
692 >>> args = [b'x', b'-R', b'--', b'y']
693 >>> _earlygetopt([b'-R'], args), args
694 ([], ['x', '-R', '--', 'y'])
695 """
696 try:
697 argcount = args.index("--")
698 except ValueError:
699 argcount = len(args)
700 shortopts = [opt for opt in aliases if len(opt) == 2]
701 values = []
702 pos = 0
703 while pos < argcount:
704 fullarg = arg = args[pos]
705 equals = -1
706 if arg.startswith('--'):
707 equals = arg.find('=')
708 if equals > -1:
709 arg = arg[:equals]
710 if arg in aliases:
711 if equals > -1:
712 values.append(fullarg[equals + 1:])
713 if strip:
714 del args[pos]
715 argcount -= 1
716 else:
717 pos += 1
718 else:
719 if pos + 1 >= argcount:
720 # ignore and let getopt report an error if there is no value
721 break
722 values.append(args[pos + 1])
723 if strip:
724 del args[pos:pos + 2]
725 argcount -= 2
726 else:
727 pos += 2
728 elif arg[:2] in shortopts:
729 # short option can have no following space, e.g. hg log -Rfoo
730 values.append(args[pos][2:])
731 if strip:
732 del args[pos]
733 argcount -= 1
734 else:
735 pos += 1
736 else:
737 pos += 1
738 return values
739 660
740 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): 661 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
741 # run pre-hook, and abort if it fails 662 # run pre-hook, and abort if it fails
742 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs), 663 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
743 pats=cmdpats, opts=cmdoptions) 664 pats=cmdpats, opts=cmdoptions)
802 cmd = aliases[0] 723 cmd = aliases[0]
803 fn = entry[0] 724 fn = entry[0]
804 725
805 if cmd and util.safehasattr(fn, 'shell'): 726 if cmd and util.safehasattr(fn, 'shell'):
806 # shell alias shouldn't receive early options which are consumed by hg 727 # shell alias shouldn't receive early options which are consumed by hg
807 args = args[:] 728 _earlyopts, args = _earlysplitopts(args)
808 _earlygetopt(commands.earlyoptflags, args, strip=True)
809 d = lambda: fn(ui, *args[1:]) 729 d = lambda: fn(ui, *args[1:])
810 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, 730 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
811 [], {}) 731 [], {})
812 732
813 def _dispatch(req): 733 def _dispatch(req):