# HG changeset patch # User Yuya Nishihara # Date 1511446736 -32400 # Node ID 7ce0ba3a1c325eb89fe23e8dfe4bac163a1a879d # Parent 6e6d0a5b88e6fedf9b8b464d8e95082e09b0ba1d 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. diff -r 6e6d0a5b88e6 -r 7ce0ba3a1c32 mercurial/commands.py --- a/mercurial/commands.py Thu Nov 23 22:23:59 2017 +0900 +++ b/mercurial/commands.py Thu Nov 23 23:18:56 2017 +0900 @@ -103,10 +103,6 @@ _("when to paginate (boolean, always, auto, or never)"), _('TYPE')), ] -# options which must be pre-parsed before loading configs and extensions -# TODO: perhaps --debugger should be included -earlyoptflags = ("--cwd", "-R", "--repository", "--repo", "--config") - dryrunopts = cmdutil.dryrunopts remoteopts = cmdutil.remoteopts walkopts = cmdutil.walkopts diff -r 6e6d0a5b88e6 -r 7ce0ba3a1c32 mercurial/dispatch.py --- a/mercurial/dispatch.py Thu Nov 23 22:23:59 2017 +0900 +++ b/mercurial/dispatch.py Thu Nov 23 23:18:56 2017 +0900 @@ -466,16 +466,15 @@ self.badalias = (_("error in definition for alias '%s': %s") % (self.name, inst)) return + earlyopts, args = _earlysplitopts(args) + if earlyopts: + self.badalias = (_("error in definition for alias '%s': %s may " + "only be given on the command line") + % (self.name, '/'.join(zip(*earlyopts)[0]))) + return self.cmdname = cmd = args.pop(0) self.givenargs = args - for invalidarg in commands.earlyoptflags: - if _earlygetopt([invalidarg], args): - self.badalias = (_("error in definition for alias '%s': %s may " - "only be given on the command line") - % (self.name, invalidarg)) - return - try: tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1] if len(tableentry) > 2: @@ -651,91 +650,13 @@ optaliases={'repository': ['repo']}) return options -def _earlygetopt(aliases, args, strip=True): - """Return list of values for an option (or aliases). - - The values are listed in the order they appear in args. - The options and values are removed from args if strip=True. - - >>> args = [b'x', b'--cwd', b'foo', b'y'] - >>> _earlygetopt([b'--cwd'], args), args - (['foo'], ['x', 'y']) - - >>> args = [b'x', b'--cwd=bar', b'y'] - >>> _earlygetopt([b'--cwd'], args), args - (['bar'], ['x', 'y']) - - >>> args = [b'x', b'--cwd=bar', b'y'] - >>> _earlygetopt([b'--cwd'], args, strip=False), args - (['bar'], ['x', '--cwd=bar', 'y']) - - >>> args = [b'x', b'-R', b'foo', b'y'] - >>> _earlygetopt([b'-R'], args), args - (['foo'], ['x', 'y']) - - >>> args = [b'x', b'-R', b'foo', b'y'] - >>> _earlygetopt([b'-R'], args, strip=False), args - (['foo'], ['x', '-R', 'foo', 'y']) - - >>> args = [b'x', b'-Rbar', b'y'] - >>> _earlygetopt([b'-R'], args), args - (['bar'], ['x', 'y']) - - >>> args = [b'x', b'-Rbar', b'y'] - >>> _earlygetopt([b'-R'], args, strip=False), args - (['bar'], ['x', '-Rbar', 'y']) - - >>> args = [b'x', b'-R=bar', b'y'] - >>> _earlygetopt([b'-R'], args), args - (['=bar'], ['x', 'y']) - - >>> args = [b'x', b'-R', b'--', b'y'] - >>> _earlygetopt([b'-R'], args), args - ([], ['x', '-R', '--', 'y']) - """ - try: - argcount = args.index("--") - except ValueError: - argcount = len(args) - shortopts = [opt for opt in aliases if len(opt) == 2] - values = [] - pos = 0 - while pos < argcount: - fullarg = arg = args[pos] - equals = -1 - if arg.startswith('--'): - equals = arg.find('=') - if equals > -1: - arg = arg[:equals] - if arg in aliases: - if equals > -1: - values.append(fullarg[equals + 1:]) - if strip: - del args[pos] - argcount -= 1 - else: - pos += 1 - else: - if pos + 1 >= argcount: - # ignore and let getopt report an error if there is no value - break - values.append(args[pos + 1]) - if strip: - del args[pos:pos + 2] - argcount -= 2 - else: - pos += 2 - elif arg[:2] in shortopts: - # short option can have no following space, e.g. hg log -Rfoo - values.append(args[pos][2:]) - if strip: - del args[pos] - argcount -= 1 - else: - pos += 1 - else: - pos += 1 - return values +def _earlysplitopts(args): + """Split args into a list of possible early options and remainder args""" + shortoptions = 'R:' + # TODO: perhaps 'debugger' should be included + longoptions = ['cwd=', 'repository=', 'repo=', 'config='] + return fancyopts.earlygetopt(args, shortoptions, longoptions, + gnu=True, keepsep=True) def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): # run pre-hook, and abort if it fails @@ -804,8 +725,7 @@ if cmd and util.safehasattr(fn, 'shell'): # shell alias shouldn't receive early options which are consumed by hg - args = args[:] - _earlygetopt(commands.earlyoptflags, args, strip=True) + _earlyopts, args = _earlysplitopts(args) d = lambda: fn(ui, *args[1:]) return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {}) diff -r 6e6d0a5b88e6 -r 7ce0ba3a1c32 tests/test-alias.t --- a/tests/test-alias.t Thu Nov 23 22:23:59 2017 +0900 +++ b/tests/test-alias.t Thu Nov 23 23:18:56 2017 +0900 @@ -119,6 +119,12 @@ $ hg help noclosing error in definition for alias 'noclosingquotation': No closing quotation +"--" in alias definition should be preserved + + $ hg --config alias.dash='cat --' -R alias dash -r0 + abort: -r0 not under root '$TESTTMP/alias' + (consider using '--cwd alias') + [255] invalid options @@ -148,6 +154,12 @@ $ hg no--config abort: error in definition for alias 'no--config': --config may only be given on the command line [255] + $ hg no --config alias.no='--repo elsewhere --cwd elsewhere status' + abort: error in definition for alias 'no': --repo/--cwd may only be given on the command line + [255] + $ hg no --config alias.no='--repo elsewhere' + abort: error in definition for alias 'no': --repo may only be given on the command line + [255] optional repository @@ -351,6 +363,10 @@ $ hg echoall --cwd .. +"--" passed to shell alias should be preserved + + $ hg --config alias.printf='!printf "$@"' printf '%s %s %s\n' -- --cwd .. + -- --cwd .. repo specific shell aliases