def create_build_context(self, variant, build_type, build_path): """Create a context to build the variant within.""" request = variant.get_requires(build_requires=True, private_build_requires=True) requests_str = ' '.join(map(str, request)) self._print("Resolving build environment: %s", requests_str) if build_type == BuildType.local: packages_path = self.package.config.packages_path else: packages_path = self.package.config.nonlocal_packages_path context = ResolvedContext(request, package_paths=packages_path, building=True) if self.verbose: context.print_info() # save context before possible fail, so user can debug rxt_filepath = os.path.join(build_path, "build.rxt") context.save(rxt_filepath) if context.status != ResolverStatus.solved: raise BuildContextResolveError(context) return context, rxt_filepath
def spawnRezManagedCommandWatcher(pidfile, logfile, args, watcherPackages, env): """ | Uses rez module to start a process with a proper rez env. :param pidfile: full path to the comand pid file (usally /var/run/puli/cw<command_id>.pid) :param logfile: file object to store process log content :param args: arguments passed to the CommandWatcher script :param watcherPackages: A list of packages that will be resolved when creating Rez context :param env: a dict holding key/value pairs that will be merged into the current env and used in subprocess :return: a CommandWatcherProcess object holding command watcher process handle """ try: from rez.resources import clear_caches from rez.resolved_context import ResolvedContext from rez.resolver import ResolverStatus except ImportError as e: LOGGER.error("Unable to load rez package in a rez managed environment.") raise e try: if watcherPackages is None: LOGGER.warning("No package specified for this command, it might not find the runner for this command.") watcherPackagesList = [] elif type(watcherPackages) in [str, unicode]: watcherPackagesList = watcherPackages.split() else: watcherPackagesList = watcherPackages clear_caches() context = ResolvedContext(watcherPackagesList) success = (context.status == ResolverStatus.solved) if not success: context.print_info(buf=sys.stderr) raise # normalize environment # JSA do not transmit env (eg PYTHONHOME) to command watcher # envN = os.environ.copy() envN = {} for key in env: envN[str(key)] = str(env[key]) proc = context.execute_shell( command=args, shell='bash', stdin=False, stdout=logfile, stderr=subprocess.STDOUT, block=False, parent_environ=envN ) LOGGER.info("Starting subprocess, log: %r, args: %r" % (logfile.name, args)) except Exception as e: LOGGER.error("Impossible to start process: %s" % e) raise e file(pidfile, "w").write(str(proc.pid)) return CommandWatcherProcess(proc, pidfile, proc.pid)
def test_create_context(self): """Test creation of context.""" r = ResolvedContext([]) r.print_info() r = ResolvedContext(["hello_world"]) r.print_info()
def _get_context(self, requires, quiet=False): # if using current env, only return current context if it meets # requirements, otherwise return None if self.use_current_env: current_context = ResolvedContext.get_current() if current_context is None: return None reqs = map(Requirement, requires) current_reqs = current_context.get_resolve_as_exact_requests() meets_requirements = ( RequirementList(current_reqs) == RequirementList(current_reqs + reqs) ) if meets_requirements: return current_context else: return None # create context or use cached context key = tuple(requires) context = self.contexts.get(key) if context is None: if self.verbose and not quiet: self._print_header( "Resolving test environment: %s\n", ' '.join(map(quote, requires)) ) with open(os.devnull, 'w') as f: context = ResolvedContext( package_requests=requires, package_paths=self.package_paths, buf=(f if quiet else None), timestamp=self.timestamp, **self.context_kwargs ) self.contexts[key] = context if not context.success and not quiet: context.print_info(buf=self.stderr) return context
def create_build_context(self, variant, build_type, build_path): """Create a context to build the variant within.""" request = variant.get_requires(build_requires=True, private_build_requires=True) req_strs = map(str, request) quoted_req_strs = map(quote, req_strs) self._print("Resolving build environment: %s", ' '.join(quoted_req_strs)) if build_type == BuildType.local: packages_path = self.package.config.packages_path else: packages_path = self.package.config.nonlocal_packages_path # It is uncommon, but possible, to define the package filters in the # developer package. Example scenario: you may want to enable visiblity # of *.dev packages if the current package is *.dev also, for example # (assuming you have a production-time package filter which filters out # *.dev packages by default). # if self.package.config.is_overridden("package_filter"): from rez.package_filter import PackageFilterList data = self.package.config.package_filter package_filter = PackageFilterList.from_pod(data) else: package_filter = None # create the build context context = ResolvedContext(request, package_paths=packages_path, package_filter=package_filter, building=True) if self.verbose: context.print_info() # save context before possible fail, so user can debug rxt_filepath = os.path.join(build_path, "build.rxt") context.save(rxt_filepath) if context.status != ResolverStatus.solved: raise BuildContextResolveError(context) return context, rxt_filepath
def create_build_context(self, variant, build_type, build_path): """Create a context to build the variant within.""" request = variant.get_requires(build_requires=True, private_build_requires=True) req_strs = map(str, request) quoted_req_strs = map(quote, req_strs) self._print("Resolving build environment: %s", ' '.join(quoted_req_strs)) if build_type == BuildType.local: packages_path = self.package.config.packages_path else: packages_path = self.package.config.nonlocal_packages_path if self.package.config.is_overridden("package_filter"): from rez.package_filter import PackageFilterList data = self.package.config.package_filter package_filter = PackageFilterList.from_pod(data) else: package_filter = None context = ResolvedContext(request, package_paths=packages_path, package_filter=package_filter, building=True) if self.verbose: context.print_info() # save context before possible fail, so user can debug rxt_filepath = os.path.join(build_path, "build.rxt") context.save(rxt_filepath) if context.status != ResolverStatus.solved: raise BuildContextResolveError(context) return context, rxt_filepath
def run_test(self, test_name): """Run a test. Runs the test in its correct environment. Note that if tests share the same requirements, the contexts will be reused. TODO: If the package had variants, the test will be run for each variant. Returns: int: Returncode - zero if all test(s) passed, otherwise the return code of the failed test. """ def print_header(txt, *nargs): pr = Printer(sys.stdout) pr(txt % nargs, heading) package = self.get_package() if test_name not in self.get_test_names(): raise PackageTestError("Test '%s' not found in package %s" % (test_name, package.uri)) if self.use_current_env: return self._run_test_in_current_env(test_name) for variant in package.iter_variants(): # get test info for this variant. If None, that just means that this # variant doesn't provide this test. That's ok - 'tests' might be # implemented as a late function attribute that provides some tests # for some variants and not others # test_info = self._get_test_info(test_name, variant) if not test_info: continue command = test_info["command"] requires = test_info["requires"] # expand refs like {root} in commands if isinstance(command, basestring): command = variant.format(command) else: command = map(variant.format, command) # show progress if self.verbose: print_header("\nTest: %s\nPackage: %s\n%s\n", test_name, variant.uri, '-' * 80) # create test env key = tuple(requires) context = self.contexts.get(key) if context is None: if self.verbose: print_header("Resolving test environment: %s\n", ' '.join(map(quote, requires))) context = ResolvedContext(package_requests=requires, package_paths=self.package_paths, buf=self.stdout, timestamp=self.timestamp, **self.context_kwargs) if not context.success: context.print_info(buf=self.stderr) raise PackageTestError( "Cannot run test '%s' of package %s: the environment " "failed to resolve" % (test_name, variant.uri)) self.contexts[key] = context # run the test in the context if self.verbose: context.print_info(self.stdout) if isinstance(command, basestring): cmd_str = command else: cmd_str = ' '.join(map(quote, command)) print_header("\nRunning test command: %s\n" % cmd_str) retcode, _, _ = context.execute_shell(command=command, stdout=self.stdout, stderr=self.stderr, block=True) if retcode: return retcode # TODO FIXME we don't iterate over all variants yet, because we # can't reliably do that (see class docstring) break return 0 # success
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: parser.error( "Cannot use --input and provide PKG(s) at the same time") context = ResolvedContext.load(opts.input) if context.status != ResolverStatus.solved: print >> sys.stderr, "cannot rez-env into a failed context" sys.exit(1) if opts.patch: # TODO: patching is lagging behind in options, and needs to be updated # anyway. if context is None: from rez.status import status context = status.context if context is None: print >> sys.stderr, "cannot patch: not in a context" sys.exit(1) 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)) success = (context.status == ResolverStatus.solved) if not success: context.print_info(buf=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. if opts.stdin and not select.select([sys.stdin], [], [], 0.0)[0]: opts.stdin = False 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)
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 >> sys.stderr, "cannot patch: not in a context" 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) 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 >> sys.stderr, \ "the failed resolve context did not generate a graph." 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)
def execute(self, app_path, app_args, version, **kwargs): """ The execute functon of the hook will be called to start the required application :param app_path: (str) The path of the application executable :param app_args: (str) Any arguments the application may require :param version: (str) version of the application being run if set in the "versions" settings of the Launcher instance, otherwise None :returns: (dict) The two valid keys are 'command' (str) and 'return_code' (int). """ multi_launchapp = self.parent extra = multi_launchapp.get_setting("extra") use_rez = False if self.check_rez(): from rez.resolved_context import ResolvedContext from rez.config import config # Define variables used to bootstrap tank from overwrite on first reference # PYTHONPATH is used by tk-maya # NUKE_PATH is used by tk-nuke # HIERO_PLUGIN_PATH is used by tk-nuke (nukestudio) # KATANA_RESOURCES is used by tk-katana config.parent_variables = [ "PYTHONPATH", "HOUDINI_PATH", "NUKE_PATH", "HIERO_PLUGIN_PATH", "KATANA_RESOURCES" ] rez_packages = extra["rez_packages"] context = ResolvedContext(rez_packages) use_rez = True else: print('Can not found rez.') system = sys.platform shell_type = 'bash' if system == "linux2": # on linux, we just run the executable directly cmd = "%s %s &" % (app_path, app_args) #cmd = "%s &" % (app_path) elif self.parent.get_setting("engine") in ["tk-flame", "tk-flare"]: # flame and flare works in a different way from other DCCs # on both linux and mac, they run unix-style command line # and on the mac the more standardized "open" command cannot # be utilized. cmd = "%s %s &" % (app_path, app_args) elif system == "darwin": # on the mac, the executable paths are normally pointing # to the application bundle and not to the binary file # embedded in the bundle, meaning that we should use the # built-in mac open command to execute it cmd = "open -n \"%s\"" % (app_path) if app_args: cmd += " --args \"%s\"" % app_args.replace("\"", "\\\"") elif system == "win32": # on windows, we run the start command in order to avoid # any command shells popping up as part of the application launch. cmd = "start /B \"App\" \"%s\" %s" % (app_path, app_args) shell_type = 'cmd' print('use_rez:{0}'.format(use_rez)) # Execute App in a Rez context if use_rez: n_env = os.environ.copy() proc = context.execute_shell(command=cmd, parent_environ=n_env, shell=shell_type, stdin=False, block=False) exit_code = proc.wait() print('exit_code:{0}'.format(exit_code)) context.print_info(verbosity=True) else: # run the command to launch the app exit_code = os.system(cmd) return {"command": cmd, "return_code": exit_code}
def execute(self, app_path, app_args, version, **kwargs): """ The execute functon of the hook will be called to start the required application :param app_path: (str) The path of the application executable :param app_args: (str) Any arguments the application may require :param version: (str) version of the application being run if set in the "versions" settings of the Launcher instance, otherwise None :returns: (dict) The two valid keys are 'command' (str) and 'return_code' (int). """ multi_launchapp = self.parent extra = multi_launchapp.get_setting("extra") use_rez = False if self.check_rez(): rez_packages = extra["rez_packages"] from rez.resolved_context import ResolvedContext from rez.config import config config.parent_variables = ["PYTHONPATH"] context = ResolvedContext(rez_packages) use_rez = True system = sys.platform shell_type = 'bash' if system == "linux2": # on linux, we just run the executable directly cmd = "%s %s &" % (app_path, app_args) elif self.parent.get_setting("engine") in ["tk-flame", "tk-flare"]: # flame and flare works in a different way from other DCCs # on both linux and mac, they run unix-style command line # and on the mac the more standardized "open" command cannot # be utilized. cmd = "%s %s &" % (app_path, app_args) elif system == "darwin": # on the mac, the executable paths are normally pointing # to the application bundle and not to the binary file # embedded in the bundle, meaning that we should use the # built-in mac open command to execute it cmd = "open -n \"%s\"" % (app_path) if app_args: cmd += " --args \"%s\"" % app_args.replace("\"", "\\\"") elif system == "win32": # on windows, we run the start command in order to avoid # any command shells popping up as part of the application launch. cmd = "start /B \"App\" \"%s\" %s" % (app_path, app_args) shell_type = 'cmd' # Execute App in a Rez context if use_rez: n_env = os.environ.copy() proc = context.execute_shell( command=cmd, parent_environ=n_env, shell=shell_type, stdin=False, block=False ) exit_code = proc.wait() context.print_info(verbosity=True) else: # run the command to launch the app exit_code = os.system(cmd) return { "command": cmd, "return_code": exit_code }
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.isolated: config.inherit_parent_environment = False if opts.inherited: config.inherit_parent_environment = True 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 opts.self: from rez.utils._version import _rez_version request += ["bleeding_rez==%s" % _rez_version] request += ["python"] # Required by Rez 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) 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) if opts.env: env = {} for pair in opts.env: key, value = pair.split("=") env[key.upper()] = value config.additional_environment = env # 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)
def run_test(self, test_name): """Run a test. Runs the test in its correct environment. Note that if tests share the same requirements, the contexts will be reused. TODO: If the package had variants, the test will be run for each variant. Returns: int: Returncode - zero if all test(s) passed, otherwise the return code of the failed test. """ def print_header(txt, *nargs): pr = Printer(sys.stdout) pr(txt % nargs, heading) package = self.get_package() if test_name not in self.get_test_names(): raise PackageTestError("Test '%s' not found in package %s" % (test_name, package.uri)) if self.use_current_env: return self._run_test_in_current_env(test_name) for variant in package.iter_variants(): # get test info for this variant. If None, that just means that this # variant doesn't provide this test. That's ok - 'tests' might be # implemented as a late function attribute that provides some tests # for some variants and not others # test_info = self._get_test_info(test_name, variant) if not test_info: continue command = test_info["command"] requires = test_info["requires"] # expand refs like {root} in commands if isinstance(command, basestring): command = variant.format(command) else: command = map(variant.format, command) # show progress if self.verbose: print_header( "\nTest: %s\nPackage: %s\n%s\n", test_name, variant.uri, '-' * 80) # create test env key = tuple(requires) context = self.contexts.get(key) if context is None: if self.verbose: print_header("Resolving test environment: %s\n", ' '.join(map(quote, requires))) context = ResolvedContext(package_requests=requires, package_paths=self.package_paths, buf=self.stdout, timestamp=self.timestamp, **self.context_kwargs) if not context.success: context.print_info(buf=self.stderr) raise PackageTestError( "Cannot run test '%s' of package %s: the environment " "failed to resolve" % (test_name, variant.uri)) self.contexts[key] = context # run the test in the context if self.verbose: context.print_info(self.stdout) if isinstance(command, basestring): cmd_str = command else: cmd_str = ' '.join(map(quote, command)) print_header("\nRunning test command: %s\n" % cmd_str) retcode, _, _ = context.execute_shell( command=command, stdout=self.stdout, stderr=self.stderr, block=True) if retcode: return retcode # TODO FIXME we don't iterate over all variants yet, because we # can't reliably do that (see class docstring) break return 0 # success
def execute(self, app_path, app_args, version, **kwargs): """Start the required application using rez if required. Notes: - Define variables used to bootstrap tank from overwrite on first reference - Define others within ``tk-multi-launchapp.yml`` file in the ``extra:rez:parent_variables`` list. Args: app_path (str): The path of the application executable app_args (str): Any arguments the application may require version (str): version of the application being run if set in the "versions" settings of the Launcher instance, otherwise ``None`` Returns: dict[str]: Execute results mapped to 'command' (str) and 'return_code' (int). """ multi_launchapp = self.parent rez_info = multi_launchapp.get_setting("extra", {}).get("rez", {}) cmd, shell_type = self.background_cmd_shell_type(app_path, app_args) # Execute App in a Rez context rez_py_path = self.get_rez_path() if rez_py_path: if rez_py_path not in sys.path: self.logger.debug('Appending to sys.path: "%s"', rez_py_path) sys.path.append(rez_py_path) # Only import after rez_py_path is inside sys.path from rez.resolved_context import ResolvedContext from rez.config import config rez_parent_variables = rez_info.get("parent_variables", []) rez_packages = [ request.format(version=version) for request in rez_info.get("packages", []) ] self.logger.debug("rez parent variables: %s", rez_parent_variables) self.logger.debug("rez packages: %s", rez_packages) config.parent_variables = rez_parent_variables context = ResolvedContext(rez_packages) parent_env = self.create_shell_parent_env(context, config, app_path, app_args, version, **kwargs) env_kwargs = {"suffix": "-prev-env.py", "delete": False} with NamedTemporaryFile(mode="w+", **env_kwargs) as env_file: env_file.write(pformat(parent_env)) self.logger.debug('Copied existing env for rez. See: "%s"', env_file.name) with TemporaryFile(mode="w+") as info_buffer: context.print_info(buf=info_buffer) info_buffer.seek(0) self.logger.debug( "Executing in rez context [%s]: %s\n%s", shell_type, cmd, info_buffer.read(), ) launcher_process = context.execute_shell( command=cmd, parent_environ=parent_env, shell=shell_type, stdin=False, block=False, ) exit_code = launcher_process.wait() else: # run the command to launch the app exit_code = subprocess.check_call(cmd) return {"command": cmd, "return_code": exit_code}