1"""A single place for constructing and exposing the main parser 2""" 3 4import os 5import sys 6 7from pipenv.patched.notpip._internal.cli import cmdoptions 8from pipenv.patched.notpip._internal.cli.parser import ( 9 ConfigOptionParser, 10 UpdatingDefaultsHelpFormatter, 11) 12from pipenv.patched.notpip._internal.commands import commands_dict, get_similar_commands 13from pipenv.patched.notpip._internal.exceptions import CommandError 14from pipenv.patched.notpip._internal.utils.misc import get_pip_version, get_prog 15from pipenv.patched.notpip._internal.utils.typing import MYPY_CHECK_RUNNING 16 17if MYPY_CHECK_RUNNING: 18 from typing import Tuple, List 19 20 21__all__ = ["create_main_parser", "parse_command"] 22 23 24def create_main_parser(): 25 # type: () -> ConfigOptionParser 26 """Creates and returns the main parser for pip's CLI 27 """ 28 29 parser_kw = { 30 'usage': '\n%prog <command> [options]', 31 'add_help_option': False, 32 'formatter': UpdatingDefaultsHelpFormatter(), 33 'name': 'global', 34 'prog': get_prog(), 35 } 36 37 parser = ConfigOptionParser(**parser_kw) 38 parser.disable_interspersed_args() 39 40 parser.version = get_pip_version() 41 42 # add the general options 43 gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) 44 parser.add_option_group(gen_opts) 45 46 # so the help formatter knows 47 parser.main = True # type: ignore 48 49 # create command listing for description 50 description = [''] + [ 51 '%-27s %s' % (name, command_info.summary) 52 for name, command_info in commands_dict.items() 53 ] 54 parser.description = '\n'.join(description) 55 56 return parser 57 58 59def parse_command(args): 60 # type: (List[str]) -> Tuple[str, List[str]] 61 parser = create_main_parser() 62 63 # Note: parser calls disable_interspersed_args(), so the result of this 64 # call is to split the initial args into the general options before the 65 # subcommand and everything else. 66 # For example: 67 # args: ['--timeout=5', 'install', '--user', 'INITools'] 68 # general_options: ['--timeout==5'] 69 # args_else: ['install', '--user', 'INITools'] 70 general_options, args_else = parser.parse_args(args) 71 72 # --version 73 if general_options.version: 74 sys.stdout.write(parser.version) # type: ignore 75 sys.stdout.write(os.linesep) 76 sys.exit() 77 78 # pip || pip help -> print_help() 79 if not args_else or (args_else[0] == 'help' and len(args_else) == 1): 80 parser.print_help() 81 sys.exit() 82 83 # the subcommand name 84 cmd_name = args_else[0] 85 86 if cmd_name not in commands_dict: 87 guess = get_similar_commands(cmd_name) 88 89 msg = ['unknown command "%s"' % cmd_name] 90 if guess: 91 msg.append('maybe you meant "%s"' % guess) 92 93 raise CommandError(' - '.join(msg)) 94 95 # all the args without the subcommand 96 cmd_args = args[:] 97 cmd_args.remove(cmd_name) 98 99 return cmd_name, cmd_args 100