Ejemplo n.º 1
0
 def test_isatty_from_env(self):
     self.assertEqual(
         NailgunProtocol.isatty_from_env({
             'NAILGUN_TTY_0': '1',
             'NAILGUN_TTY_1': '0',
             'NAILGUN_TTY_2': '1'
         }), (True, False, True))
Ejemplo n.º 2
0
 def test_isatty_from_env(self):
     self.assertEqual(
         NailgunProtocol.isatty_from_env(
             {"NAILGUN_TTY_0": "1", "NAILGUN_TTY_1": "0", "NAILGUN_TTY_2": "1"}
         ),
         (True, False, True),
     )
Ejemplo n.º 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)

        # 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
Ejemplo n.º 4
0
 def test_isatty_from_env_mixed(self):
   self.assertEquals(
     NailgunProtocol.isatty_from_env({
       'NAILGUN_TTY_0': '0',
       'NAILGUN_TTY_1': '1'
     }),
     (False, True, False)
   )
Ejemplo n.º 5
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((stdin_isatty, stdout_isatty, stderr_isatty)):
      with self._tty_stdio() as finalizer:
        yield finalizer
    else:
      with self._pipe_stdio(sock, stdin_isatty, stdout_isatty, stderr_isatty) as finalizer:
        yield finalizer
Ejemplo n.º 6
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((stdin_isatty, stdout_isatty, stderr_isatty)):
      with self._tty_stdio() as finalizer:
        yield finalizer
    else:
      with self._pipe_stdio(sock, stdin_isatty, stdout_isatty, stderr_isatty) as finalizer:
        yield finalizer
Ejemplo n.º 7
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
Ejemplo n.º 8
0
    def nailgunned_stdio(cls, sock, env, handle_stdin=True):
        """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(
            env)
        is_tty_capable = all((stdin_isatty, stdout_isatty, stderr_isatty))

        if is_tty_capable:
            with cls._tty_stdio(env) as finalizer:
                yield finalizer
        else:
            with cls._pipe_stdio(sock, stdin_isatty, stdout_isatty,
                                 stderr_isatty, handle_stdin) as finalizer:
                yield finalizer
Ejemplo n.º 9
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 NailgunStreamStdinReader.open(sock, isatty=stdin_isatty) as stdin,\
             NailgunStreamWriter.open(sock, ChunkType.STDOUT, None, isatty=stdout_isatty) as stdout,\
             NailgunStreamWriter.open(sock, ChunkType.STDERR, None, isatty=stderr_isatty) as stderr:
            with stdio_as(stdout=stdout, stderr=stderr, stdin=stdin):
                yield
Ejemplo n.º 10
0
  def _nailgunned_stdio(self, sock):
    """Redirects stdio to the connected socket speaking the nailgun protocol."""
    # Determine output tty capabilities from the environment.
    _, stdout_isatty, stderr_isatty = NailgunProtocol.isatty_from_env(self._env)

    # TODO(kwlzn): Implement remote input reading and fix the non-fork()-safe sys.stdin reference
    # in NailgunClient to enable support for interactive goals like `repl` etc.

    # Construct StreamWriters for stdout, stderr.
    streams = (
      NailgunStreamWriter(sock, ChunkType.STDOUT, isatty=stdout_isatty),
      NailgunStreamWriter(sock, ChunkType.STDERR, isatty=stderr_isatty)
    )

    # Launch the stdin StreamReader and redirect stdio.
    with stdio_as(*streams):
      yield
Ejemplo n.º 11
0
  def _nailgunned_stdio(self, sock):
    """Redirects stdio to the connected socket speaking the nailgun protocol."""
    # Determine output tty capabilities from the environment.
    _, stdout_isatty, stderr_isatty = NailgunProtocol.isatty_from_env(self._env)

    # TODO(kwlzn): Implement remote input reading and fix the non-fork()-safe sys.stdin reference
    # in NailgunClient to enable support for interactive goals like `repl` etc.

    # Construct StreamWriters for stdout, stderr.
    streams = (
      NailgunStreamWriter(sock, ChunkType.STDOUT, isatty=stdout_isatty),
      NailgunStreamWriter(sock, ChunkType.STDERR, isatty=stderr_isatty)
    )

    # Launch the stdin StreamReader and redirect stdio.
    with stdio_as(*streams):
      yield
Ejemplo n.º 12
0
  def nailgunned_stdio(cls, sock, env, handle_stdin=True):
    """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(env)
    is_tty_capable = all((stdin_isatty, stdout_isatty, stderr_isatty))

    if is_tty_capable:
      with cls._tty_stdio(env) as finalizer:
        yield finalizer
    else:
      with cls._pipe_stdio(
        sock,
        stdin_isatty,
        stdout_isatty,
        stderr_isatty,
        handle_stdin
      ) as finalizer:
        yield finalizer
Ejemplo n.º 13
0
  def _nailgunned_stdio(self, sock):
    """Redirects stdio to the connected socket speaking the nailgun protocol."""
    # Determine output tty capabilities from the environment.
    _, stdout_isatty, stderr_isatty = NailgunProtocol.isatty_from_env(self._env)

    # Construct a StreamReader for stdin.
    stdin_reader = NailgunStreamReader(sys.stdin, sock)

    # Construct StreamWriters for stdout, stderr.
    streams = (
      NailgunStreamWriter(sock, ChunkType.STDOUT, isatty=stdout_isatty),
      NailgunStreamWriter(sock, ChunkType.STDERR, isatty=stderr_isatty),
      stdin_reader
    )

    # Launch the stdin StreamReader and redirect stdio.
    with stdin_reader.running(), stdio_as(*streams):
      yield
Ejemplo n.º 14
0
    def _nailgunned_stdio(self, sock):
        """Redirects stdio to the connected socket speaking the nailgun protocol."""
        # Determine output tty capabilities from the environment.
        _, stdout_isatty, stderr_isatty = NailgunProtocol.isatty_from_env(
            self._env)

        # Construct a StreamReader for stdin.
        stdin_reader = NailgunStreamReader(sys.stdin, sock)

        # Construct StreamWriters for stdout, stderr.
        streams = (NailgunStreamWriter(sock,
                                       ChunkType.STDOUT,
                                       isatty=stdout_isatty),
                   NailgunStreamWriter(sock,
                                       ChunkType.STDERR,
                                       isatty=stderr_isatty), stdin_reader)

        # Launch the stdin StreamReader and redirect stdio.
        with stdin_reader.running(), stdio_as(*streams):
            yield
Ejemplo n.º 15
0
 def test_isatty_from_empty_env(self):
   self.assertEquals(NailgunProtocol.isatty_from_env({}), (False, False, False))