Skip to content

Commit 5601342

Browse files
Pavel Minaevint19h
Pavel Minaev
authored andcommitted
Fix #1217: Support "restart" in "terminated" event for "attach"{"listen"}
Request client to restart the adapter if "restart":true was specified in the debug configuration.
1 parent e9dc3e8 commit 5601342

File tree

4 files changed

+38
-3
lines changed

4 files changed

+38
-3
lines changed

.vscode/launch.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"host": "127.0.0.1"
5353
},
5454
"logToFile": true,
55+
//"restart": true,
5556
"debugAdapterPath": "${workspaceFolder}/src/debugpy/adapter"
5657
},
5758
{

src/debugpy/adapter/clients.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class Expectations(components.Capabilities):
4444
def __init__(self, sock):
4545
if sock == "stdio":
4646
log.info("Connecting to client over stdio...", self)
47+
self.using_stdio = True
4748
stream = messaging.JsonIOStream.from_stdio()
4849
# Make sure that nothing else tries to interfere with the stdio streams
4950
# that are going to be used for DAP communication from now on.
@@ -52,6 +53,7 @@ def __init__(self, sock):
5253
sys.stdout = stdout = open(os.devnull, "w")
5354
atexit.register(stdout.close)
5455
else:
56+
self.using_stdio = False
5557
stream = messaging.JsonIOStream.from_socket(sock)
5658

5759
with sessions.Session() as session:
@@ -69,6 +71,11 @@ def __init__(self, sock):
6971
"""The "launch" or "attach" request as received from the client.
7072
"""
7173

74+
self.restart_requested = False
75+
"""Whether the client requested the debug adapter to be automatically
76+
restarted via "restart":true in the start request.
77+
"""
78+
7279
self._initialize_request = None
7380
"""The "initialize" request as received from the client, to propagate to the
7481
server later."""
@@ -471,6 +478,7 @@ def attach_request(self, request):
471478
host = listen("host", "127.0.0.1")
472479
port = listen("port", int)
473480
adapter.access_token = None
481+
self.restart_requested = request("restart", False)
474482
host, port = servers.serve(host, port)
475483
else:
476484
if not servers.is_serving():
@@ -651,6 +659,10 @@ def debugpySystemInfo_request(self, request):
651659

652660
@message_handler
653661
def terminate_request(self, request):
662+
# If user specifically requests to terminate, it means that they don't want
663+
# debug session auto-restart kicking in.
664+
self.restart_requested = False
665+
654666
if self._forward_terminate_request:
655667
# According to the spec, terminate should try to do a gracefull shutdown.
656668
# We do this in the server by interrupting the main thread with a Ctrl+C.
@@ -665,11 +677,29 @@ def terminate_request(self, request):
665677

666678
@message_handler
667679
def disconnect_request(self, request):
680+
# If user specifically requests to disconnect, it means that they don't want
681+
# debug session auto-restart kicking in.
682+
self.restart_requested = False
683+
668684
terminate_debuggee = request("terminateDebuggee", bool, optional=True)
669685
if terminate_debuggee == ():
670686
terminate_debuggee = None
671687
self.session.finalize('client requested "disconnect"', terminate_debuggee)
672-
return {}
688+
request.respond({})
689+
690+
if self.using_stdio:
691+
# There's no way for the client to reconnect to this adapter once it disconnects
692+
# from this session, so close any remaining server connections.
693+
servers.stop_serving()
694+
log.info("{0} disconnected from stdio; closing remaining server connections.", self)
695+
for conn in servers.connections():
696+
try:
697+
conn.channel.close()
698+
except Exception:
699+
log.swallow_exception()
700+
701+
def disconnect(self):
702+
super().disconnect()
673703

674704
def notify_of_subprocess(self, conn):
675705
log.info("{1} is a subprocess of {0}.", self, conn)
@@ -689,7 +719,7 @@ def notify_of_subprocess(self, conn):
689719
self.known_subprocesses.add(conn)
690720
self.session.notify_changed()
691721

692-
for key in "processId", "listen", "preLaunchTask", "postDebugTask", "request":
722+
for key in "processId", "listen", "preLaunchTask", "postDebugTask", "request", "restart":
693723
body.pop(key, None)
694724

695725
body["name"] = "Subprocess {0}".format(conn.pid)

src/debugpy/adapter/sessions.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,11 @@ def _finalize(self, why, terminate_debuggee):
226226
if self.client.is_connected:
227227
# Tell the client that debugging is over, but don't close the channel until it
228228
# tells us to, via the "disconnect" request.
229+
body = {}
230+
if self.client.restart_requested:
231+
body["restart"] = True
229232
try:
230-
self.client.channel.send_event("terminated")
233+
self.client.channel.send_event("terminated", body)
231234
except Exception:
232235
pass
233236

src/debugpy/common/log.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ def report_paths(get_paths, label=None):
321321
prefix = " " * len(prefix)
322322

323323
report("System paths:\n")
324+
report_paths("sys.executable")
324325
report_paths("sys.prefix")
325326
report_paths("sys.base_prefix")
326327
report_paths("sys.real_prefix")

0 commit comments

Comments
 (0)