Attach to pid support (#1701)

* Fix launcher test

* Attach to pid support

* Address comments.

* Minor tweaks
This commit is contained in:
Karthik Nadig 2019-08-19 14:08:23 -07:00 committed by GitHub
parent e94980f86c
commit 9ece432dff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 4 deletions

View file

@ -80,6 +80,48 @@ def spawn_and_connect(request):
before_accept=lambda address: _parse_request_and_spawn(request, address),
)
def attach_by_pid(request):
"""Start server to receive connection from the debug server injected into the
debuggee process.
"""
def _parse_request_and_inject(request, address):
cmdline = [sys.executable]
host, port = address
ptvsd_args = request("ptvsdArgs", json.array(unicode))
cmdline += [
compat.filename(ptvsd.__main__.__file__),
"--client",
"--host",
host,
"--port",
str(port),
"--pid",
str(request("processId", int))
] + ptvsd_args
log.debug("Launching debugger injector: {0!r}", cmdline)
try:
# This process will immediately exit after injecting debug server
proc = subprocess.Popen(
cmdline,
bufsize=0,
)
except Exception as exc:
raise request.cant_handle("Error launching debug process: {0}", exc)
proc.wait()
if proc.returncode != 0:
raise request.cant_handle(
"Failed to inject debugger with error code: {0}",
proc.returncode,
)
channels.Channels().accept_connection_from_server(
("127.0.0.1", 0),
before_accept=lambda address: _parse_request_and_inject(address),
)
def _parse_request_and_spawn(request, address):
spawn_info = _parse_request(request, address)

View file

@ -199,9 +199,12 @@ class IDEMessages(Messages):
_Shared.readonly_attrs.add("terminate_on_disconnect")
self._debug_config(request)
options.host = request("host", options.host)
options.port = request("port", options.port)
_channels.connect_to_server(address=(options.host, options.port))
if "processId" in request:
debuggee.attach_by_pid(request)
else:
options.host = request("host", options.host)
options.port = request("port", options.port)
_channels.connect_to_server(address=(options.host, options.port))
return self._configure(request)

View file

@ -8,6 +8,7 @@ import errno
import os.path
import platform
import pytest
import socket
import subprocess
import sys
@ -17,10 +18,31 @@ from ptvsd.common import launcher
launcher_py = os.path.abspath(launcher.__file__)
class ReceivePid(object):
def start_server(self):
self.listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.listener.bind(("127.0.0.1", 0))
self.listener.listen(1)
self.host, self.port = self.listener.getsockname()
return (self.host, self.port)
def wait_for_pid(self):
try:
sock, _ = self.listener.accept()
finally:
self.listener.close()
try:
data = sock.makefile().read()
finally:
sock.close()
return -1 if data == b"" else int(data)
@pytest.mark.parametrize("run_as", ["program", "module", "code"])
@pytest.mark.parametrize("mode", ["normal", "abnormal", "normal+abnormal", ""])
@pytest.mark.parametrize("seperator", ["seperator", ""])
def test_launcher_parser(mode, seperator, run_as):
@pytest.mark.parametrize("port", ["12345", ""])
def test_launcher_parser(mode, seperator, run_as, port):
args = []
switch = mode.split("+")
@ -31,9 +53,13 @@ def test_launcher_parser(mode, seperator, run_as):
if "abnormal" in switch:
args += [launcher.WAIT_ON_ABNORMAL_SWITCH]
if port:
args += [launcher.INTERNAL_PORT_SWITCH, port]
if seperator:
args += ["--"]
if run_as == "file":
expected = ["myscript.py", "--arg1", "--arg2", "--arg3", "--", "more args"]
elif run_as == "module":
@ -67,12 +93,17 @@ def test_launcher(pyfile, mode, exit_code, run_as):
switch = mode.split("+")
pid_server = ReceivePid()
_, port = pid_server.start_server()
if "normal" in switch:
args += [launcher.WAIT_ON_NORMAL_SWITCH]
if "abnormal" in switch:
args += [launcher.WAIT_ON_ABNORMAL_SWITCH]
args += [launcher.INTERNAL_PORT_SWITCH, str(port)]
args += ["--"]
if run_as == "file":
@ -110,6 +141,8 @@ def test_launcher(pyfile, mode, exit_code, run_as):
stdout=subprocess.PIPE,
)
assert pid_server.wait_for_pid() >= -1
if wait_for_user:
outstr = b""
while not outstr.endswith(b". . . "):