mercurial/fancyopts.py
author Daniel Ploch <dploch@google.com>
Wed, 21 Feb 2018 20:05:29 -0800
changeset 36386 cc9d0763c8e9
parent 35236 98a5aa5575e7
child 36414 24b481668293
permissions -rw-r--r--
fancyopts: add support for custom multi-arg opts in fancyopts.py This allows for more complex multi-arg opt logic, such as "--sum 1 --sum 2" -> 3, "--csv alice,bob --csv charlie" -> ["alice","bob","charlie"]. The current support for callables is insufficient for this. This is done by introducing a 'customopt' class which can be extended for more powerful opts logic. All existing opt-types are converted to use this class, simplifying the fancyopts() logic. Differential Revision: https://phab.mercurial-scm.org/D2090
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
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
    10
import abc
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    11
import functools
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
    12
import types
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    13
25947
6002e2d95e54 fancyopts: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25563
diff changeset
    14
from .i18n import _
30583
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29951
diff changeset
    15
from . import (
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29951
diff changeset
    16
    error,
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29951
diff changeset
    17
    pycompat,
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29951
diff changeset
    18
)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
    19
29951
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    20
# Set of flags to not apply boolean negation logic on
32331
bd872f64a8ba cleanup: use set literals
Martin von Zweigbergk <martinvonz@google.com>
parents: 30583
diff changeset
    21
nevernegate = {
29951
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    22
    # avoid --no-noninteractive
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    23
    'noninteractive',
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    24
    # 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
    25
    # 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
    26
    # like aliases anyway.
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    27
    'help',
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    28
    'version',
32331
bd872f64a8ba cleanup: use set literals
Martin von Zweigbergk <martinvonz@google.com>
parents: 30583
diff changeset
    29
}
29951
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
    30
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    31
def _earlyoptarg(arg, shortlist, namelist):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    32
    """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: 33115
diff changeset
    33
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    34
    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: 33115
diff changeset
    35
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    36
    >>> def opt(arg):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    37
    ...     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: 33115
diff changeset
    38
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    39
    long form:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    40
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    41
    >>> opt(b'--cwd')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    42
    ('--cwd', False, '', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    43
    >>> opt(b'--cwd=')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    44
    ('--cwd', True, '', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    45
    >>> opt(b'--cwd=foo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    46
    ('--cwd', True, 'foo', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    47
    >>> opt(b'--debugger')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    48
    ('--debugger', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    49
    >>> opt(b'--debugger=')  # invalid but parsable
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    50
    ('--debugger', True, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    51
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    52
    short form:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    53
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    54
    >>> opt(b'-R')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    55
    ('-R', False, '', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    56
    >>> opt(b'-Rfoo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    57
    ('-R', True, 'foo', True)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    58
    >>> opt(b'-q')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    59
    ('-q', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    60
    >>> opt(b'-qfoo')  # invalid but parsable
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    61
    ('-q', True, 'foo', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    62
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    63
    unknown or invalid:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    64
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    65
    >>> opt(b'--unknown')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    66
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    67
    >>> opt(b'-u')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    68
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    69
    >>> opt(b'-ufoo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    70
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    71
    >>> opt(b'--')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    72
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    73
    >>> opt(b'-')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    74
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    75
    >>> opt(b'-:')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    76
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    77
    >>> opt(b'-:foo')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    78
    ('', False, '', False)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    79
    """
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    80
    if arg.startswith('--'):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    81
        flag, eq, val = arg.partition('=')
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    82
        if flag[2:] in namelist:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    83
            return flag, bool(eq), val, False
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    84
        if flag[2:] + '=' in namelist:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    85
            return flag, bool(eq), val, True
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    86
    elif arg.startswith('-') and arg != '-' and not arg.startswith('-:'):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    87
        flag, val = arg[:2], arg[2:]
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    88
        i = shortlist.find(flag[1:])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    89
        if i >= 0:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    90
            return flag, bool(val), val, shortlist.startswith(':', i + 1)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    91
    return '', False, '', False
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    92
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    93
def earlygetopt(args, shortlist, namelist, gnu=False, keepsep=False):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    94
    """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: 33115
diff changeset
    95
    forms
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    96
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
    97
    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: 33115
diff changeset
    98
    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: 33115
diff changeset
    99
    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: 33115
diff changeset
   100
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   101
    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: 33115
diff changeset
   102
    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: 33115
diff changeset
   103
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   104
    >>> def get(args, gnu=False, keepsep=False):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   105
    ...     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: 33115
diff changeset
   106
    ...                        gnu=gnu, keepsep=keepsep)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   107
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   108
    default parsing rules for early options:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   109
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   110
    >>> 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: 33115
diff changeset
   111
    ([('--cwd', 'foo'), ('-R', 'bar'), ('-q', '')], ['x', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   112
    >>> 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: 33115
diff changeset
   113
    ([('--cwd', 'foo'), ('-R', 'bar'), ('--debugger', '')], ['x', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   114
    >>> 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: 33115
diff changeset
   115
    ([('--cwd', 'foo')], ['--unknown', '--debugger'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   116
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   117
    restricted parsing rules (early options must come first):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   118
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   119
    >>> 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: 33115
diff changeset
   120
    ([('--cwd', 'foo'), ('-R', 'bar')], ['x', '-q', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   121
    >>> 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: 33115
diff changeset
   122
    ([('--cwd', 'foo')], ['x', 'y', '-R', 'bar', '--debugger'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   123
    >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=False)
35236
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   124
    ([], ['--unknown', '--cwd=foo', '--', '--debugger'])
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   125
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   126
    stripping early options (without loosing '--'):
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   127
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   128
    >>> 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: 33115
diff changeset
   129
    ['x', '--', '--debugger']
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   130
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   131
    last argument:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   132
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   133
    >>> get([b'--cwd'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   134
    ([], ['--cwd'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   135
    >>> get([b'--cwd=foo'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   136
    ([('--cwd', 'foo')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   137
    >>> get([b'-R'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   138
    ([], ['-R'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   139
    >>> get([b'-Rbar'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   140
    ([('-R', 'bar')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   141
    >>> get([b'-q'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   142
    ([('-q', '')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   143
    >>> get([b'-q', b'--'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   144
    ([('-q', '')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   145
35236
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   146
    '--' may be a value:
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   147
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   148
    >>> get([b'-R', b'--', b'x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   149
    ([('-R', '--')], ['x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   150
    >>> get([b'--cwd', b'--', b'x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   151
    ([('--cwd', '--')], ['x'])
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   152
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   153
    value passed to bool options:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   154
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   155
    >>> get([b'--debugger=foo', b'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   156
    ([], ['--debugger=foo', 'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   157
    >>> get([b'-qfoo', b'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   158
    ([], ['-qfoo', 'x'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   159
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   160
    short option isn't separated with '=':
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   161
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   162
    >>> get([b'-R=bar'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   163
    ([('-R', '=bar')], [])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   164
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   165
    ':' 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: 33115
diff changeset
   166
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   167
    >>> get([b'-:', b'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   168
    ([], ['-:', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   169
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   170
    '-' is a valid non-option argument:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   171
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   172
    >>> get([b'-', b'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   173
    ([], ['-', 'y'])
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   174
    """
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   175
    parsedopts = []
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   176
    parsedargs = []
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   177
    pos = 0
35236
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   178
    while pos < len(args):
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   179
        arg = args[pos]
35236
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   180
        if arg == '--':
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   181
            pos += not keepsep
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   182
            break
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   183
        flag, hasval, val, takeval = _earlyoptarg(arg, shortlist, namelist)
35236
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   184
        if not hasval and takeval and pos + 1 >= len(args):
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   185
            # missing last argument
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   186
            break
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   187
        if not flag or hasval and not takeval:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   188
            # non-option argument or -b/--bool=INVALID_VALUE
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   189
            if gnu:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   190
                parsedargs.append(arg)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   191
                pos += 1
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   192
            else:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   193
                break
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   194
        elif hasval == takeval:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   195
            # -b/--bool or -s/--str=VALUE
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   196
            parsedopts.append((flag, val))
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   197
            pos += 1
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   198
        else:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   199
            # -s/--str VALUE
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   200
            parsedopts.append((flag, args[pos + 1]))
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   201
            pos += 2
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   202
35236
98a5aa5575e7 fancyopts: fix handling of "--" value in earlygetopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35235
diff changeset
   203
    parsedargs.extend(args[pos:])
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   204
    return parsedopts, parsedargs
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   205
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   206
class customopt(object):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   207
    """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: 35236
diff changeset
   208
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   209
    __metaclass__ = abc.ABCMeta
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   210
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   211
    def __init__(self, defaultvalue):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   212
        self.defaultvalue = defaultvalue
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   213
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   214
    def _isboolopt(self):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   215
        return False
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   216
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   217
    @abc.abstractmethod
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   218
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   219
        """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: 35236
diff changeset
   220
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   221
        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: 35236
diff changeset
   222
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   223
class _simpleopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   224
    def _isboolopt(self):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   225
        return isinstance(self.defaultvalue, (bool, types.NoneType))
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   226
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   227
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   228
        return newparam
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   229
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   230
class _callableopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   231
    def __init__(self, callablefn):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   232
        self.callablefn = callablefn
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   233
        super(_callableopt, self).__init__(None)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   234
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   235
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   236
        return self.callablefn(newparam)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   237
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   238
class _listopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   239
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   240
        oldstate.append(newparam)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   241
        return oldstate
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   242
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   243
class _intopt(customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   244
    def newstate(self, oldstate, newparam, abort):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   245
        try:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   246
            return int(newparam)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   247
        except ValueError:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   248
            abort(_('expected int'))
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   249
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   250
def _defaultopt(default):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   251
    """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: 35236
diff changeset
   252
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   253
    if isinstance(default, customopt):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   254
        return default
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   255
    elif callable(default):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   256
        return _callableopt(default)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   257
    elif isinstance(default, list):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   258
        return _listopt(default[:])
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   259
    elif type(default) is type(1):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   260
        return _intopt(default)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   261
    else:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   262
        return _simpleopt(default)
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   263
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   264
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
   265
    """
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   266
    read args, parse options, and store options in state
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   267
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   268
    each option is a tuple of:
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   269
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   270
      short option or ''
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   271
      long option
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   272
      default value
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   273
      description
11321
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   274
      option value label(optional)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   275
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   276
    option types include:
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   277
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   278
      boolean or none - option sets variable in state to true
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   279
      string - parameter string is stored in state
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   280
      list - parameter string is added to a list
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   281
      integer - parameter strings is stored as int
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   282
      function - call function with parameter
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   283
      customopt - subclass of 'customopt'
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   284
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   285
    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: 34995
diff changeset
   286
    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: 34995
diff changeset
   287
    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: 34995
diff changeset
   288
    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: 34995
diff changeset
   289
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   290
    non-option args are returned
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   291
    """
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   292
    if optaliases is None:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   293
        optaliases = {}
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   294
    namelist = []
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   295
    shortlist = ''
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   296
    argmap = {}
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   297
    defmap = {}
29951
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   298
    negations = {}
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   299
    alllong = set(o[1] for o in options)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   300
11321
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   301
    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
   302
        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
   303
            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
   304
        else:
40c06bbf58be help: show value requirement and multiple occurrence of options
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10282
diff changeset
   305
            short, name, default, comment = option
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   306
        # convert opts to getopt format
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   307
        onames = [name]
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   308
        onames.extend(optaliases.get(name, []))
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   309
        name = name.replace('-', '_')
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   310
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   311
        argmap['-' + short] = name
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   312
        for n in onames:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   313
            argmap['--' + n] = name
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   314
        defmap[name] = _defaultopt(default)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   315
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   316
        # copy defaults to state
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   317
        state[name] = defmap[name].defaultvalue
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   318
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   319
        # does it take a parameter?
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   320
        if not defmap[name]._isboolopt():
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   321
            if short:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   322
                short += ':'
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   323
            onames = [n + '=' for n in onames]
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   324
        elif name not in nevernegate:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   325
            for n in onames:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   326
                if n.startswith('no-'):
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   327
                    insert = n[3:]
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   328
                else:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   329
                    insert = 'no-' + n
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   330
                # 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: 34995
diff changeset
   331
                # --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: 34995
diff changeset
   332
                # negations of those flags.
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   333
                if insert not in alllong:
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   334
                    assert ('--' + n) not in negations
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   335
                    negations['--' + insert] = '--' + n
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   336
                    namelist.append(insert)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   337
        if short:
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   338
            shortlist += short
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   339
        if name:
35232
4edd2202f7d7 dispatch: alias --repo to --repository while parsing early options
Yuya Nishihara <yuya@tcha.org>
parents: 34995
diff changeset
   340
            namelist.extend(onames)
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   341
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   342
    # parse arguments
34995
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   343
    if early:
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   344
        parse = functools.partial(earlygetopt, gnu=gnu)
898c6f812a51 fancyopts: add early-options parser compatible with getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 33115
diff changeset
   345
    elif gnu:
35235
5b569d512fbd fancyopts: use getopt.gnu_getopt()
Yuya Nishihara <yuya@tcha.org>
parents: 35232
diff changeset
   346
        parse = pycompat.gnugetoptb
7772
88887054d277 fancyopts: Parse options that occur after arguments.
Augie Fackler <durin42@gmail.com>
parents: 5878
diff changeset
   347
    else:
30583
c6ce11f2ee50 py3: make a bytes version of getopt.getopt()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29951
diff changeset
   348
        parse = pycompat.getoptb
7772
88887054d277 fancyopts: Parse options that occur after arguments.
Augie Fackler <durin42@gmail.com>
parents: 5878
diff changeset
   349
    opts, args = parse(args, shortlist, namelist)
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   350
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   351
    # transfer result to state
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   352
    for opt, val in opts:
29951
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   353
        boolval = True
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   354
        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
   355
        if negation:
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   356
            opt = negation
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   357
            boolval = False
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   358
        name = argmap[opt]
25563
69e8384a436c fancyopts: allow all callable as default parameter value
introom <i@introo.me>
parents: 21794
diff changeset
   359
        obj = defmap[name]
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   360
        if obj._isboolopt():
29951
e1f0ec0b7d2d flags: allow specifying --no-boolean-flag on the command line (BC)
Augie Fackler <augie@google.com>
parents: 26587
diff changeset
   361
            state[name] = boolval
36386
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   362
        else:
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   363
            def abort(s):
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   364
                raise error.Abort(
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   365
                    _('invalid value %r for option %s, %s') % (val, opt, s))
cc9d0763c8e9 fancyopts: add support for custom multi-arg opts in fancyopts.py
Daniel Ploch <dploch@google.com>
parents: 35236
diff changeset
   366
            state[name] = defmap[name].newstate(state[name], val, abort)
209
63af1db35611 Beginning of new command parsing interface
mpm@selenic.com
parents: 164
diff changeset
   367
5638
a9b7e425674f fancyopts: lots of cleanups
Matt Mackall <mpm@selenic.com>
parents: 5093
diff changeset
   368
    # return unparsed args
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
   369
    return args