Skip to content

Commit 7b04ad7

Browse files
Fix incorrect use of bytes() when invoking the daemon in a tty (#6181)
### Problem `pkill -f "pantsd \[" pantsd-runner && ./pants --enable-pantsd help` fails on master when run within a tty because we incorrectly try to pass an `int` directly to a `bytes`. This was introduced during #6159. ### Solution - Wrap the `bytes()` argument in a list in `NailgunProtocol.isatty_to_env()`. - Add unit testing which mocks out the tty querying to ensure the environment we return is valid. ### Result No more crashing when trying to create a pantsd in a tty. #### Thoughts This may be another argument for something like #6157. There may also be room for an integration test which opens up a "real" pty to catch issues like these in the future, but it's not clear to me how to do that right now.
1 parent 4aec12c commit 7b04ad7

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

src/python/pants/java/nailgun_protocol.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
import os
88
import struct
9-
from builtins import bytes, object, zip
9+
from builtins import object, str, zip
1010

1111
import six
12+
from future.utils import binary_type
1213

1314

1415
STDIO_DESCRIPTORS = (0, 1, 2)
@@ -245,7 +246,7 @@ def isatty_to_env(cls, stdin, stdout, stderr):
245246
def gen_env_vars():
246247
for fd_id, fd in zip(STDIO_DESCRIPTORS, (stdin, stdout, stderr)):
247248
is_atty = fd.isatty()
248-
yield (cls.TTY_ENV_TMPL.format(fd_id), bytes(int(is_atty)))
249+
yield (cls.TTY_ENV_TMPL.format(fd_id), binary_type(str(int(is_atty))))
249250
if is_atty:
250251
yield (cls.TTY_PATH_ENV.format(fd_id), os.ttyname(fd.fileno()) or '')
251252
return dict(gen_env_vars())

tests/python/pants_test/java/test_nailgun_protocol.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,45 @@ def test_isatty_from_env_mixed(self):
205205
(False, True, False)
206206
)
207207

208+
def _make_mock_stream(self, isatty, fileno):
209+
mock_stream = mock.Mock()
210+
mock_stream.isatty.return_value = isatty
211+
mock_stream.fileno.return_value = fileno
212+
return mock_stream
213+
214+
_fake_ttyname = '/this/is/not/a/real/tty'
215+
216+
@mock.patch('os.ttyname', autospec=True, spec_set=True)
217+
def test_isatty_to_env_with_mock_tty(self, mock_ttyname):
218+
mock_ttyname.return_value = self._fake_ttyname
219+
mock_stdin = self._make_mock_stream(True, 0)
220+
mock_stdout = self._make_mock_stream(True, 1)
221+
mock_stderr = self._make_mock_stream(True, 2)
222+
223+
self.assertEquals(
224+
NailgunProtocol.isatty_to_env(mock_stdin, mock_stdout, mock_stderr),
225+
{
226+
'NAILGUN_TTY_0': b'1',
227+
'NAILGUN_TTY_1': b'1',
228+
'NAILGUN_TTY_2': b'1',
229+
'NAILGUN_TTY_PATH_0': self._fake_ttyname,
230+
'NAILGUN_TTY_PATH_1': self._fake_ttyname,
231+
'NAILGUN_TTY_PATH_2': self._fake_ttyname,
232+
})
233+
234+
def test_isatty_to_env_without_tty(self):
235+
mock_stdin = self._make_mock_stream(False, 0)
236+
mock_stdout = self._make_mock_stream(False, 1)
237+
mock_stderr = self._make_mock_stream(False, 2)
238+
239+
self.assertEquals(
240+
NailgunProtocol.isatty_to_env(mock_stdin, mock_stdout, mock_stderr),
241+
{
242+
'NAILGUN_TTY_0': b'0',
243+
'NAILGUN_TTY_1': b'0',
244+
'NAILGUN_TTY_2': b'0',
245+
})
246+
208247
def test_construct_chunk(self):
209248
with self.assertRaises(TypeError):
210249
NailgunProtocol.construct_chunk(ChunkType.STDOUT, 1111)

0 commit comments

Comments
 (0)