mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Fix #156: Add a flag for the old way of handling args from a launch config
Add new property "argsExpansion", which defaults to "shell", but can be explicitly set to "none" to request no expansion. Propagate "args" to launcher via CLI or JSON, depending on the value of "argsExpansion". Move the logic to compute process name back to the adapter, alongside other processing of "launch" targets.
This commit is contained in:
parent
7a332142ce
commit
1a44e70206
5 changed files with 45 additions and 49 deletions
|
|
@ -272,22 +272,19 @@ class Client(components.Component):
|
|||
|
||||
return value
|
||||
|
||||
# Propagate command line arguments via launcher CLI rather than "args", so that
|
||||
# they get shell expansion applied to them in "runInTerminal" scenarios.
|
||||
|
||||
program = module = code = ()
|
||||
if "program" in request:
|
||||
program = request("program", unicode)
|
||||
args = [program]
|
||||
# process_name = program
|
||||
request.arguments["processName"] = program
|
||||
if "module" in request:
|
||||
module = request("module", unicode)
|
||||
args = ["-m", module]
|
||||
# process_name = module
|
||||
request.arguments["processName"] = module
|
||||
if "code" in request:
|
||||
code = request("code", json.array(unicode, vectorize=True, size=(1,)))
|
||||
args = ["-c", "\n".join(code)]
|
||||
# process_name = cmdline[0]
|
||||
request.arguments["processName"] = "-c"
|
||||
|
||||
num_targets = len([x for x in (program, module, code) if x != ()])
|
||||
if num_targets == 0:
|
||||
|
|
@ -299,7 +296,11 @@ class Client(components.Component):
|
|||
'"program", "module", and "code" are mutually exclusive'
|
||||
)
|
||||
|
||||
args += request("args", json.array(unicode))
|
||||
# Propagate "args" via CLI if and only if shell expansion is requested.
|
||||
args_expansion = request("argsExpansion", json.enum("shell", "none", optional=True))
|
||||
if args_expansion == "shell":
|
||||
args += request("args", json.array(unicode))
|
||||
del request.arguments["args"]
|
||||
|
||||
cwd = request("cwd", unicode, optional=True)
|
||||
if cwd == ():
|
||||
|
|
@ -536,6 +537,8 @@ class Client(components.Component):
|
|||
body["name"] = fmt("Subprocess {0}", conn.pid)
|
||||
body["request"] = "attach"
|
||||
body["subProcessId"] = conn.pid
|
||||
body.pop("processName", None)
|
||||
body.pop("args", None)
|
||||
|
||||
host = body.pop("host", None)
|
||||
port = body.pop("port", None)
|
||||
|
|
|
|||
|
|
@ -67,14 +67,14 @@ def launch_request(request):
|
|||
debugpy_args = request("debugpyArgs", json.array(unicode))
|
||||
cmdline += debugpy_args
|
||||
|
||||
# Use command line arguments propagated via launcher CLI, rather than "args", to get
|
||||
# their values after shell expansion in "runInTerminal" scenarios. The command line
|
||||
# parser in __main__ has already removed everything up to and including "--" by now.
|
||||
# Further arguments can come via two channels: the launcher's own command line, or
|
||||
# "args" in the request; effective arguments are concatenation of these two in order.
|
||||
# Arguments for debugpy (such as -m) always come via CLI, but those specified by the
|
||||
# user via "args" are passed differently by the adapter depending on "argsExpansion".
|
||||
cmdline += sys.argv[1:]
|
||||
cmdline += request("args", json.array(unicode))
|
||||
|
||||
# We want the process name to reflect the target. So for -m, use the module name
|
||||
# that follows; otherwise use the first argument, which is either -c or filename.
|
||||
process_name = compat.filename(sys.argv[1] if sys.argv[1] != "-m" else sys.argv[2])
|
||||
process_name = request("processName", compat.filename(sys.executable))
|
||||
|
||||
env = os.environ.copy()
|
||||
env_changes = request("env", json.object(unicode))
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class DebugConfig(collections.MutableMapping):
|
|||
"type": (),
|
||||
# Launch
|
||||
"args": [],
|
||||
"argsExpansion": "shell",
|
||||
"code": (),
|
||||
"console": "internal",
|
||||
"cwd": (),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
|||
|
||||
import pytest
|
||||
|
||||
from debugpy.common import log
|
||||
from tests import debug
|
||||
from tests.debug import runners, targets
|
||||
from tests.patterns import some
|
||||
|
|
@ -35,7 +36,8 @@ def test_args(pyfile, target, run):
|
|||
|
||||
@pytest.mark.parametrize("target", targets.all)
|
||||
@pytest.mark.parametrize("run", runners.all_launch)
|
||||
def test_shell_expansion(pyfile, target, run):
|
||||
@pytest.mark.parametrize("expansion", ["", "none", "shell"])
|
||||
def test_shell_expansion(pyfile, target, run, expansion):
|
||||
@pyfile
|
||||
def code_to_debug():
|
||||
import sys
|
||||
|
|
@ -46,9 +48,11 @@ def test_shell_expansion(pyfile, target, run):
|
|||
backchannel.send(sys.argv)
|
||||
|
||||
def expand(args):
|
||||
log.info("Before expansion: {0}", args)
|
||||
for i, arg in enumerate(args):
|
||||
if arg.startswith("$"):
|
||||
args[i] = arg[1:]
|
||||
log.info("After expansion: {0}", args)
|
||||
|
||||
class Session(debug.Session):
|
||||
def run_in_terminal(self, args, cwd, env):
|
||||
|
|
@ -57,11 +61,15 @@ def test_shell_expansion(pyfile, target, run):
|
|||
|
||||
args = ["0", "$1", "2"]
|
||||
with Session() as session:
|
||||
if expansion:
|
||||
session.config["argsExpansion"] = expansion
|
||||
|
||||
backchannel = session.open_backchannel()
|
||||
with run(session, target(code_to_debug, args=args)):
|
||||
pass
|
||||
|
||||
argv = backchannel.receive()
|
||||
|
||||
if session.config["console"] != "internalConsole":
|
||||
if session.config["console"] != "internalConsole" and expansion != "none":
|
||||
expand(args)
|
||||
assert argv == [some.str] + args
|
||||
|
|
|
|||
|
|
@ -21,6 +21,21 @@ if not tests.full:
|
|||
return request.param
|
||||
|
||||
|
||||
def expected_subprocess_config(parent_session):
|
||||
config = dict(parent_session.config)
|
||||
for key in "args", "listen", "postDebugTask", "preLaunchTask", "processId":
|
||||
config.pop(key, None)
|
||||
config.update(
|
||||
{
|
||||
"name": some.str,
|
||||
"request": "attach",
|
||||
"subProcessId": some.int,
|
||||
"connect": {"host": some.str, "port": some.int},
|
||||
}
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"start_method",
|
||||
[""]
|
||||
|
|
@ -114,17 +129,7 @@ def test_multiprocessing(pyfile, target, run, start_method):
|
|||
with run(parent_session, target(code_to_debug, args=[start_method])):
|
||||
pass
|
||||
|
||||
expected_child_config = dict(parent_session.config)
|
||||
expected_child_config.pop("listen", None)
|
||||
expected_child_config.update(
|
||||
{
|
||||
"name": some.str,
|
||||
"request": "attach",
|
||||
"subProcessId": some.int,
|
||||
"connect": {"host": some.str, "port": some.int},
|
||||
}
|
||||
)
|
||||
|
||||
expected_child_config = expected_subprocess_config(parent_session)
|
||||
child_config = parent_session.wait_for_next_event("debugpyAttach")
|
||||
assert child_config == expected_child_config
|
||||
parent_session.proceed()
|
||||
|
|
@ -133,17 +138,7 @@ def test_multiprocessing(pyfile, target, run, start_method):
|
|||
with child_session.start():
|
||||
pass
|
||||
|
||||
expected_grandchild_config = dict(child_session.config)
|
||||
expected_grandchild_config.pop("listen", None)
|
||||
expected_grandchild_config.update(
|
||||
{
|
||||
"name": some.str,
|
||||
"request": "attach",
|
||||
"subProcessId": some.int,
|
||||
"connect": {"host": some.str, "port": some.int},
|
||||
}
|
||||
)
|
||||
|
||||
expected_grandchild_config = expected_subprocess_config(child_session)
|
||||
grandchild_config = child_session.wait_for_next_event("debugpyAttach")
|
||||
assert grandchild_config == expected_grandchild_config
|
||||
|
||||
|
|
@ -200,21 +195,10 @@ def test_subprocess(pyfile, target, run, subProcess):
|
|||
with run(parent_session, target(parent, args=[child])):
|
||||
pass
|
||||
|
||||
expected_child_config = dict(parent_session.config)
|
||||
for key in "processId", "listen", "preLaunchTask", "postDebugTask":
|
||||
expected_child_config.pop(key, None)
|
||||
expected_child_config.update(
|
||||
{
|
||||
"name": some.str,
|
||||
"request": "attach",
|
||||
"subProcessId": some.int,
|
||||
"connect": {"host": some.str, "port": some.int},
|
||||
}
|
||||
)
|
||||
|
||||
if subProcess is False:
|
||||
return
|
||||
|
||||
expected_child_config = expected_subprocess_config(parent_session)
|
||||
child_config = parent_session.wait_for_next_event("debugpyAttach")
|
||||
assert child_config == expected_child_config
|
||||
parent_session.proceed()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue