1from __future__ import absolute_import, unicode_literals 2 3import logging 4from functools import partial 5 6from ..app_data import make_app_data 7from ..config.cli.parser import VirtualEnvConfigParser 8from ..report import LEVELS, setup_report 9from ..run.session import Session 10from ..seed.wheels.periodic_update import manual_upgrade 11from ..version import __version__ 12from .plugin.activators import ActivationSelector 13from .plugin.creators import CreatorSelector 14from .plugin.discovery import get_discover 15from .plugin.seeders import SeederSelector 16 17 18def cli_run(args, options=None, setup_logging=True): 19 """ 20 Create a virtual environment given some command line interface arguments. 21 22 :param args: the command line arguments 23 :param options: passing in a ``VirtualEnvOptions`` object allows return of the parsed options 24 :param setup_logging: ``True`` if setup logging handlers, ``False`` to use handlers already registered 25 :return: the session object of the creation (its structure for now is experimental and might change on short notice) 26 """ 27 of_session = session_via_cli(args, options, setup_logging) 28 with of_session: 29 of_session.run() 30 return of_session 31 32 33def session_via_cli(args, options=None, setup_logging=True): 34 """ 35 Create a virtualenv session (same as cli_run, but this does not perform the creation). Use this if you just want to 36 query what the virtual environment would look like, but not actually create it. 37 38 :param args: the command line arguments 39 :param options: passing in a ``VirtualEnvOptions`` object allows return of the parsed options 40 :param setup_logging: ``True`` if setup logging handlers, ``False`` to use handlers already registered 41 :return: the session object of the creation (its structure for now is experimental and might change on short notice) 42 """ 43 parser, elements = build_parser(args, options, setup_logging) 44 options = parser.parse_args(args) 45 creator, seeder, activators = tuple(e.create(options) for e in elements) # create types 46 of_session = Session(options.verbosity, options.app_data, parser._interpreter, creator, seeder, activators) # noqa 47 return of_session 48 49 50def build_parser(args=None, options=None, setup_logging=True): 51 parser = VirtualEnvConfigParser(options) 52 add_version_flag(parser) 53 parser.add_argument( 54 "--with-traceback", 55 dest="with_traceback", 56 action="store_true", 57 default=False, 58 help="on failure also display the stacktrace internals of virtualenv", 59 ) 60 _do_report_setup(parser, args, setup_logging) 61 options = load_app_data(args, parser, options) 62 handle_extra_commands(options) 63 64 discover = get_discover(parser, args) 65 parser._interpreter = interpreter = discover.interpreter 66 if interpreter is None: 67 raise RuntimeError("failed to find interpreter for {}".format(discover)) 68 elements = [ 69 CreatorSelector(interpreter, parser), 70 SeederSelector(interpreter, parser), 71 ActivationSelector(interpreter, parser), 72 ] 73 options, _ = parser.parse_known_args(args) 74 for element in elements: 75 element.handle_selected_arg_parse(options) 76 parser.enable_help() 77 return parser, elements 78 79 80def build_parser_only(args=None): 81 """Used to provide a parser for the doc generation""" 82 return build_parser(args)[0] 83 84 85def handle_extra_commands(options): 86 if options.upgrade_embed_wheels: 87 result = manual_upgrade(options.app_data) 88 raise SystemExit(result) 89 90 91def load_app_data(args, parser, options): 92 parser.add_argument( 93 "--read-only-app-data", 94 action="store_true", 95 help="use app data folder in read-only mode (write operations will fail with error)", 96 ) 97 options, _ = parser.parse_known_args(args, namespace=options) 98 99 # here we need a write-able application data (e.g. the zipapp might need this for discovery cache) 100 parser.add_argument( 101 "--app-data", 102 help="a data folder used as cache by the virtualenv", 103 type=partial(make_app_data, read_only=options.read_only_app_data), 104 default=make_app_data(None, read_only=options.read_only_app_data), 105 ) 106 parser.add_argument( 107 "--reset-app-data", 108 action="store_true", 109 help="start with empty app data folder", 110 ) 111 parser.add_argument( 112 "--upgrade-embed-wheels", 113 action="store_true", 114 help="trigger a manual update of the embedded wheels", 115 ) 116 options, _ = parser.parse_known_args(args, namespace=options) 117 if options.reset_app_data: 118 options.app_data.reset() 119 return options 120 121 122def add_version_flag(parser): 123 import virtualenv 124 125 parser.add_argument( 126 "--version", 127 action="version", 128 version="%(prog)s {} from {}".format(__version__, virtualenv.__file__), 129 help="display the version of the virtualenv package and its location, then exit", 130 ) 131 132 133def _do_report_setup(parser, args, setup_logging): 134 level_map = ", ".join("{}={}".format(logging.getLevelName(l), c) for c, l in sorted(list(LEVELS.items()))) 135 msg = "verbosity = verbose - quiet, default {}, mapping => {}" 136 verbosity_group = parser.add_argument_group( 137 title="verbosity", 138 description=msg.format(logging.getLevelName(LEVELS[3]), level_map), 139 ) 140 verbosity = verbosity_group.add_mutually_exclusive_group() 141 verbosity.add_argument("-v", "--verbose", action="count", dest="verbose", help="increase verbosity", default=2) 142 verbosity.add_argument("-q", "--quiet", action="count", dest="quiet", help="decrease verbosity", default=0) 143 option, _ = parser.parse_known_args(args) 144 if setup_logging: 145 setup_report(option.verbosity) 146 147 148__all__ = ( 149 "cli_run", 150 "session_via_cli", 151) 152