Example #1
0
    def _pipe_stdio(self, sock, stdin_isatty, stdout_isatty, stderr_isatty):
        """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))
        with NailgunStreamStdinReader.open(sock, stdin_isatty) as stdin_fd,\
             NailgunStreamWriter.open_multi(sock, types, ttys) as ((stdout_fd, stderr_fd), writer),\
             stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(
                        .001
                    )  # HACK: Sleep 1ms in the main thread to free the GIL.
                    writer.stop()
                    writer.join()
                    stdout.close()
                    stderr.close()

            yield finalizer
Example #2
0
    def _nailgunned_stdio(self, sock):
        """Redirects stdio to the connected socket speaking the nailgun protocol."""
        # Determine output tty capabilities from the environment.
        stdin_isatty, stdout_isatty, stderr_isatty = NailgunProtocol.isatty_from_env(
            self._env)

        # Launch a thread to read stdin data from the socket (the only messages expected from the client
        # for the remainder of the protocol), and threads to copy from stdout/stderr pipes onto the
        # socket.
        with NailgunStreamWriter.open_multi(
               sock,
               (ChunkType.STDOUT, ChunkType.STDERR),
               None,
               (stdout_isatty, stderr_isatty)
             ) as ((stdout_fd, stderr_fd), writer),\
             NailgunStreamStdinReader.open(sock, stdin_isatty) as stdin_fd,\
             stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(
                        .001
                    )  # HACK: Sleep 1ms in the main thread to free the GIL.
                    writer.stop()
                    writer.join()
                    stdout.close()
                    stderr.close()

            yield finalizer
Example #3
0
    def _nailgunned_stdio(self, sock):
        """Redirects stdio to the connected socket speaking the nailgun protocol."""
        # Determine output tty capabilities from the environment.
        stdin_isatty, stdout_isatty, stderr_isatty = NailgunProtocol.isatty_from_env(
            self._env)

        # If all stdio is a tty, there's only one logical I/O device (the tty device). This happens to
        # be addressable as a file in OSX and Linux, so we take advantage of that and directly open the
        # character device for output redirection - eliminating the need to directly marshall any
        # interactive stdio back/forth across the socket and permitting full, correct tty control with
        # no middle-man.
        if all((stdin_isatty, stdout_isatty, stderr_isatty)):
            stdin_ttyname, stdout_ttyname, stderr_ttyname = NailgunProtocol.ttynames_from_env(
                self._env)
            assert stdin_ttyname == stdout_ttyname == stderr_ttyname, (
                'expected all stdio ttys to be the same, but instead got: {}\n'
                'please file a bug at http://github.com/pantsbuild/pants'.
                format([stdin_ttyname, stdout_ttyname, stderr_ttyname]))
            with open(stdin_ttyname, 'rb+wb', 0) as tty:
                tty_fileno = tty.fileno()
                with stdio_as(stdin_fd=tty_fileno,
                              stdout_fd=tty_fileno,
                              stderr_fd=tty_fileno):

                    def finalizer():
                        termios.tcdrain(tty_fileno)

                    yield finalizer
        else:
            stdio_writers = ((ChunkType.STDOUT, stdout_isatty),
                             (ChunkType.STDERR, stderr_isatty))
            types, ttys = zip(*(stdio_writers))
            with NailgunStreamStdinReader.open(sock, stdin_isatty) as stdin_fd,\
                 NailgunStreamWriter.open_multi(sock, types, ttys) as ((stdout_fd, stderr_fd), writer),\
                 stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(
                            .001
                        )  # HACK: Sleep 1ms in the main thread to free the GIL.
                        writer.stop()
                        writer.join()
                        stdout.close()
                        stderr.close()

                yield finalizer
Example #4
0
    def _pipe_stdio(cls, sock, 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:
                # TODO: Launching this thread pre-fork to handle @rule input currently results
                # in an unhandled SIGILL in `src/python/pants/engine/scheduler.py, line 313 in pre_fork`.
                # More work to be done here in https://github.com/pantsbuild/pants/issues/6005
                with NailgunStreamStdinReader.open(sock, stdin_isatty) as fd:
                    yield fd
            else:
                with open('/dev/null', 'rb') as fh:
                    yield fh.fileno()

        with maybe_handle_stdin(handle_stdin) as stdin_fd,\
             NailgunStreamWriter.open_multi(sock, types, ttys) as ((stdout_fd, stderr_fd), writer),\
             stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(
                        .001
                    )  # HACK: Sleep 1ms in the main thread to free the GIL.
                    writer.stop()
                    writer.join()
                    stdout.close()
                    stderr.close()

            yield finalizer
    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,\
          NailgunStreamWriter.open_multi(maybe_shutdown_socket.socket, types, ttys) as ((stdout_fd, stderr_fd), writer),\
          stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(
                        .001
                    )  # HACK: Sleep 1ms in the main thread to free the GIL.
                    writer.stop()
                    writer.join()
                    stdout.close()
                    stderr.close()

            yield finalizer
  def _pipe_stdio(cls, sock, 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:
        # TODO: Launching this thread pre-fork to handle @rule input currently results
        # in an unhandled SIGILL in `src/python/pants/engine/scheduler.py, line 313 in pre_fork`.
        # More work to be done here in https://github.com/pantsbuild/pants/issues/6005
        with NailgunStreamStdinReader.open(sock, stdin_isatty) as fd:
          yield fd
      else:
        with open('/dev/null', 'rb') as fh:
          yield fh.fileno()

    with maybe_handle_stdin(handle_stdin) as stdin_fd,\
         NailgunStreamWriter.open_multi(sock, types, ttys) as ((stdout_fd, stderr_fd), writer),\
         stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(.001)  # HACK: Sleep 1ms in the main thread to free the GIL.
          writer.stop()
          writer.join()
          stdout.close()
          stderr.close()
      yield finalizer
 def _pipe_stdio(self, sock, stdin_isatty, stdout_isatty, stderr_isatty):
   """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))
   with NailgunStreamStdinReader.open(sock, stdin_isatty) as stdin_fd,\
        NailgunStreamWriter.open_multi(sock, types, ttys) as ((stdout_fd, stderr_fd), writer),\
        stdio_as(stdout_fd=stdout_fd, stderr_fd=stderr_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(.001)  # HACK: Sleep 1ms in the main thread to free the GIL.
         writer.stop()
         writer.join()
         stdout.close()
         stderr.close()
     yield finalizer