def _execute_cmd(cmd, capture=False, break_callback=None, **kwargs):
    """
    Call given command, yielding output line by line if capture=True.

    break_callback: A callable that returns a boolean indicating whether to
    stop execution.
    See https://stackoverflow.com/a/4896288

    Must be yielded from.
    """
    if capture:
        kwargs["stdout"] = subprocess.PIPE
        kwargs["stderr"] = subprocess.STDOUT

    proc = subprocess.Popen(cmd, **kwargs)

    if not capture:
        # not capturing output, let subprocesses talk directly to terminal
        ret = proc.wait()
        if ret != 0:
            raise subprocess.CalledProcessError(ret, cmd)
        return

    # Capture output for logging.
    # Each line will be yielded as text.
    q = queue.Queue()

    def read_to_queue(proc, capture, q):
        try:
            for line in proc.stdout:
                q.put(line)
        finally:
            proc.wait()

    t = Thread(target=read_to_queue, args=(proc, capture, q))
    # thread dies with the program
    t.daemon = True
    t.start()

    terminated = False
    while True:
        try:
            line = q.get(True, timeout=DEFAULT_READ_TIMEOUT)
            yield line.decode("utf8", "replace")
            if break_callback and break_callback():
                proc.kill()
                terminated = True
        except queue.Empty:
            if break_callback and break_callback():
                proc.kill()
                terminated = True
            if not t.is_alive():
                break

    t.join()

    if terminated:
        raise ProcessTerminated(cmd)
    if proc.returncode != 0:
        raise subprocess.CalledProcessError(proc.returncode, cmd)

    Call given command, yielding output line by line if capture=True.

    break_callback: A callable that returns a boolean indicating whether to
    stop execution.
    See https://stackoverflow.com/a/4896288

    Must be yielded from.
    
binderhub/build_local.py