codekingpro/portable-devtools
114k
1from __future__ import annotations2 3import logging4import os5from functools import partial6 7from virtualenv.app_data import make_app_data8from virtualenv.config.cli.parser import VirtualEnvConfigParser9from virtualenv.report import LEVELS, setup_report10from virtualenv.run.session import Session11from virtualenv.seed.wheels.periodic_update import manual_upgrade12from virtualenv.version import __version__13 14from .plugin.activators import ActivationSelector15from .plugin.creators import CreatorSelector16from .plugin.discovery import get_discover17from .plugin.seeders import SeederSelector18 19 20def cli_run(args, options=None, setup_logging=True, env=None): # noqa: FBT00221 """22 Create a virtual environment given some command line interface arguments.23 24 :param args: the command line arguments25 :param options: passing in a ``VirtualEnvOptions`` object allows return of the parsed options26 :param setup_logging: ``True`` if setup logging handlers, ``False`` to use handlers already registered27 :param env: environment variables to use28 :return: the session object of the creation (its structure for now is experimental and might change on short notice)29 """30 env = os.environ if env is None else env31 of_session = session_via_cli(args, options, setup_logging, env)32 with of_session:33 of_session.run()34 return of_session35 36 37def session_via_cli(args, options=None, setup_logging=True, env=None): # noqa: FBT00238 """39 Create a virtualenv session (same as cli_run, but this does not perform the creation). Use this if you just want to40 query what the virtual environment would look like, but not actually create it.41 42 :param args: the command line arguments43 :param options: passing in a ``VirtualEnvOptions`` object allows return of the parsed options44 :param setup_logging: ``True`` if setup logging handlers, ``False`` to use handlers already registered45 :param env: environment variables to use46 :return: the session object of the creation (its structure for now is experimental and might change on short notice)47 """ # noqa: D20548 env = os.environ if env is None else env49 parser, elements = build_parser(args, options, setup_logging, env)50 options = parser.parse_args(args)51 creator, seeder, activators = tuple(e.create(options) for e in elements) # create types52 return Session(53 options.verbosity,54 options.app_data,55 parser._interpreter, # noqa: SLF00156 creator,57 seeder,58 activators,59 )60 61 62def build_parser(args=None, options=None, setup_logging=True, env=None): # noqa: FBT00263 parser = VirtualEnvConfigParser(options, os.environ if env is None else env)64 add_version_flag(parser)65 parser.add_argument(66 "--with-traceback",67 dest="with_traceback",68 action="store_true",69 default=False,70 help="on failure also display the stacktrace internals of virtualenv",71 )72 _do_report_setup(parser, args, setup_logging)73 options = load_app_data(args, parser, options)74 handle_extra_commands(options)75 76 discover = get_discover(parser, args)77 parser._interpreter = interpreter = discover.interpreter # noqa: SLF00178 if interpreter is None:79 msg = f"failed to find interpreter for {discover}"80 raise RuntimeError(msg)81 elements = [82 CreatorSelector(interpreter, parser),83 SeederSelector(interpreter, parser),84 ActivationSelector(interpreter, parser),85 ]86 options, _ = parser.parse_known_args(args)87 for element in elements:88 element.handle_selected_arg_parse(options)89 parser.enable_help()90 return parser, elements91 92 93def build_parser_only(args=None):94 """Used to provide a parser for the doc generation."""95 return build_parser(args)[0]96 97 98def handle_extra_commands(options):99 if options.upgrade_embed_wheels:100 result = manual_upgrade(options.app_data, options.env)101 raise SystemExit(result)102 103 104def load_app_data(args, parser, options):105 parser.add_argument(106 "--read-only-app-data",107 action="store_true",108 help="use app data folder in read-only mode (write operations will fail with error)",109 )110 options, _ = parser.parse_known_args(args, namespace=options)111 112 # here we need a write-able application data (e.g. the zipapp might need this for discovery cache)113 parser.add_argument(114 "--app-data",115 help="a data folder used as cache by the virtualenv",116 type=partial(make_app_data, read_only=options.read_only_app_data, env=options.env),117 default=make_app_data(None, read_only=options.read_only_app_data, env=options.env),118 )119 parser.add_argument(120 "--reset-app-data",121 action="store_true",122 help="start with empty app data folder",123 )124 parser.add_argument(125 "--upgrade-embed-wheels",126 action="store_true",127 help="trigger a manual update of the embedded wheels",128 )129 options, _ = parser.parse_known_args(args, namespace=options)130 if options.reset_app_data:131 options.app_data.reset()132 return options133 134 135def add_version_flag(parser):136 import virtualenv # noqa: PLC0415137 138 parser.add_argument(139 "--version",140 action="version",141 version=f"%(prog)s {__version__} from {virtualenv.__file__}",142 help="display the version of the virtualenv package and its location, then exit",143 )144 145 146def _do_report_setup(parser, args, setup_logging):147 level_map = ", ".join(f"{logging.getLevelName(line)}={c}" for c, line in sorted(LEVELS.items()))148 msg = "verbosity = verbose - quiet, default {}, mapping => {}"149 verbosity_group = parser.add_argument_group(150 title="verbosity",151 description=msg.format(logging.getLevelName(LEVELS[3]), level_map),152 )153 verbosity = verbosity_group.add_mutually_exclusive_group()154 verbosity.add_argument("-v", "--verbose", action="count", dest="verbose", help="increase verbosity", default=2)155 verbosity.add_argument("-q", "--quiet", action="count", dest="quiet", help="decrease verbosity", default=0)156 option, _ = parser.parse_known_args(args)157 if setup_logging:158 setup_report(option.verbosity)159 160 161__all__ = [162 "cli_run",163 "session_via_cli",164]165 