Source code for rez.cli._main

# SPDX-License-Identifier: Apache-2.0
# Copyright Contributors to the Rez Project


"""
The main command-line entry point.
"""
from __future__ import print_function

import sys
import importlib
from argparse import _StoreTrueAction, SUPPRESS
from rez.cli._util import subcommands, LazyArgumentParser, _env_var_true
from rez.utils.logging_ import print_error
from rez.exceptions import RezError, RezSystemError, _NeverError
from rez import __version__, module_root_path


# true if command was like 'rez-env' rather than 'rez env'
_hyphened_command = False


[docs]def is_hyphened_command(): return _hyphened_command
[docs]class SetupRezSubParser(object): """Callback class for lazily setting up rez sub-parsers. """ def __init__(self, module_name): self.module_name = module_name def __call__(self, parser_name, parser): mod = self.get_module() error_msg = None if not mod.__doc__: error_msg = "command module %s must have a module-level " \ "docstring (used as the command help)" % self.module_name if not hasattr(mod, 'command'): error_msg = "command module %s must provide a command() " \ "function" % self.module_name if not hasattr(mod, 'setup_parser'): error_msg = "command module %s must provide a setup_parser() " \ "function" % self.module_name if error_msg: print(error_msg, file=sys.stderr) return SUPPRESS mod.setup_parser(parser) parser.description = mod.__doc__ parser.set_defaults(func=mod.command, parser=parser) # add the common args to the subparser _add_common_args(parser) # optionally, return the brief help line for this sub-parser brief = mod.__doc__.strip('\n').split('\n')[0] return brief
[docs] def get_module(self): if self.module_name not in sys.modules: importlib.import_module(self.module_name) return sys.modules[self.module_name]
def _add_common_args(parser): parser.add_argument("-v", "--verbose", action="count", default=0, help="verbose mode, repeat for more verbosity") parser.add_argument("--debug", dest="debug", action="store_true", help=SUPPRESS) parser.add_argument("--profile", dest="profile", type=str, help=SUPPRESS)
[docs]class InfoAction(_StoreTrueAction): def __call__(self, parser, args, values, option_string=None): from rez.system import system txt = system.get_summary_string() print() print(txt) print() sys.exit(0)
[docs]def setup_parser(): """Create and setup parser for given rez command line interface. Returns: LazyArgumentParser: Argument parser for rez command. """ py = sys.version_info parser = LazyArgumentParser("rez") parser.add_argument("-i", "--info", action=InfoAction, help="print information about rez and exit") parser.add_argument("-V", "--version", action="version", version="Rez %s from %s (python %d.%d)" % ( __version__, module_root_path, py.major, py.minor )) # add args common to all subcommands... we add them both to the top parser, # AND to the subparsers, for two reasons: # 1) this allows us to do EITHER "rez --debug build" OR # "rez build --debug" # 2) this allows the flags to be used when using either "rez" or # "rez-build" - ie, this will work: "rez-build --debug" _add_common_args(parser) # add lazy subparsers subparser = parser.add_subparsers(dest='cmd', metavar='COMMAND') for subcommand, data in subcommands.items(): module_name = data.get('module_name', 'rez.cli.%s' % subcommand) subparser.add_parser( subcommand, help='', # required so that it can be setup later setup_subparser=SetupRezSubParser(module_name)) return parser
[docs]def run(command=None): global _hyphened_command sys.dont_write_bytecode = True # construct args list. Note that commands like 'rez-env foo' and # 'rez env foo' are equivalent # if command: # like 'rez-foo arg1 arg2' args = [command] + sys.argv[1:] _hyphened_command = True elif len(sys.argv) > 1 and sys.argv[1] in subcommands: # like 'rez foo arg1 arg2' command = sys.argv[1] args = sys.argv[1:] else: # like 'rez -i' args = sys.argv[1:] # parse args depending on subcommand behaviour if command: arg_mode = subcommands[command].get("arg_mode") else: arg_mode = None parser = setup_parser() if arg_mode == "grouped": # args split into groups by '--' arg_groups = [[]] for arg in args: if arg == '--': arg_groups.append([]) continue arg_groups[-1].append(arg) opts = parser.parse_args(arg_groups[0]) extra_arg_groups = arg_groups[1:] elif arg_mode == "passthrough": # unknown args passed in first extra_arg_group opts, extra_args = parser.parse_known_args(args) extra_arg_groups = [extra_args] else: # native arg parsing opts = parser.parse_args(args) extra_arg_groups = [] if opts.debug or _env_var_true("REZ_DEBUG"): exc_type = _NeverError else: exc_type = RezError def run_cmd(): try: # python3 will not automatically handle cases where no sub parser # has been selected. In these cases func will not exist, and an # AttributeError will be raised. func = opts.func except AttributeError: parser.error("too few arguments.") else: return func(opts, opts.parser, extra_arg_groups) if opts.profile: import cProfile cProfile.runctx("run_cmd()", globals(), locals(), filename=opts.profile) returncode = 0 else: try: returncode = run_cmd() except (NotImplementedError, RezSystemError): raise except exc_type as e: print_error("%s: %s" % (e.__class__.__name__, str(e))) sys.exit(1) sys.exit(returncode or 0)
if __name__ == '__main__': run()