Blame dnf/cli/option_parser.py

Packit 6f3914
# optparse.py
Packit 6f3914
# CLI options parser.
Packit 6f3914
#
Packit 6f3914
# Copyright (C) 2014-2016 Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
# This copyrighted material is made available to anyone wishing to use,
Packit 6f3914
# modify, copy, or redistribute it subject to the terms and conditions of
Packit 6f3914
# the GNU General Public License v.2, or (at your option) any later version.
Packit 6f3914
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit 6f3914
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit 6f3914
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 6f3914
# Public License for more details.  You should have received a copy of the
Packit 6f3914
# GNU General Public License along with this program; if not, write to the
Packit 6f3914
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6f3914
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit 6f3914
# source code or documentation are not subject to the GNU General Public
Packit 6f3914
# License and may only be used or replicated with the express permission of
Packit 6f3914
# Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
Packit 6f3914
from __future__ import unicode_literals
Packit 6f3914
from dnf.i18n import _
Packit 6f3914
from dnf.util import _parse_specs
Packit 6f3914
Packit 6f3914
import argparse
Packit 6f3914
import dnf.exceptions
Packit 6f3914
import dnf.util
Packit 6f3914
import dnf.rpm
Packit 6f3914
import dnf.yum.misc
Packit 6f3914
import logging
Packit 6f3914
import os.path
Packit 6f3914
import re
Packit 6f3914
import sys
Packit 6f3914
Packit 6f3914
logger = logging.getLogger("dnf")
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MultilineHelpFormatter(argparse.HelpFormatter):
Packit 6f3914
    def _split_lines(self, text, width):
Packit 6f3914
        if '\n' in text:
Packit 6f3914
            return text.splitlines()
Packit 6f3914
        return super(MultilineHelpFormatter, self)._split_lines(text, width)
Packit 6f3914
Packit 6f3914
class OptionParser(argparse.ArgumentParser):
Packit 6f3914
    """ArgumentParser like class to do things the "yum way"."""
Packit 6f3914
Packit 6f3914
    def __init__(self, reset_usage=True):
Packit 6f3914
        super(OptionParser, self).__init__(add_help=False,
Packit 6f3914
                                           formatter_class=MultilineHelpFormatter)
Packit 6f3914
        self.command_positional_parser = None
Packit 6f3914
        self.command_group = None
Packit 6f3914
        self._add_general_options()
Packit 6f3914
        if reset_usage:
Packit 6f3914
            self._cmd_usage = {}      # names, summary for dnf commands, to build usage
Packit 6f3914
            self._cmd_groups = set()  # cmd groups added (main, plugin)
Packit 6f3914
Packit 6f3914
    def error(self, msg):
Packit 6f3914
        """Output an error message, and exit the program.
Packit 6f3914
           This method overrides standard argparser's error
Packit 6f3914
           so that error output goes to the logger.
Packit 6f3914
Packit 6f3914
        :param msg: the error message to output
Packit 6f3914
        """
Packit 6f3914
        self.print_usage()
Packit 6f3914
        logger.critical(_("Command line error: %s"), msg)
Packit 6f3914
        sys.exit(1)
Packit 6f3914
Packit 6f3914
    class _RepoCallback(argparse.Action):
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            operation = 'disable' if opt_str == '--disablerepo' else 'enable'
Packit 6f3914
            l = getattr(namespace, self.dest)
Packit 6f3914
            l.extend((x, operation) for x in re.split(r'\s*[,\s]\s*', values))
Packit 6f3914
Packit 6f3914
    class _RepoCallbackEnable(argparse.Action):
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            namespace.repos_ed.append((values[0], 'enable'))
Packit 6f3914
            setattr(namespace, 'reponame', values)
Packit 6f3914
Packit 6f3914
    class _SplitCallback(argparse._AppendAction):
Packit 6f3914
        """ Split all strings in seq, at "," and whitespace.
Packit 6f3914
        Returns a new list. """
Packit 6f3914
        SPLITTER = r'\s*[,\s]\s*'
Packit 6f3914
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            for val in re.split(self.SPLITTER, values):
Packit 6f3914
                super(OptionParser._SplitCallback,
Packit 6f3914
                      self).__call__(parser, namespace, val, opt_str)
Packit 6f3914
Packit 6f3914
    class _SplitExtendDictCallback(argparse.Action):
Packit 6f3914
        """ Split string at "," or whitespace to (key, value).
Packit 6f3914
        Extends dict with {key: value}."""
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            try:
Packit 6f3914
                key, val = values.split(',')
Packit 6f3914
                if not key or not val:
Packit 6f3914
                    raise ValueError
Packit 6f3914
            except ValueError:
Packit 6f3914
                msg = _('bad format: %s') % values
Packit 6f3914
                raise argparse.ArgumentError(self, msg)
Packit 6f3914
            dct = getattr(namespace, self.dest)
Packit 6f3914
            dct[key] = val
Packit 6f3914
Packit 6f3914
    class _SetoptsCallback(argparse.Action):
Packit 6f3914
        """ Parse setopts arguments and put them into main_<setopts>
Packit 6f3914
            and repo_<setopts>."""
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            vals = values.split('=')
Packit 6f3914
            if len(vals) > 2:
Packit 6f3914
                logger.warning(_("Setopt argument has multiple values: %s"), values)
Packit 6f3914
                return
Packit 6f3914
            if len(vals) < 2:
Packit 6f3914
                logger.warning(_("Setopt argument has no value: %s"), values)
Packit 6f3914
                return
Packit 6f3914
            k, v = vals
Packit 6f3914
            period = k.rfind('.')
Packit 6f3914
            if period != -1:
Packit 6f3914
                repo = k[:period]
Packit 6f3914
                k = k[period+1:]
Packit 6f3914
                if hasattr(namespace, 'repo_setopts'):
Packit 6f3914
                    repoopts = namespace.repo_setopts
Packit 6f3914
                else:
Packit 6f3914
                    repoopts = {}
Packit 6f3914
                repoopts.setdefault(repo, {}).setdefault(k, []).append(v)
Packit 6f3914
                setattr(namespace, 'repo_' + self.dest, repoopts)
Packit 6f3914
            else:
Packit 6f3914
                if hasattr(namespace, 'main_setopts'):
Packit 6f3914
                    mainopts = namespace.main_setopts
Packit 6f3914
                else:
Packit 6f3914
                    mainopts = {}
Packit 6f3914
                mainopts.setdefault(k, []).append(v)
Packit 6f3914
                setattr(namespace, 'main_' + self.dest, mainopts)
Packit 6f3914
Packit 6f3914
    class ParseSpecGroupFileCallback(argparse.Action):
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            _parse_specs(namespace, values)
Packit 6f3914
Packit 6f3914
    class PkgNarrowCallback(argparse.Action):
Packit 6f3914
        def __init__(self, *args, **kwargs):
Packit 6f3914
            self.pkgnarrow = {}
Packit 6f3914
            try:
Packit 6f3914
                for k in ['choices', 'default']:
Packit 6f3914
                    self.pkgnarrow[k] = kwargs[k]
Packit 6f3914
                    del kwargs[k]
Packit 6f3914
            except KeyError as e:
Packit 6f3914
                raise TypeError("%s() missing mandatory argument %s"
Packit 6f3914
                                % (self.__class__.__name__, e))
Packit 6f3914
            kwargs['default'] = []
Packit 6f3914
            super(OptionParser.PkgNarrowCallback, self).__init__(*args, **kwargs)
Packit 6f3914
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            dest_action = self.dest + '_action'
Packit 6f3914
            if not values or values[0] not in self.pkgnarrow['choices']:
Packit 6f3914
                narrow = self.pkgnarrow['default']
Packit 6f3914
            else:
Packit 6f3914
                narrow = values.pop(0)
Packit 6f3914
            setattr(namespace, dest_action, narrow)
Packit 6f3914
            setattr(namespace, self.dest, values)
Packit 6f3914
Packit 6f3914
    class ForceArchAction(argparse.Action):
Packit 6f3914
        def __call__(self, parser, namespace, values, opt_str):
Packit 6f3914
            namespace.ignorearch = True
Packit 6f3914
            namespace.arch = values
Packit 6f3914
Packit 6f3914
    def _add_general_options(self):
Packit 6f3914
        """ Standard options known to all dnf subcommands. """
Packit 6f3914
        # All defaults need to be a None, so we can always tell whether the user
Packit 6f3914
        # has set something or whether we are getting a default.
Packit 6f3914
        general_grp = self.add_argument_group(_('General {prog} options'.format(
Packit 6f3914
            prog=dnf.util.MAIN_PROG_UPPER)))
Packit 6f3914
        general_grp.add_argument("-c", "--config", dest="config_file_path",
Packit 6f3914
                                 default=None, metavar='[config file]',
Packit 6f3914
                                 help=_("config file location"))
Packit 6f3914
        general_grp.add_argument("-q", "--quiet", dest="quiet",
Packit 6f3914
                                 action="store_true", default=None,
Packit 6f3914
                                 help=_("quiet operation"))
Packit 6f3914
        general_grp.add_argument("-v", "--verbose", action="store_true",
Packit 6f3914
                                 default=None, help=_("verbose operation"))
Packit 6f3914
        general_grp.add_argument("--version", action="store_true", default=None,
Packit 6f3914
                                 help=_("show {prog} version and exit").format(
Packit 6f3914
                                     prog=dnf.util.MAIN_PROG_UPPER))
Packit 6f3914
        general_grp.add_argument("--installroot", help=_("set install root"),
Packit 6f3914
                                 metavar='[path]')
Packit 6f3914
        general_grp.add_argument("--nodocs", action="store_const", const=['nodocs'], dest='tsflags',
Packit 6f3914
                                 help=_("do not install documentations"))
Packit 6f3914
        general_grp.add_argument("--noplugins", action="store_false",
Packit 6f3914
                                 default=None, dest='plugins',
Packit 6f3914
                                 help=_("disable all plugins"))
Packit 6f3914
        general_grp.add_argument("--enableplugin", dest="enableplugin",
Packit 6f3914
                                 default=[], action=self._SplitCallback,
Packit 6f3914
                                 help=_("enable plugins by name"),
Packit 6f3914
                                 metavar='[plugin]')
Packit 6f3914
        general_grp.add_argument("--disableplugin", dest="disableplugin",
Packit 6f3914
                                 default=[], action=self._SplitCallback,
Packit 6f3914
                                 help=_("disable plugins by name"),
Packit 6f3914
                                 metavar='[plugin]')
Packit 6f3914
        general_grp.add_argument("--releasever", default=None,
Packit 6f3914
                                 help=_("override the value of $releasever"
Packit 6f3914
                                        " in config and repo files"))
Packit 6f3914
        general_grp.add_argument("--setopt", dest="setopts", default=[],
Packit 6f3914
                                 action=self._SetoptsCallback,
Packit 6f3914
                                 help=_("set arbitrary config and repo options"))
Packit 6f3914
        general_grp.add_argument("--skip-broken", dest="skip_broken", action="store_true",
Packit 6f3914
                                 default=None,
Packit 6f3914
                                 help=_("resolve depsolve problems by skipping packages"))
Packit 6f3914
        general_grp.add_argument('-h', '--help', '--help-cmd',
Packit 6f3914
                                 action="store_true", dest='help',
Packit 6f3914
                                 help=_("show command help"))
Packit 6f3914
Packit 6f3914
        general_grp.add_argument('--allowerasing', action='store_true',
Packit 6f3914
                                 default=None,
Packit 6f3914
                                 help=_('allow erasing of installed packages to '
Packit 6f3914
                                        'resolve dependencies'))
Packit 6f3914
        best_group = general_grp.add_mutually_exclusive_group()
Packit 6f3914
        best_group.add_argument("-b", "--best", action="store_true", dest='best', default=None,
Packit 6f3914
                                help=_("try the best available package versions in transactions."))
Packit 6f3914
        best_group.add_argument("--nobest", action="store_false", dest='best',
Packit 6f3914
                                help=_("do not limit the transaction to the best candidate"))
Packit 6f3914
        general_grp.add_argument("-C", "--cacheonly", dest="cacheonly",
Packit 6f3914
                                 action="store_true", default=None,
Packit 6f3914
                                 help=_("run entirely from system cache, "
Packit 6f3914
                                        "don't update cache"))
Packit 6f3914
        general_grp.add_argument("-R", "--randomwait", dest="sleeptime", type=int,
Packit 6f3914
                                 default=None, metavar='[minutes]',
Packit 6f3914
                                 help=_("maximum command wait time"))
Packit 6f3914
        general_grp.add_argument("-d", "--debuglevel", dest="debuglevel",
Packit 6f3914
                                 metavar='[debug level]', default=None,
Packit 6f3914
                                 help=_("debugging output level"), type=int)
Packit 6f3914
        general_grp.add_argument("--debugsolver",
Packit 6f3914
                                 action="store_true", default=None,
Packit 6f3914
                                 help=_("dumps detailed solving results into"
Packit 6f3914
                                        " files"))
Packit 6f3914
        general_grp.add_argument("--showduplicates", dest="showdupesfromrepos",
Packit 6f3914
                                 action="store_true", default=None,
Packit 6f3914
                                 help=_("show duplicates, in repos, "
Packit 6f3914
                                        "in list/search commands"))
Packit 6f3914
        general_grp.add_argument("-e", "--errorlevel", default=None, type=int,
Packit 6f3914
                                 help=_("error output level"))
Packit 6f3914
        general_grp.add_argument("--obsoletes", default=None, dest="obsoletes",
Packit 6f3914
                                 action="store_true",
Packit 6f3914
                                 help=_("enables {prog}'s obsoletes processing logic "
Packit 6f3914
                                        "for upgrade or display capabilities that "
Packit 6f3914
                                        "the package obsoletes for info, list and "
Packit 6f3914
                                        "repoquery").format(prog=dnf.util.MAIN_PROG))
Packit 6f3914
        general_grp.add_argument("--rpmverbosity", default=None,
Packit 6f3914
                                 help=_("debugging output level for rpm"),
Packit 6f3914
                                 metavar='[debug level name]')
Packit 6f3914
        general_grp.add_argument("-y", "--assumeyes", action="store_true",
Packit 6f3914
                                 default=None, help=_("automatically answer yes"
Packit 6f3914
                                                      " for all questions"))
Packit 6f3914
        general_grp.add_argument("--assumeno", action="store_true",
Packit 6f3914
                                 default=None, help=_("automatically answer no"
Packit 6f3914
                                                      " for all questions"))
Packit 6f3914
        general_grp.add_argument("--enablerepo", action=self._RepoCallback,
Packit 6f3914
                                 dest='repos_ed', default=[], metavar='[repo]',
Packit 6f3914
                                 help=_("Enable additional repositories. List option. "
Packit 6f3914
                                        "Supports globs, can be specified multiple times."))
Packit 6f3914
        repo_group = general_grp.add_mutually_exclusive_group()
Packit 6f3914
        repo_group.add_argument("--disablerepo", action=self._RepoCallback,
Packit 6f3914
                                dest='repos_ed', default=[], metavar='[repo]',
Packit 6f3914
                                help=_("Disable repositories. List option. "
Packit 6f3914
                                       "Supports globs, can be specified multiple times."))
Packit 6f3914
        repo_group.add_argument('--repo', '--repoid', metavar='[repo]', dest='repo',
Packit 6f3914
                                action=self._SplitCallback, default=[],
Packit 6f3914
                                help=_('enable just specific repositories by an id or a glob, '
Packit 6f3914
                                       'can be specified multiple times'))
Packit 6f3914
        enable_group = general_grp.add_mutually_exclusive_group()
Packit 6f3914
        enable_group.add_argument("--enable", "--set-enabled", default=False,
Packit 6f3914
                                  dest="set_enabled", action="store_true",
Packit 6f3914
                                  help=_("enable repos with config-manager "
Packit 6f3914
                                         "command (automatically saves)"))
Packit 6f3914
        enable_group.add_argument("--disable", "--set-disabled", default=False,
Packit 6f3914
                                  dest="set_disabled", action="store_true",
Packit 6f3914
                                  help=_("disable repos with config-manager "
Packit 6f3914
                                         "command (automatically saves)"))
Packit 6f3914
        general_grp.add_argument("-x", "--exclude", "--excludepkgs", default=[],
Packit 6f3914
                                 dest='excludepkgs', action=self._SplitCallback,
Packit 6f3914
                                 help=_("exclude packages by name or glob"),
Packit 6f3914
                                 metavar='[package]')
Packit 6f3914
        general_grp.add_argument("--disableexcludes", "--disableexcludepkgs",
Packit 6f3914
                                 default=[], dest="disable_excludes",
Packit 6f3914
                                 action=self._SplitCallback,
Packit 6f3914
                                 help=_("disable excludepkgs"),
Packit 6f3914
                                 metavar='[repo]')
Packit 6f3914
        general_grp.add_argument("--repofrompath", default={},
Packit 6f3914
                                 action=self._SplitExtendDictCallback,
Packit 6f3914
                                 metavar='[repo,path]',
Packit 6f3914
                                 help=_("label and path to an additional repository to use (same "
Packit 6f3914
                                        "path as in a baseurl), can be specified multiple times."))
Packit 6f3914
        general_grp.add_argument("--noautoremove", action="store_false",
Packit 6f3914
                                 default=None, dest='clean_requirements_on_remove',
Packit 6f3914
                                 help=_("disable removal of dependencies that are no longer used"))
Packit 6f3914
        general_grp.add_argument("--nogpgcheck", action="store_false",
Packit 6f3914
                                 default=None, dest='gpgcheck',
Packit 6f3914
                                 help=_("disable gpg signature checking (if RPM policy allows)"))
Packit 6f3914
        general_grp.add_argument("--color", dest="color", default=None,
Packit 6f3914
                                 help=_("control whether color is used"))
Packit 6f3914
        general_grp.add_argument("--refresh", dest="freshest_metadata",
Packit 6f3914
                                 action="store_true",
Packit 6f3914
                                 help=_("set metadata as expired before running"
Packit 6f3914
                                        " the command"))
Packit 6f3914
        general_grp.add_argument("-4", dest="ip_resolve", default=None,
Packit 6f3914
                                 help=_("resolve to IPv4 addresses only"),
Packit 6f3914
                                 action="store_const", const='ipv4')
Packit 6f3914
        general_grp.add_argument("-6", dest="ip_resolve", default=None,
Packit 6f3914
                                 help=_("resolve to IPv6 addresses only"),
Packit 6f3914
                                 action="store_const", const='ipv6')
Packit 6f3914
        general_grp.add_argument("--destdir", "--downloaddir", dest="destdir", default=None,
Packit 6f3914
                                 help=_("set directory to copy packages to"))
Packit 6f3914
        general_grp.add_argument("--downloadonly", dest="downloadonly",
Packit 6f3914
                                 action="store_true", default=False,
Packit 6f3914
                                 help=_("only download packages"))
Packit 6f3914
        general_grp.add_argument("--comment", dest="comment", default=None,
Packit 6f3914
                                 help=_("add a comment to transaction"))
Packit 6f3914
        # Updateinfo options...
Packit 6f3914
        general_grp.add_argument("--bugfix", action="store_true",
Packit 6f3914
                                 help=_("Include bugfix relevant packages, "
Packit 6f3914
                                        "in updates"))
Packit 6f3914
        general_grp.add_argument("--enhancement", action="store_true",
Packit 6f3914
                                 help=_("Include enhancement relevant packages,"
Packit 6f3914
                                        " in updates"))
Packit 6f3914
        general_grp.add_argument("--newpackage", action="store_true",
Packit 6f3914
                                 help=_("Include newpackage relevant packages,"
Packit 6f3914
                                        " in updates"))
Packit 6f3914
        general_grp.add_argument("--security", action="store_true",
Packit 6f3914
                                 help=_("Include security relevant packages, "
Packit 6f3914
                                        "in updates"))
Packit 6f3914
        general_grp.add_argument("--advisory", "--advisories", dest="advisory",
Packit 6f3914
                                 default=[], action=self._SplitCallback,
Packit 6f3914
                                 help=_("Include packages needed to fix the "
Packit 6f3914
                                        "given advisory, in updates"))
Packit 6f3914
        general_grp.add_argument("--bz", "--bzs", default=[], dest="bugzilla",
Packit 6f3914
                                 action=self._SplitCallback, help=_(
Packit 6f3914
                "Include packages needed to fix the given BZ, in updates"))
Packit 6f3914
        general_grp.add_argument("--cve", "--cves", default=[], dest="cves",
Packit 6f3914
                                 action=self._SplitCallback,
Packit 6f3914
                                 help=_("Include packages needed to fix the given CVE, in updates"))
Packit 6f3914
        general_grp.add_argument(
Packit 6f3914
            "--sec-severity", "--secseverity",
Packit 6f3914
            choices=['Critical', 'Important', 'Moderate', 'Low'], default=[],
Packit 6f3914
            dest="severity", action=self._SplitCallback, help=_(
Packit 6f3914
                "Include security relevant packages matching the severity, "
Packit 6f3914
                "in updates"))
Packit 6f3914
        general_grp.add_argument("--forcearch", metavar="ARCH",
Packit 6f3914
                                 dest=argparse.SUPPRESS,
Packit 6f3914
                                 action=self.ForceArchAction,
Packit 6f3914
                                 choices=sorted(dnf.rpm._BASEARCH_MAP.keys()),
Packit 6f3914
                                 help=_("Force the use of an architecture"))
Packit 6f3914
        general_grp.add_argument('command', nargs='?', help=argparse.SUPPRESS)
Packit 6f3914
Packit 6f3914
    def _add_cmd_usage(self, cmd, group):
Packit 6f3914
        """ store usage info about a single dnf command."""
Packit 6f3914
        summary = dnf.i18n.ucd(cmd.summary)
Packit 6f3914
        name = dnf.i18n.ucd(cmd.aliases[0])
Packit 6f3914
        if not name in self._cmd_usage:
Packit 6f3914
            self._cmd_usage[name] = (group, summary)
Packit 6f3914
            self._cmd_groups.add(group)
Packit 6f3914
Packit 6f3914
    def add_commands(self, cli_cmds, group):
Packit 6f3914
        """ store name & summary for dnf commands
Packit 6f3914
Packit 6f3914
        The stored information is used build usage information
Packit 6f3914
        grouped by build-in & plugin commands.
Packit 6f3914
        """
Packit 6f3914
        for cmd in set(cli_cmds.values()):
Packit 6f3914
            self._add_cmd_usage(cmd, group)
Packit 6f3914
Packit 6f3914
    def get_usage(self):
Packit 6f3914
        """ get the usage information to show the user. """
Packit 6f3914
        desc = {'main': _('List of Main Commands:'),
Packit 6f3914
                'plugin': _('List of Plugin Commands:')}
Packit 6f3914
        usage = '%s [options] COMMAND\n' % dnf.util.MAIN_PROG
Packit 6f3914
        for grp in ['main', 'plugin']:
Packit 6f3914
            if not grp in self._cmd_groups:
Packit 6f3914
                # dont add plugin usage, if we dont have plugins
Packit 6f3914
                continue
Packit 6f3914
            usage += "\n%s\n\n" % desc[grp]
Packit 6f3914
            for name in sorted(self._cmd_usage.keys()):
Packit 6f3914
                group, summary = self._cmd_usage[name]
Packit 6f3914
                if group == grp:
Packit 6f3914
                    usage += "%-25s %s\n" % (name, summary)
Packit 6f3914
        return usage
Packit 6f3914
Packit 6f3914
    def _add_command_options(self, command):
Packit 6f3914
        self.prog = "%s %s" % (dnf.util.MAIN_PROG, command._basecmd)
Packit 6f3914
        self.description = command.summary
Packit 6f3914
        self.command_positional_parser = argparse.ArgumentParser(self.prog, add_help=False)
Packit 6f3914
        self.command_positional_parser.print_usage = self.print_usage
Packit 6f3914
        self.command_positional_parser._positionals.title = None
Packit 6f3914
        self.command_group = self.add_argument_group(
Packit 6f3914
            '{} command-specific options'.format(command._basecmd.capitalize()))
Packit 6f3914
        self.command_group.add_argument = self.cmd_add_argument
Packit 6f3914
        self.command_group._command = command._basecmd
Packit 6f3914
        command.set_argparser(self.command_group)
Packit 6f3914
Packit 6f3914
    def cmd_add_argument(self, *args, **kwargs):
Packit 6f3914
        if all([(arg[0] in self.prefix_chars) for arg in args]):
Packit 6f3914
            return type(self.command_group).add_argument(self.command_group, *args, **kwargs)
Packit 6f3914
        else:
Packit 6f3914
            return self.command_positional_parser.add_argument(*args, **kwargs)
Packit 6f3914
Packit 6f3914
    def parse_main_args(self, args):
Packit 6f3914
        namespace, _unused_args = self.parse_known_args(args)
Packit 6f3914
        return namespace
Packit 6f3914
Packit 6f3914
    def parse_command_args(self, command, args):
Packit 6f3914
        self._add_command_options(command)
Packit 6f3914
        namespace, unused_args = self.parse_known_args(args)
Packit 6f3914
        namespace = self.command_positional_parser.parse_args(unused_args, namespace)
Packit 6f3914
        command.opts = namespace
Packit 6f3914
        return command.opts
Packit 6f3914
Packit 6f3914
    def print_usage(self, file_=None):
Packit 6f3914
        if self.command_positional_parser:
Packit 6f3914
            self._actions += self.command_positional_parser._actions
Packit 6f3914
        super(OptionParser, self).print_usage(file_)
Packit 6f3914
Packit 6f3914
    def print_help(self, command=None):
Packit 6f3914
        # pylint: disable=W0212
Packit 6f3914
        if command:
Packit 6f3914
            if not self.command_group or self.command_group._command != command._basecmd:
Packit 6f3914
                self._add_command_options(command)
Packit 6f3914
            self._actions += self.command_positional_parser._actions
Packit 6f3914
            self._action_groups.append(self.command_positional_parser._positionals)
Packit 6f3914
        else:
Packit 6f3914
            self.usage = self.get_usage()
Packit 6f3914
        super(OptionParser, self).print_help()