def _run_cmd()

in build/fbcode_builder/getdeps/runcmd.py [0:0]


def _run_cmd(cmd, env, cwd, allow_fail, log_fn) -> int:
    log_fn("---\n")
    try:
        cmd_str = " \\\n+      ".join(shellquote(arg) for arg in cmd)
    except TypeError:
        # eg: one of the elements is None
        raise RunCommandError("problem quoting cmd: %r" % cmd)

    if env:
        assert isinstance(env, Env)
        _print_env_diff(env, log_fn)

        # Convert from our Env type to a regular dict.
        # This is needed because python3 looks up b'PATH' and 'PATH'
        # and emits an error if both are present.  In our Env type
        # we'll return the same value for both requests, but we don't
        # have duplicate potentially conflicting values which is the
        # spirit of the check.
        env = dict(env.items())

    if cwd:
        log_fn("+ cd %s && \\\n" % shellquote(cwd))
        # Our long path escape sequence may confuse cmd.exe, so if the cwd
        # is short enough, strip that off.
        if is_windows() and (len(cwd) < 250) and cwd.startswith("\\\\?\\"):
            cwd = cwd[4:]

    log_fn("+ %s\n" % cmd_str)

    isinteractive = os.isatty(sys.stdout.fileno())
    if isinteractive:
        stdout = None
        sys.stdout.buffer.flush()
    else:
        stdout = subprocess.PIPE

    try:
        p = subprocess.Popen(
            cmd, env=env, cwd=cwd, stdout=stdout, stderr=subprocess.STDOUT
        )
    except (TypeError, ValueError, OSError) as exc:
        log_fn("error running `%s`: %s" % (cmd_str, exc))
        raise RunCommandError(
            "%s while running `%s` with env=%r\nos.environ=%r"
            % (str(exc), cmd_str, env, os.environ)
        )

    if not isinteractive:
        _pipe_output(p, log_fn)

    p.wait()
    if p.returncode != 0 and not allow_fail:
        raise subprocess.CalledProcessError(p.returncode, cmd)

    return p.returncode