Spawn a possibly-interactive shell.

        Args:
            shell: Shell type, for eg 'bash'. If None, the current shell type
                is used.
            parent_environ: Environment to run the shell process in, if None
                then the current environment is used.
            rcfile: Specify a file to source instead of shell startup files.
            norc: If True, skip shell startup files, if possible.
            stdin: If True, read commands from stdin, in a non-interactive
                shell.
            command: If not None, execute this command in a non-interactive shell.
                If an empty string or list, don't run a command, but don't open
                an interactive shell either. Can be a list of args.
            quiet: If True, skip the welcome message in interactive shells.
            block: If True, block until the shell is terminated. If False,
                return immediately. If None, will default to blocking if the
                shell is interactive.
            actions_callback: Callback with signature (RexExecutor). This lets
                the user append custom actions to the context, such as setting
                extra environment variables. Callback is run prior to context Rex
                execution.
            post_actions_callback: Callback with signature (RexExecutor). This lets
                the user append custom actions to the context, such as setting
                extra environment variables. Callback is run after context Rex
                execution.
            context_filepath: If provided, the context file will be written
                here, rather than to the default location (which is in a
                tempdir). If you use this arg, you are responsible for cleaning
                up the file.
            start_new_session: If True, change the process group of the target
                process. Note that this may override the Popen_args keyword
                'preexec_fn'.
            detached: If True, open a separate terminal. Note that this may
                override the `pre_command` argument.
            pre_command: Command to inject before the shell command itself. This
                is for internal use.
            Popen_args: args to pass to the shell process object constructor.

        Returns:
            If blocking: A 3-tuple of (returncode, stdout, stderr);
            If non-blocking - A subprocess.Popen object for the shell process.

def execute_shell(self, shell=None, parent_environ=None, rcfile=None,
                      norc=False, stdin=False, command=None, quiet=False,
                      block=None, actions_callback=None, post_actions_callback=None,
                      context_filepath=None, start_new_session=False, detached=False,
                      pre_command=None, **Popen_args):
        """Spawn a possibly-interactive shell.

        Args:
            shell: Shell type, for eg 'bash'. If None, the current shell type
                is used.
            parent_environ: Environment to run the shell process in, if None
                then the current environment is used.
            rcfile: Specify a file to source instead of shell startup files.
            norc: If True, skip shell startup files, if possible.
            stdin: If True, read commands from stdin, in a non-interactive
                shell.
            command: If not None, execute this command in a non-interactive shell.
                If an empty string or list, don't run a command, but don't open
                an interactive shell either. Can be a list of args.
            quiet: If True, skip the welcome message in interactive shells.
            block: If True, block until the shell is terminated. If False,
                return immediately. If None, will default to blocking if the
                shell is interactive.
            actions_callback: Callback with signature (RexExecutor). This lets
                the user append custom actions to the context, such as setting
                extra environment variables. Callback is run prior to context Rex
                execution.
            post_actions_callback: Callback with signature (RexExecutor). This lets
                the user append custom actions to the context, such as setting
                extra environment variables. Callback is run after context Rex
                execution.
            context_filepath: If provided, the context file will be written
                here, rather than to the default location (which is in a
                tempdir). If you use this arg, you are responsible for cleaning
                up the file.
            start_new_session: If True, change the process group of the target
                process. Note that this may override the Popen_args keyword
                'preexec_fn'.
            detached: If True, open a separate terminal. Note that this may
                override the `pre_command` argument.
            pre_command: Command to inject before the shell command itself. This
                is for internal use.
            Popen_args: args to pass to the shell process object constructor.

        Returns:
            If blocking: A 3-tuple of (returncode, stdout, stderr);
            If non-blocking - A subprocess.Popen object for the shell process.
        """
        sh = create_shell(shell)

        if hasattr(command, "__iter__"):
            command = sh.join(command)

        # start a new session if specified
        if start_new_session:
            Popen_args.update(config.new_session_popen_args)

        # open a separate terminal if specified
        if detached:
            term_cmd = config.terminal_emulator_command
            if term_cmd:
                pre_command = term_cmd.strip().split()

        # block if the shell is likely to be interactive
        if block is None:
            block = not (command or stdin)

        # context and rxt files. If running detached, don't cleanup files, because
        # rez-env returns too early and deletes the tmp files before the detached
        # process can use them
        tmpdir = self.tmpdir_manager.mkdtemp(cleanup=not detached)

        if self.load_path and os.path.isfile(self.load_path):
            rxt_file = self.load_path
        else:
            rxt_file = os.path.join(tmpdir, "context.rxt")
            self.save(rxt_file)

        context_file = context_filepath or \
            os.path.join(tmpdir, "context.%s" % sh.file_extension())

        # interpret this context and write out the native context file
        executor = self._create_executor(sh, parent_environ)
        executor.env.REZ_RXT_FILE = rxt_file
        executor.env.REZ_CONTEXT_FILE = context_file

        if actions_callback:
            actions_callback(executor)

        self._execute(executor)

        if post_actions_callback:
            post_actions_callback(executor)

        context_code = executor.get_output()
        with open(context_file, 'w') as f:
            f.write(context_code)

        quiet = quiet or \
            (RezToolsVisibility[config.rez_tools_visibility] == RezToolsVisibility.never)

        # spawn the shell subprocess
        p = sh.spawn_shell(context_file,
                           tmpdir,
                           rcfile=rcfile,
                           norc=norc,
                           stdin=stdin,
                           command=command,
                           env=parent_environ,
                           quiet=quiet,
                           pre_command=pre_command,
                           **Popen_args)
        if block:
            stdout, stderr = p.communicate()
            return p.returncode, stdout, stderr
        else:
            return p