# SPDX-License-Identifier: Apache-2.0
# Copyright Contributors to the Rez Project
'''
Open a rez-configured shell, possibly interactive.
'''
from __future__ import print_function
[docs]def setup_parser(parser, completions=False):
from argparse import SUPPRESS
from rez.config import config
from rez.system import system
from rez.shells import get_shell_types
import os
shells = get_shell_types()
parser.add_argument(
"--shell", dest="shell", type=str, choices=shells,
default=config.default_shell or system.shell,
help="target shell type (default: %(default)s)")
parser.add_argument(
"--rcfile", type=str,
help="source this file instead of the target shell's standard startup "
"scripts, if possible")
parser.add_argument(
"--norc", action="store_true",
help="skip loading of startup scripts")
command_action = parser.add_argument(
"-c", "--command", type=str,
help="read commands from string. Alternatively, list command arguments "
"after a '--'")
parser.add_argument(
"-s", "--stdin", action="store_true",
help="read commands from standard input")
parser.add_argument(
"--ni", "--no-implicit", dest="no_implicit",
action="store_true",
help="don't add implicit packages to the request")
parser.add_argument(
"--nl", "--no-local", dest="no_local", action="store_true",
help="don't load local packages")
parser.add_argument(
"-b", "--build", action="store_true",
help="create a build environment")
parser.add_argument(
"--paths", type=str, default=None,
help="set package search path (use %r separator)" % os.pathsep)
parser.add_argument(
"-t", "--time", type=str,
help="ignore packages released after the given time. Supported formats "
"are: epoch time (eg 1393014494), or relative time (eg -10s, -5m, "
"-0.5h, -10d)")
parser.add_argument(
"--max-fails", type=int, default=-1, dest="max_fails",
metavar='N',
help="abort if the number of failed configuration attempts exceeds N")
parser.add_argument(
"--time-limit", type=int, default=-1,
dest="time_limit", metavar='SECS',
help="abort if the resolve time exceeds SECS")
parser.add_argument(
"-o", "--output", type=str, metavar="FILE",
help="store the context into an rxt file, instead of starting an "
"interactive shell. Note that this will also store a failed resolve. "
"If you use the special value '-', the context is written to stdout.")
input_action = parser.add_argument(
"-i", "--input", type=str, metavar="FILE",
help="use a previously saved context. Resolve settings, such as PKG, "
"--ni etc are ignored in this case")
parser.add_argument(
"--exclude", type=str, nargs='+', metavar="RULE",
help="add package exclusion filters, eg '*.beta'. Note that these are "
"added to the globally configured exclusions")
parser.add_argument(
"--include", type=str, nargs='+', metavar="RULE",
help="add package inclusion filters, eg 'mypkg', 'boost-*'. Note that "
"these are added to the globally configured inclusions")
parser.add_argument(
"--no-filters", dest="no_filters", action="store_true",
help="turn off package filters. Note that any filters specified with "
"--exclude/--include are still applied")
parser.add_argument(
"-p", "--patch", action="store_true",
help="patch the current context to create a new context")
parser.add_argument(
"--strict", action="store_true",
help="strict patching. Ignored if --patch is not present")
parser.add_argument(
"--patch-rank", type=int, metavar="N", default=0,
help="patch rank. Ignored if --patch is not present")
parser.add_argument(
"--no-cache", dest="no_cache", action="store_true",
help="do not fetch cached resolves")
parser.add_argument(
"-q", "--quiet", action="store_true",
help="run in quiet mode (hides welcome message)")
parser.add_argument(
"--fail-graph", action="store_true",
help="if the build environment fails to resolve due to a conflict, "
"display the resolve graph as an image.")
parser.add_argument(
"--new-session", action="store_true",
help="start the shell in a new process group")
parser.add_argument(
"--detached", action="store_true",
help="open a separate terminal")
parser.add_argument(
"--no-passive", action="store_true",
help="only print actions that affect the solve (has an effect only "
"when verbosity is enabled)")
parser.add_argument(
"--stats", action="store_true",
help="print advanced solver stats")
parser.add_argument(
"--no-pkg-cache", action="store_true",
help="Disable package caching")
parser.add_argument(
"--pre-command", type=str, help=SUPPRESS)
PKG_action = parser.add_argument(
"PKG", type=str, nargs='*',
help='packages to use in the target environment')
extra_0_action = parser.add_argument( # args after --
"--N0", dest="extra_0", nargs='*',
help=SUPPRESS)
if completions:
from rez.cli._complete_util import PackageCompleter, FilesCompleter, \
ExecutablesCompleter, AndCompleter, SequencedCompleter
command_action.completer = AndCompleter(ExecutablesCompleter, FilesCompleter())
input_action.completer = FilesCompleter(dirs=False, file_patterns=["*.rxt"])
PKG_action.completer = PackageCompleter
extra_0_action.completer = SequencedCompleter(
"extra_0", ExecutablesCompleter, FilesCompleter())
[docs]def command(opts, parser, extra_arg_groups=None):
from rez.resolved_context import ResolvedContext
from rez.resolver import ResolverStatus
from rez.package_filter import PackageFilterList, Rule
from rez.utils.formatting import get_epoch_time_from_str
from rez.config import config
import select
import sys
import os
import os.path
command = opts.command
if extra_arg_groups:
if opts.command:
parser.error("argument --command: not allowed with arguments after '--'")
command = extra_arg_groups[0] or None
context = None
request = opts.PKG
t = get_epoch_time_from_str(opts.time) if opts.time else None
if opts.paths is None:
pkg_paths = (config.nonlocal_packages_path
if opts.no_local else None)
else:
pkg_paths = opts.paths.split(os.pathsep)
pkg_paths = [os.path.expanduser(x) for x in pkg_paths if x]
if opts.input:
if opts.PKG and not opts.patch:
parser.error("Cannot use --input and provide PKG(s), unless patching.")
context = ResolvedContext.load(opts.input)
if opts.patch:
if context is None:
from rez.status import status
context = status.context
if context is None:
print("cannot patch: not in a context", file=sys.stderr)
sys.exit(1)
# modify the request in terms of the given patch request
request = context.get_patched_request(request,
strict=opts.strict,
rank=opts.patch_rank)
context = None
if context is None:
# create package filters
if opts.no_filters:
package_filter = PackageFilterList()
else:
package_filter = PackageFilterList.singleton.copy()
for rule_str in (opts.exclude or []):
rule = Rule.parse_rule(rule_str)
package_filter.add_exclusion(rule)
for rule_str in (opts.include or []):
rule = Rule.parse_rule(rule_str)
package_filter.add_inclusion(rule)
# perform the resolve
context = ResolvedContext(
package_requests=request,
timestamp=t,
package_paths=pkg_paths,
building=opts.build,
package_filter=package_filter,
add_implicit_packages=(not opts.no_implicit),
verbosity=opts.verbose,
max_fails=opts.max_fails,
time_limit=opts.time_limit,
caching=(not opts.no_cache),
suppress_passive=opts.no_passive,
print_stats=opts.stats,
package_caching=(not opts.no_pkg_cache)
)
success = (context.status == ResolverStatus.solved)
if not success:
context.print_info(buf=sys.stderr)
if opts.fail_graph:
if context.graph:
from rez.utils.graph_utils import view_graph
g = context.graph(as_dot=True)
view_graph(g)
else:
print("the failed resolve context did not generate a graph.",
file=sys.stderr)
if opts.output:
if opts.output == '-': # print to stdout
context.write_to_buffer(sys.stdout)
else:
context.save(opts.output)
sys.exit(0 if success else 1)
if not success:
sys.exit(1)
# generally shells will behave as though the '-s' flag was not present when
# no stdin is available. So here we replicate this behaviour.
try:
if opts.stdin and not select.select([sys.stdin], [], [], 0.0)[0]:
opts.stdin = False
except select.error:
pass # because windows
quiet = opts.quiet or bool(command)
returncode, _, _ = context.execute_shell(
shell=opts.shell,
rcfile=opts.rcfile,
norc=opts.norc,
command=command,
stdin=opts.stdin,
quiet=quiet,
start_new_session=opts.new_session,
detached=opts.detached,
pre_command=opts.pre_command,
block=True)
sys.exit(returncode)