mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Detour pydev_monkey.patch_args and construct the appropriate ptvsd command line.
This commit is contained in:
parent
317e7b0657
commit
bad34258ac
3 changed files with 103 additions and 1 deletions
|
|
@ -8,6 +8,7 @@ import atexit
|
|||
import itertools
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
|
||||
try:
|
||||
|
|
@ -121,3 +122,100 @@ def init_subprocess(initial_pid, initial_request, parent_pid, parent_port, first
|
|||
ptvsd.wait_for_attach()
|
||||
|
||||
|
||||
def patch_args(args):
|
||||
"""
|
||||
Patches a command line invoking Python such that it has the same meaning, but
|
||||
the process runs under ptvsd. In general, this means that given something like:
|
||||
|
||||
python -R -Q warn -m app
|
||||
|
||||
the result should be:
|
||||
|
||||
python -R -Q warn -m ptvsd --host localhost --port 0 --multiprocess --wait -m app
|
||||
|
||||
Note that the first -m above is interpreted by Python, and the second by ptvsd.
|
||||
"""
|
||||
|
||||
args = list(args)
|
||||
print(args)
|
||||
|
||||
# First, let's find the target of the invocation. This is one of:
|
||||
#
|
||||
# filename.py
|
||||
# -m module_name
|
||||
# -c "code"
|
||||
# -
|
||||
#
|
||||
# This needs to take into account other switches that have values:
|
||||
#
|
||||
# -Q -W -X --check-hash-based-pycs
|
||||
#
|
||||
# because in something like "-X -c", -c is a value, not a switch.
|
||||
expect_value = False
|
||||
for i, arg in enumerate(args):
|
||||
# Skip Python binary.
|
||||
if i == 0:
|
||||
continue
|
||||
|
||||
if arg == '-':
|
||||
# We do not support debugging while reading from stdin, so just let this
|
||||
# process run without debugging.
|
||||
return args
|
||||
|
||||
if expect_value:
|
||||
expect_value = False
|
||||
continue
|
||||
|
||||
if not arg.startswith('-') or arg in ('-c', '-m'):
|
||||
break
|
||||
|
||||
if arg.startswith('--'):
|
||||
expect_value = (arg == '--check-hash-based-pycs')
|
||||
continue
|
||||
|
||||
# All short switches other than -c and -m can be combined together, including
|
||||
# those with values. So, instead of -R -B -v -Q old, we might see -RBvQ old.
|
||||
# Furthermore, the value itself can be concatenated with the switch, so rather
|
||||
# than -Q old, we might have -Qold. When switches are combined, any switch that
|
||||
# has a value "eats" the rest of the argument; for example, -RBQv is treated as
|
||||
# -R -B -Qv, and not as -R -B -Q -v. So, we need to check whether one of 'Q',
|
||||
# 'W' or 'X' was present somewhere in the arg, and whether there was anything
|
||||
# following it in the arg. If it was there but nothing followed after it, then
|
||||
# the switch is expecting a value.
|
||||
split = re.split(r'[QWX]', arg, maxsplit=1)
|
||||
expect_value = (len(split) > 1 and split[-1] != '')
|
||||
|
||||
else:
|
||||
# Didn't find the target, so we don't know how to patch this command line; let
|
||||
# it run without debugging.
|
||||
return args
|
||||
|
||||
if not args[i].startswith('-'):
|
||||
# If it was a filename, it can be a Python file, a directory, or a zip archive
|
||||
# that is treated as if it were a directory. However, pydevd only supports the
|
||||
# first scenario. Distinguishing between these can be tricky, and getting it
|
||||
# wrong means that process fails to launch, so be conservative.
|
||||
if not args[i].endswith('.py'):
|
||||
print('!!!', args[i])
|
||||
return args
|
||||
|
||||
# Now we need to inject the ptvsd invocation right before the target. The target
|
||||
# itself can remain as is, because ptvsd is compatible with Python in that respect.
|
||||
args[i:i] = [
|
||||
'-m', 'ptvsd',
|
||||
'--server-host', 'localhost',
|
||||
'--port', '0',
|
||||
'--multiprocess',
|
||||
'--wait'
|
||||
]
|
||||
|
||||
print(args)
|
||||
return args
|
||||
|
||||
|
||||
def patch_and_quote_args(args):
|
||||
# On Windows, pydevd expects arguments to be quoted and escaped as necessary, such
|
||||
# that simply concatenating them via ' ' produces a valid command line. This wraps
|
||||
# patch_args and applies quoting (quote_args contains platform check), so that the
|
||||
# implementation of patch_args can be kept simple.
|
||||
return pydev_monkey.quote_args(patch_args(args))
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ def install(pydevd_module, address,
|
|||
pydevd_comm.start_client = _start_client
|
||||
|
||||
# This is invoked when a child process is spawned with multiproc debugging enabled.
|
||||
pydev_monkey._get_python_c_args = get_python_c_args
|
||||
pydev_monkey.patch_args = multiproc.patch_and_quote_args
|
||||
|
||||
# Ensure that pydevd is using our functions.
|
||||
pydevd_module.start_server = _start_server
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ def create_server(host, port, timeout=None):
|
|||
host = 'localhost'
|
||||
server = _new_sock()
|
||||
server.bind((host, port))
|
||||
|
||||
# _, listener_port = server.getsockname()
|
||||
# print('Listening on', listener_port)
|
||||
|
||||
if timeout is not None:
|
||||
server.settimeout(timeout)
|
||||
server.listen(1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue