def run_command(
    cmd,
    stdin=None,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    shell=False,
    cwd=None,
    env=None,
    close_fds=None,
):
    """
    Run the provided command in a subprocess and wait until it completes.

    :param cmd: Command to run.
    :type cmd: ``str`` or ``list``

    :param stdin: Process stdin.
    :type stdin: ``object``

    :param stdout: Process stdout.
    :type stdout: ``object``

    :param stderr: Process stderr.
    :type stderr: ``object``

    :param shell: True to use a shell.
    :type shell ``boolean``

    :param cwd: Optional working directory.
    :type cwd: ``str``

    :param env: Optional environment to use with the command. If not provided,
                environment from the current process is inherited.
    :type env: ``dict``

    :param close_fds: True to close all the fds. By default when None is provided we rely on
                      default upstream behavior which may be Python version specific.

    :rtype: ``tuple`` (exit_code, stdout, stderr)
    """
    if not isinstance(cmd, (list, tuple) + six.string_types):
        raise TypeError(
            f"Command must be a type of list, tuple, or string, not '{type(cmd)}'."
        )

    if not env:
        env = os.environ.copy()

    kwargs = {}
    if close_fds is not None:
        kwargs["close_fds"] = close_fds

    process = concurrency.subprocess_popen(
        args=cmd,
        stdin=stdin,
        stdout=stdout,
        stderr=stderr,
        env=env,
        cwd=cwd,
        shell=shell,
        **kwargs,
    )
    stdout, stderr = process.communicate()
    exit_code = process.returncode

    if six.PY3:
        return (exit_code, stdout.decode(), stderr.decode())
    else:
        return (exit_code, stdout, stderr)

    Run the provided command in a subprocess and wait until it completes.

    :param cmd: Command to run.
    :type cmd: ``str`` or ``list``

    :param stdin: Process stdin.
    :type stdin: ``object``

    :param stdout: Process stdout.
    :type stdout: ``object``

    :param stderr: Process stderr.
    :type stderr: ``object``

    :param shell: True to use a shell.
    :type shell ``boolean``

    :param cwd: Optional working directory.
    :type cwd: ``str``

    :param env: Optional environment to use with the command. If not provided,
                environment from the current process is inherited.
    :type env: ``dict``

    :param close_fds: True to close all the fds. By default when None is provided we rely on
                      default upstream behavior which may be Python version specific.

    :rtype: ``tuple`` (exit_code, stdout, stderr)
    
st2common/st2common/util/shell.py