mercurial/fancyopts.py
author Martijn Pieters <mj@zopatista.com>
Wed, 11 Jul 2018 14:28:13 +0100
changeset 38661 8ac0c9cd4c48
parent 37465 39e5e346eba7
child 43076 2372284d9457
permissions -rw-r--r--
fncache: avoid loading the filename cache when not actually modifying it With time, fncache can become very large. The mozilla-central repo for example, has a 31M and growing fncache file. Loading this file takes time (280ms for the mozilla-central repository). In many scenarios, we don't need to load fncache at all. For example, when committing changes to existing files, or pushing such commits to another clone. This patch detects when a name is added via store.vfs(), and only loads the cache if a) the data metadata file doesn't already exist, or b) when opening for appending, the data or metadata file exists but has size (a transaction rollback leaves behind such files). Benchmarks (run on Macos 10.13 on a 2017-model Macbook Pro with Core i7 2.9GHz and flash drive), each test without and with patch run 5 times: * committing to an existing file, against the mozilla-central repository. Baseline real time average 2.3736, with patch 1.9884. * unbundling a large changeset consisting *only* of existing-file modifications (159 revisions, 1050 modifications, mozilla-central 4a250a0e4f29:beea9ac7d823), into a clone limited to the ancestor revision of that revset). Baseline real time average 1.5048, with patch 1.3108.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8230
ec98f35e3e16 fancyopts: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7772
diff changeset
     1
# fancyopts.py - better command line parsing
ec98f35e3e16 fancyopts: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7772
diff changeset
     2
#
ec98f35e3e16 fancyopts: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7772
diff changeset
     3
#  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
ec98f35e3e16 fancyopts: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7772
diff changeset
     4
#
ec98f35e3e16 fancyopts: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7772
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 8366
diff changeset
     6
# GNU General Public License version 2 or any later version.
8230
ec98f35e3e16 fancyopts: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7772
diff changeset
     7
25947
6002e2d95e54 fancyopts: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25563
diff changeset
     8
from __future__ import absolute_import
6002e2d95e54 fancyopts: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25563
diff changeset
     9
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
    10
import abc
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    11
import functools
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    12
25947
6002e2d95e54 fancyopts: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25563
diff changeset
    13
from .i18n import _
30578
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29947
diff changeset
    14
from . import (
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29947
diff changeset
    15
    error,
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29947
diff changeset
    16
    pycompat,
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29947
diff changeset
    17
)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    18
29947
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    19
# Set of flags to not apply boolean negation logic on
32291
bd872f64a8ba cleanup: use set literals
Martin von Zweigbergk <martinvonz@google.com>
parents: 30578
diff changeset
    20
nevernegate = {
29947
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    21
    # avoid --no-noninteractive
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    22
    'noninteractive',
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    23
    # These two flags are special because they cause hg to do one
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    24
    # thing and then exit, and so aren't suitable for use in things
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    25
    # like aliases anyway.
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    26
    'help',
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    27
    'version',
32291
bd872f64a8ba cleanup: use set literals
Martin von Zweigbergk <martinvonz@google.com>
parents: 30578
diff changeset
    28
}
29947
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    29
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    30
def _earlyoptarg(arg, shortlist, namelist):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    31
    """Check if the given arg is a valid unabbreviated option
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    32
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    33
    Returns (flag_str, has_embedded_value?, embedded_value, takes_value?)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    34
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    35
    >>> def opt(arg):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    36
    ...     return _earlyoptarg(arg, b'R:q', [b'cwd=', b'debugger'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    37
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    38
    long form:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    39
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    40
    >>> opt(b'--cwd')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    41
    ('--cwd', False, '', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    42
    >>> opt(b'--cwd=')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    43
    ('--cwd', True, '', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    44
    >>> opt(b'--cwd=foo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    45
    ('--cwd', True, 'foo', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    46
    >>> opt(b'--debugger')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    47
    ('--debugger', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    48
    >>> opt(b'--debugger=')  # invalid but parsable
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    49
    ('--debugger', True, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    50
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    51
    short form:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    52
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    53
    >>> opt(b'-R')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    54
    ('-R', False, '', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    55
    >>> opt(b'-Rfoo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    56
    ('-R', True, 'foo', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    57
    >>> opt(b'-q')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    58
    ('-q', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    59
    >>> opt(b'-qfoo')  # invalid but parsable
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    60
    ('-q', True, 'foo', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    61
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    62
    unknown or invalid:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    63
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    64
    >>> opt(b'--unknown')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    65
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    66
    >>> opt(b'-u')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    67
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    68
    >>> opt(b'-ufoo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    69
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    70
    >>> opt(b'--')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    71
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    72
    >>> opt(b'-')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    73
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    74
    >>> opt(b'-:')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    75
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    76
    >>> opt(b'-:foo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    77
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    78
    """
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    79
    if arg.startswith('--'):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    80
        flag, eq, val = arg.partition('=')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    81
        if flag[2:] in namelist:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    82
            return flag, bool(eq), val, False
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    83
        if flag[2:] + '=' in namelist:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    84
            return flag, bool(eq), val, True
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    85
    elif arg.startswith('-') and arg != '-' and not arg.startswith('-:'):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    86
        flag, val = arg[:2], arg[2:]
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    87
        i = shortlist.find(flag[1:])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    88
        if i >= 0:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    89
            return flag, bool(val), val, shortlist.startswith(':', i + 1)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    90
    return '', False, '', False
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    91
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    92
def earlygetopt(args, shortlist, namelist, gnu=False, keepsep=False):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    93
    """Parse options like getopt, but ignores unknown options and abbreviated
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    94
    forms
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    95
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    96
    If gnu=False, this stops processing options as soon as a non/unknown-option
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    97
    argument is encountered. Otherwise, option and non-option arguments may be
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    98
    intermixed, and unknown-option arguments are taken as non-option.
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
    99
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   100
    If keepsep=True, '--' won't be removed from the list of arguments left.
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   101
    This is useful for stripping early options from a full command arguments.
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   102
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   103
    >>> def get(args, gnu=False, keepsep=False):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   104
    ...     return earlygetopt(args, b'R:q', [b'cwd=', b'debugger'],
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   105
    ...                        gnu=gnu, keepsep=keepsep)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   106
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   107
    default parsing rules for early options:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   108
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   109
    >>> get([b'x', b'--cwd', b'foo', b'-Rbar', b'-q', b'y'], gnu=True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   110
    ([('--cwd', 'foo'), ('-R', 'bar'), ('-q', '')], ['x', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   111
    >>> get([b'x', b'--cwd=foo', b'y', b'-R', b'bar', b'--debugger'], gnu=True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   112
    ([('--cwd', 'foo'), ('-R', 'bar'), ('--debugger', '')], ['x', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   113
    >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   114
    ([('--cwd', 'foo')], ['--unknown', '--debugger'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   115
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   116
    restricted parsing rules (early options must come first):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   117
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   118
    >>> get([b'--cwd', b'foo', b'-Rbar', b'x', b'-q', b'y'], gnu=False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   119
    ([('--cwd', 'foo'), ('-R', 'bar')], ['x', '-q', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   120
    >>> get([b'--cwd=foo', b'x', b'y', b'-R', b'bar', b'--debugger'], gnu=False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   121
    ([('--cwd', 'foo')], ['x', 'y', '-R', 'bar', '--debugger'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   122
    >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=False)
35227
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   123
    ([], ['--unknown', '--cwd=foo', '--', '--debugger'])
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   124
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   125
    stripping early options (without loosing '--'):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   126
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   127
    >>> get([b'x', b'-Rbar', b'--', '--debugger'], gnu=True, keepsep=True)[1]
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   128
    ['x', '--', '--debugger']
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   129
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   130
    last argument:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   131
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   132
    >>> get([b'--cwd'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   133
    ([], ['--cwd'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   134
    >>> get([b'--cwd=foo'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   135
    ([('--cwd', 'foo')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   136
    >>> get([b'-R'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   137
    ([], ['-R'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   138
    >>> get([b'-Rbar'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   139
    ([('-R', 'bar')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   140
    >>> get([b'-q'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   141
    ([('-q', '')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   142
    >>> get([b'-q', b'--'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   143
    ([('-q', '')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   144
35227
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   145
    '--' may be a value:
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   146
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   147
    >>> get([b'-R', b'--', b'x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   148
    ([('-R', '--')], ['x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   149
    >>> get([b'--cwd', b'--', b'x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   150
    ([('--cwd', '--')], ['x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   151
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   152
    value passed to bool options:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   153
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   154
    >>> get([b'--debugger=foo', b'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   155
    ([], ['--debugger=foo', 'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   156
    >>> get([b'-qfoo', b'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   157
    ([], ['-qfoo', 'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   158
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   159
    short option isn't separated with '=':
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   160
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   161
    >>> get([b'-R=bar'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   162
    ([('-R', '=bar')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   163
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   164
    ':' may be in shortlist, but shouldn't be taken as an option letter:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   165
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   166
    >>> get([b'-:', b'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   167
    ([], ['-:', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   168
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   169
    '-' is a valid non-option argument:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   170
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   171
    >>> get([b'-', b'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   172
    ([], ['-', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   173
    """
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   174
    parsedopts = []
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   175
    parsedargs = []
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   176
    pos = 0
35227
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   177
    while pos < len(args):
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   178
        arg = args[pos]
35227
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   179
        if arg == '--':
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   180
            pos += not keepsep
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   181
            break
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   182
        flag, hasval, val, takeval = _earlyoptarg(arg, shortlist, namelist)
35227
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   183
        if not hasval and takeval and pos + 1 >= len(args):
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   184
            # missing last argument
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   185
            break
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   186
        if not flag or hasval and not takeval:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   187
            # non-option argument or -b/--bool=INVALID_VALUE
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   188
            if gnu:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   189
                parsedargs.append(arg)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   190
                pos += 1
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   191
            else:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   192
                break
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   193
        elif hasval == takeval:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   194
            # -b/--bool or -s/--str=VALUE
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   195
            parsedopts.append((flag, val))
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   196
            pos += 1
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   197
        else:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   198
            # -s/--str VALUE
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   199
            parsedopts.append((flag, args[pos + 1]))
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   200
            pos += 2
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   201
35227
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35226
diff changeset
   202
    parsedargs.extend(args[pos:])
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   203
    return parsedopts, parsedargs
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   204
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   205
class customopt(object):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   206
    """Manage defaults and mutations for any type of opt."""
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   207
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   208
    __metaclass__ = abc.ABCMeta
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   209
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   210
    def __init__(self, defaultvalue):
37092
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   211
        self._defaultvalue = defaultvalue
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   212
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   213
    def _isboolopt(self):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   214
        return False
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   215
37092
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   216
    def getdefaultvalue(self):
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   217
        """Returns the default value for this opt.
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   218
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   219
        Subclasses should override this to return a new value if the value type
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   220
        is mutable."""
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   221
        return self._defaultvalue
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   222
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   223
    @abc.abstractmethod
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   224
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   225
        """Adds newparam to oldstate and returns the new state.
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   226
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   227
        On failure, abort can be called with a string error message."""
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   228
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   229
class _simpleopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   230
    def _isboolopt(self):
37092
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   231
        return isinstance(self._defaultvalue, (bool, type(None)))
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   232
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   233
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   234
        return newparam
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   235
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   236
class _callableopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   237
    def __init__(self, callablefn):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   238
        self.callablefn = callablefn
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   239
        super(_callableopt, self).__init__(None)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   240
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   241
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   242
        return self.callablefn(newparam)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   243
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   244
class _listopt(customopt):
37092
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   245
    def getdefaultvalue(self):
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   246
        return self._defaultvalue[:]
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   247
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   248
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   249
        oldstate.append(newparam)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   250
        return oldstate
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   251
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   252
class _intopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   253
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   254
        try:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   255
            return int(newparam)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   256
        except ValueError:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   257
            abort(_('expected int'))
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   258
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   259
def _defaultopt(default):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   260
    """Returns a default opt implementation, given a default value."""
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   261
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   262
    if isinstance(default, customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   263
        return default
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   264
    elif callable(default):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   265
        return _callableopt(default)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   266
    elif isinstance(default, list):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   267
        return _listopt(default[:])
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   268
    elif type(default) is type(1):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   269
        return _intopt(default)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   270
    else:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   271
        return _simpleopt(default)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   272
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   273
def fancyopts(args, options, state, gnu=False, early=False, optaliases=None):
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   274
    """
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   275
    read args, parse options, and store options in state
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   276
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   277
    each option is a tuple of:
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   278
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   279
      short option or ''
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   280
      long option
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   281
      default value
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   282
      description
11321
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   283
      option value label(optional)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   284
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   285
    option types include:
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   286
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   287
      boolean or none - option sets variable in state to true
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   288
      string - parameter string is stored in state
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   289
      list - parameter string is added to a list
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   290
      integer - parameter strings is stored as int
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   291
      function - call function with parameter
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   292
      customopt - subclass of 'customopt'
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   293
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   294
    optaliases is a mapping from a canonical option name to a list of
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   295
    additional long options. This exists for preserving backward compatibility
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   296
    of early options. If we want to use it extensively, please consider moving
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   297
    the functionality to the options table (e.g separate long options by '|'.)
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   298
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   299
    non-option args are returned
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   300
    """
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   301
    if optaliases is None:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   302
        optaliases = {}
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   303
    namelist = []
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   304
    shortlist = ''
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   305
    argmap = {}
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   306
    defmap = {}
29947
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   307
    negations = {}
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   308
    alllong = set(o[1] for o in options)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   309
11321
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   310
    for option in options:
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   311
        if len(option) == 5:
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   312
            short, name, default, comment, dummy = option
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   313
        else:
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   314
            short, name, default, comment = option
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   315
        # convert opts to getopt format
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   316
        onames = [name]
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   317
        onames.extend(optaliases.get(name, []))
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   318
        name = name.replace('-', '_')
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   319
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   320
        argmap['-' + short] = name
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   321
        for n in onames:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   322
            argmap['--' + n] = name
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   323
        defmap[name] = _defaultopt(default)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   324
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   325
        # copy defaults to state
37092
ef6215df2402 fancyopts: prevent mutation of the default value in customopts
Daniel Ploch <dploch@google.com>
parents: 36383
diff changeset
   326
        state[name] = defmap[name].getdefaultvalue()
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   327
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   328
        # does it take a parameter?
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   329
        if not defmap[name]._isboolopt():
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   330
            if short:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   331
                short += ':'
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   332
            onames = [n + '=' for n in onames]
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   333
        elif name not in nevernegate:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   334
            for n in onames:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   335
                if n.startswith('no-'):
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   336
                    insert = n[3:]
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   337
                else:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   338
                    insert = 'no-' + n
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   339
                # backout (as a practical example) has both --commit and
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   340
                # --no-commit options, so we don't want to allow the
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   341
                # negations of those flags.
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   342
                if insert not in alllong:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   343
                    assert ('--' + n) not in negations
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   344
                    negations['--' + insert] = '--' + n
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   345
                    namelist.append(insert)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   346
        if short:
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   347
            shortlist += short
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   348
        if name:
35223
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 35169
diff changeset
   349
            namelist.extend(onames)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   350
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   351
    # parse arguments
35169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   352
    if early:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   353
        parse = functools.partial(earlygetopt, gnu=gnu)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33103
diff changeset
   354
    elif gnu:
35226
5b569d512fbd fancyopts: use getopt.gnu_getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35223
diff changeset
   355
        parse = pycompat.gnugetoptb
7772
88887054d277 fancyopts: Parse options that occur after arguments.
Augie Fackler <durin42@gmail.com>
parents: 5878
diff changeset
   356
    else:
30578
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29947
diff changeset
   357
        parse = pycompat.getoptb
7772
88887054d277 fancyopts: Parse options that occur after arguments.
Augie Fackler <durin42@gmail.com>
parents: 5878
diff changeset
   358
    opts, args = parse(args, shortlist, namelist)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   359
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   360
    # transfer result to state
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   361
    for opt, val in opts:
29947
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   362
        boolval = True
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   363
        negation = negations.get(opt, False)
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   364
        if negation:
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   365
            opt = negation
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   366
            boolval = False
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   367
        name = argmap[opt]
25563
69e8384a436c fancyopts: allow all callable as default parameter value
introom <i@introo.me>
parents: 21794
diff changeset
   368
        obj = defmap[name]
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   369
        if obj._isboolopt():
29947
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   370
            state[name] = boolval
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   371
        else:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   372
            def abort(s):
37465
39e5e346eba7 py3: drop b'' from error message of fancyopts
Yuya Nishihara <yuya@tcha.org>
parents: 37092
diff changeset
   373
                raise error.Abort(_('invalid value %r for option %s, %s')
39e5e346eba7 py3: drop b'' from error message of fancyopts
Yuya Nishihara <yuya@tcha.org>
parents: 37092
diff changeset
   374
                                  % (pycompat.maybebytestr(val), opt, s))
36353
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35227
diff changeset
   375
            state[name] = defmap[name].newstate(state[name], val, abort)
209
63af1db35611 Beginning of new command parsing interface
mpm@selenic.com
parents: 164
diff changeset
   376
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   377
    # return unparsed args
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   378
    return args