Esempio n. 1
0
    def __rand__(self, cmd):
        with cmd.bgrun(retcode=self.retcode,
                       stdin=None,
                       stdout=PIPE,
                       stderr=PIPE) as p:
            outbuf = []
            errbuf = []
            out = p.stdout
            err = p.stderr
            buffers = {out: outbuf, err: errbuf}
            tee_to = {out: sys.stdout, err: sys.stderr}
            while p.poll() is None:
                ready, _, _ = select((out, err), (), ())
                for fd in ready:
                    buf = buffers[fd]
                    data, text = read_fd_decode_safely(fd, 4096)
                    if not data:  # eof
                        continue

                    # Python conveniently line-buffers stdout and stderr for
                    # us, so all we need to do is write to them

                    # This will automatically add up to three bytes if it cannot be decoded
                    tee_to[fd].write(text)

                    # And then "unbuffered" is just flushing after each write
                    if not self.buffered:
                        tee_to[fd].flush()

                    buf.append(data)

            stdout = ''.join([x.decode('utf-8') for x in outbuf])
            stderr = ''.join([x.decode('utf-8') for x in errbuf])
            return p.returncode, stdout, stderr
Esempio n. 2
0
    def __rand__(self, cmd):
        with cmd.bgrun(retcode=self.retcode, stdin=None, stdout=PIPE, stderr=PIPE) as p:
            outbuf = []
            errbuf = []
            out = p.stdout
            err = p.stderr
            buffers = {out: outbuf, err: errbuf}
            tee_to = {out: sys.stdout, err: sys.stderr}
            while p.poll() is None:
                ready, _, _ = select((out, err), (), ())
                for fd in ready:
                    buf = buffers[fd]
                    data, text = read_fd_decode_safely(fd, 4096)
                    if not data:  # eof
                        continue

                    # Python conveniently line-buffers stdout and stderr for
                    # us, so all we need to do is write to them

                    # This will automatically add up to three bytes if it cannot be decoded
                    tee_to[fd].write(text)

                    # And then "unbuffered" is just flushing after each write
                    if not self.buffered:
                        tee_to[fd].flush()

                    buf.append(data)

            stdout = "".join([x.decode("utf-8") for x in outbuf])
            stderr = "".join([x.decode("utf-8") for x in errbuf])
            return p.returncode, stdout, stderr
Esempio n. 3
0
def tee(process: PlumbumLocalPopen,
        buffered: bool = True) -> tp.Tuple[int, str, str]:
    """
    Adapted from plumbum's TEE implementation.

    Plumbum's TEE does not allow access to the underlying popen object, which we
    need to properly handle keyboard interrupts. Therefore, we just copy the
    relevant portion of plumbum's implementation and create the popen object by
    ourself.
    """
    outbuf: tp.List[bytes] = []
    errbuf: tp.List[bytes] = []
    out = process.stdout
    err = process.stderr
    buffers = {out: outbuf, err: errbuf}
    tee_to = {out: sys.stdout, err: sys.stderr}
    done = False
    while not done:
        # After the process exits, we have to do one more
        # round of reading in order to drain any data in the
        # pipe buffer. Thus, we check poll() here,
        # unconditionally enter the read loop, and only then
        # break out of the outer loop if the process has
        # exited.
        done = process.poll() is not None

        # We continue this loop until we've done a full
        # `select()` call without collecting any input. This
        # ensures that our final pass -- after process exit --
        # actually drains the pipe buffers, even if it takes
        # multiple calls to read().
        progress = True
        while progress:
            progress = False
            ready, _, _ = select((out, err), (), ())
            # logging.info(f"Streams ready: {[r.fileno() for r in ready]}")
            for file_descriptor in ready:
                buf = buffers[file_descriptor]
                data, text = read_fd_decode_safely(file_descriptor, 4096)
                if not data:  # eof
                    continue
                progress = True

                # Python conveniently line-buffers stdout and stderr for
                # us, so all we need to do is write to them

                # This will automatically add up to three bytes if it cannot be
                # decoded
                tee_to[file_descriptor].write(text)

                # And then "unbuffered" is just flushing after each write
                if not buffered:
                    tee_to[file_descriptor].flush()

                buf.append(data)

    stdout = "".join([x.decode("utf-8") for x in outbuf])
    stderr = "".join([x.decode("utf-8") for x in errbuf])
    return process.returncode, stdout, stderr
Esempio n. 4
0
    def __rand__(self, cmd):
        with cmd.bgrun(
                retcode=self.retcode,
                stdin=None,
                stdout=PIPE,
                stderr=PIPE,
                timeout=self.timeout,
        ) as p:
            outbuf = []
            errbuf = []
            out = p.stdout
            err = p.stderr
            buffers = {out: outbuf, err: errbuf}
            tee_to = {out: sys.stdout, err: sys.stderr}
            done = False
            while not done:
                # After the process exits, we have to do one more
                # round of reading in order to drain any data in the
                # pipe buffer. Thus, we check poll() here,
                # unconditionally enter the read loop, and only then
                # break out of the outer loop if the process has
                # exited.
                done = p.poll() is not None

                # We continue this loop until we've done a full
                # `select()` call without collecting any input. This
                # ensures that our final pass -- after process exit --
                # actually drains the pipe buffers, even if it takes
                # multiple calls to read().
                progress = True
                while progress:
                    progress = False
                    ready, _, _ = select((out, err), (), ())
                    for fd in ready:
                        buf = buffers[fd]
                        data, text = read_fd_decode_safely(fd, 4096)
                        if not data:  # eof
                            continue
                        progress = True

                        # Python conveniently line-buffers stdout and stderr for
                        # us, so all we need to do is write to them

                        # This will automatically add up to three bytes if it cannot be decoded
                        tee_to[fd].write(text)

                        # And then "unbuffered" is just flushing after each write
                        if not self.buffered:
                            tee_to[fd].flush()

                        buf.append(data)

            stdout = "".join([x.decode("utf-8") for x in outbuf])
            stderr = "".join([x.decode("utf-8") for x in errbuf])
            return p.returncode, stdout, stderr
Esempio n. 5
0
    def __rand__(self, cmd):
        with cmd.bgrun(
                retcode=self.retcode,
                stdin=None,
                stdout=PIPE,
                stderr=PIPE,
                timeout=self.timeout) as p:
            outbuf = []
            errbuf = []
            out = p.stdout
            err = p.stderr
            buffers = {out: outbuf, err: errbuf}
            tee_to = {out: sys.stdout, err: sys.stderr}
            done = False
            while not done:
                # After the process exits, we have to do one more
                # round of reading in order to drain any data in the
                # pipe buffer. Thus, we check poll() here,
                # unconditionally enter the read loop, and only then
                # break out of the outer loop if the process has
                # exited.
                done = (p.poll() is not None)

                # We continue this loop until we've done a full
                # `select()` call without collecting any input. This
                # ensures that our final pass -- after process exit --
                # actually drains the pipe buffers, even if it takes
                # multiple calls to read().
                progress = True
                while progress:
                    progress = False
                    ready, _, _ = select((out, err), (), ())
                    for fd in ready:
                        buf = buffers[fd]
                        data, text = read_fd_decode_safely(fd, 4096)
                        if not data:  # eof
                            continue
                        progress = True

                        # Python conveniently line-buffers stdout and stderr for
                        # us, so all we need to do is write to them

                        # This will automatically add up to three bytes if it cannot be decoded
                        tee_to[fd].write(text)

                        # And then "unbuffered" is just flushing after each write
                        if not self.buffered:
                            tee_to[fd].flush()

                        buf.append(data)

            stdout = ''.join([x.decode('utf-8') for x in outbuf])
            stderr = ''.join([x.decode('utf-8') for x in errbuf])
            return p.returncode, stdout, stderr