Пример #1
0
    def _pipe_stdio(cls, maybe_shutdown_socket, stdin_isatty, stdout_isatty,
                    stderr_isatty, handle_stdin):
        """Handles stdio redirection in the case of pipes and/or mixed pipes and ttys."""
        stdio_writers = ((ChunkType.STDOUT, stdout_isatty), (ChunkType.STDERR,
                                                             stderr_isatty))
        types, ttys = zip(*(stdio_writers))

        @contextmanager
        def maybe_handle_stdin(want):
            if want:
                with NailgunStreamStdinReader.open(maybe_shutdown_socket,
                                                   stdin_isatty) as fd:
                    yield fd
            else:
                with open("/dev/null", "rb") as fh:
                    yield fh.fileno()

        # TODO https://github.com/pantsbuild/pants/issues/7653
        with maybe_handle_stdin(
                handle_stdin) as stdin_fd, PipedNailgunStreamWriter.open_multi(
                    maybe_shutdown_socket.socket, types,
                    ttys) as ((stdout_pipe, stderr_pipe),
                              writer), stdio_as(stdout_fd=stdout_pipe.write_fd,
                                                stderr_fd=stderr_pipe.write_fd,
                                                stdin_fd=stdin_fd):
            # N.B. This will be passed to and called by the `DaemonExiter` prior to sending an
            # exit chunk, to avoid any socket shutdown vs write races.
            stdout, stderr = sys.stdout, sys.stderr

            def finalizer():
                try:
                    stdout.flush()
                    stderr.flush()
                finally:
                    time.sleep(
                        0.001
                    )  # HACK: Sleep 1ms in the main thread to free the GIL.
                    stdout_pipe.stop_writing()
                    stderr_pipe.stop_writing()
                    writer.join(timeout=60)
                    if writer.isAlive():
                        raise NailgunStreamWriterError(
                            "pantsd timed out while waiting for the stdout/err to finish writing to the socket."
                        )

            yield finalizer
Пример #2
0
  def test_auto_shutdown_on_write_end_closed(self, mock_writer, mock_select, mock_read):
    pipe = Pipe.create(False)
    test_data = [b"A"] * 1000 + [b'']
    mock_read.side_effect = test_data
    mock_select.side_effect = [([pipe.read_fd], [], [])] * len(test_data)

    writer = PipedNailgunStreamWriter(
      pipes=[pipe],
      socket=self.mock_socket,
      chunk_type=(ChunkType.STDOUT,),
      chunk_eof_type=None,
      buf_size=len(b"A")
    )

    with writer.running():
      pipe.stop_writing()
      writer.join(1)
      self.assertFalse(writer.is_alive())

    mock_writer.assert_has_calls([unittest.mock.call(unittest.mock.ANY, ChunkType.STDOUT, b'A')] * (len(test_data) - 1))