lsp-devtools icon indicating copy to clipboard operation
lsp-devtools copied to clipboard

Windows support

Open alcarney opened this issue 2 years ago • 2 comments

The lsp-devtools agent does not work on windows, due to the way it currently tries to obtain async readers/writers for stdin/stdout.

alcarney avatar Dec 27 '23 14:12 alcarney

Hello @alcarney ,

Is there any update on this issue?

I'm looking to use your (awesome!) test framework and was trying to use lsp-devtools record alongside test execution to record a session replay file that helps debug the server outside the test environment. That worked well on Linux but when I switched to Windows to check that it works there, the test infra fails when spawning lsp-devtools agent.

And I can confirm the failure by calling lsp-devtools agent outside the context of a test (error below).

Meanwhile I'm going to look into creating the replay file in a different way, perhaps by overriding something at the protocol level to intercept messages as they are getting sent.

$ lsp-devtools agent -- ada_language_server
Exception in callback _ProactorReadPipeTransport._loop_reading()
handle: <Handle _ProactorReadPipeTransport._loop_reading()>
Traceback (most recent call last):
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 305, in _loop_reading
    self._read_fut = self._loop._proactor.recv_into(self._sock, self._data)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 482, in recv_into
    self._register_with_iocp(conn)
  File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 752, in _register_with_iocp
    _overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
OSError: [WinError 6] The handle is invalid

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\it\local\e3\Lib\asyncio\events.py", line 84, in _run
    self._context.run(self._callback, *self._args)
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 315, in _loop_reading
    self._fatal_error(exc, 'Fatal read error on pipe transport')
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 132, in _fatal_error
    self._force_close(exc)
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 135, in _force_close
    if self._empty_waiter is not None and not self._empty_waiter.done():
       ^^^^^^^^^^^^^^^^^^
AttributeError: '_ProactorReadPipeTransport' object has no attribute '_empty_waiter'
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\data\ancr\venv\Scripts\lsp-devtools.exe\__main__.py", line 7, in <module>
  File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\cli.py", line 57, in main
    return parsed_args.run(parsed_args, extra)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\__init__.py", line 58, in run_agent
    asyncio.run(main(args, extra))
  File "C:\it\local\e3\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\base_events.py", line 654, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\__init__.py", line 50, in main
    await asyncio.gather(
  File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\agent.py", line 159, in start
    self.reader, self.writer = await get_streams(self.stdin, self.stdout)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\agent.py", line 129, in get_streams
    write_transport, write_protocol = await loop.connect_write_pipe(
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\base_events.py", line 1619, in connect_write_pipe
    transport = self._make_write_pipe_transport(pipe, protocol, waiter)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 681, in _make_write_pipe_transport
    return _ProactorWritePipeTransport(self,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 440, in __init__
    self._read_fut = self._loop._proactor.recv(self._sock, 16)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 459, in recv
    self._register_with_iocp(conn)
  File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 752, in _register_with_iocp
    _overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
OSError: [WinError 6] The handle is invalid
Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x00000263C72CF4C0>
Traceback (most recent call last):
  File "C:\it\local\e3\Lib\asyncio\base_subprocess.py", line 126, in __del__
  File "C:\it\local\e3\Lib\asyncio\base_subprocess.py", line 104, in close
  File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 109, in close
  File "C:\it\local\e3\Lib\asyncio\base_events.py", line 762, in call_soon
  File "C:\it\local\e3\Lib\asyncio\base_events.py", line 520, in _check_closed
RuntimeError: Event loop is closed

eliericha avatar Nov 25 '24 14:11 eliericha

Is there any update on this issue?

I think the answer is to change the agent so that it works similar to how pygls works - reading sys.stdin in a background thread using a ThreadPoolExecutor.

I was looking at making the switch as part of #192 but had issues getting some of the tests to pass so reverted to the current approach for the time being.

alcarney avatar Nov 26 '24 19:11 alcarney