Merge branch 'master' into python-subprocess

This commit is contained in:
mergify[bot] 2020-05-24 11:25:10 +00:00 committed by GitHub
commit 435e33e23e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 164 additions and 25 deletions

View file

@ -383,8 +383,8 @@ research that.
Vimspector's tools are intended to automate your existing process for setting
this up rather than to offer batteries-included approach. Ultimately, all
vimspector is going to do is run your commands over SSH and co-ordinate with the
adapter.
vimspector is going to do is run your commands over SSH, or docker, and
co-ordinate with the adapter.
### Python (debugpy) Example
@ -394,7 +394,9 @@ and connect to it using debugpy.
The usage pattern is to hit `<F5>`, enter `host` (the host where your app runs),
`account` (the account it runs under), and `port` (a port that will be opened on
the remote host). Vimspector then orchestrates the various tools to set you up.
the remote host). Vimspector also supports exec'ing into Docker run containers
with `container` (the container name or id your app is running in).
Vimspector then orchestrates the various tools to set you up.
```json
@ -405,7 +407,7 @@ the remote host). Vimspector then orchestrates the various tools to set you up.
"host": "${host}",
"launch": {
"remote": {
"host": "${host}", // Remote host to ssh to (mandatory)
"host": "${host}", // Remote host to ssh to (mandatory if not using container)
"account": "${account}", // User to connect as (optional)
// Optional.... Manual additional arguments for ssh
@ -417,7 +419,7 @@ the remote host). Vimspector then orchestrates the various tools to set you up.
// %CMD% replaced with the remote-cmdLine configured in the launch
// configuration. (mandatory)
"launchCommmand": [
"python", "-m", "debugpy", "--listen 0.0.0.0:${port}",
"python", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"%CMD%"
]
@ -432,14 +434,8 @@ the remote host). Vimspector then orchestrates the various tools to set you up.
},
"attach": {
"remote": {
"host": "${host}", // Remote host to ssh to (mandatory)
"host": "${host}", // Remote host to ssh to (mandatory if not using container)
"account": "${account}", // User to connect as (optional)
// Optional.... Manual additional arguments for ssh
// "ssh": {
// "args": [ "-o", "StrictHostKeyChecking=no" ]
// },
// Command to get the PID of the process to attach (mandatory)
"pidCommand": [
//
@ -453,7 +449,7 @@ the remote host). Vimspector then orchestrates the various tools to set you up.
// Command to attach the debugger; %PID% replaced with output of
// pidCommand above (mandatory)
"attachCommand": [
"python", "-m", "debugpy", "--listen 0.0.0.0:${port}",
"python", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"--pid", "%PID%"
]
@ -522,7 +518,7 @@ the remote host). Vimspector then orchestrates the various tools to set you up.
### C-family (gdbserver) Example
This example uses vimspector to remotely luanch or attach to a binary using
This example uses vimspector to remotely launch or attach to a binary using
`gdbserver` and then instructs vscode-cpptools to attach to that `gdbserver`.
The appraoch is very similar to the above for python, just that we use gdbserver
@ -610,6 +606,117 @@ and have to tell cpptools a few more options.
}
```
### Docker Example
This example uses vimspector to remotely launch or attach to a docker container
port.
``` json
{
"adapters": {
"python-remote": {
"port": "${port}",
"launch": {
"remote": {
"container": "${container}", // Docker container id or name to exec into to.
// Command to launch the debugee and attach the debugger;
// %CMD% replaced with the remote-cmdLine configured in the launch
// configuration. (mandatory)
"launchCommmand": [
"python", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"%CMD%"
]
// Optional alternative to launchCommmand (if you need to run multiple
// commands)
// "launchCommmands": [
// [ /* first command */ ],
// [ /* second command */ ]
// ]
}
},
"attach": {
"remote": {
"container": "${container}", // Docker container id or name to exec into.
// Command to get the PID of the process to attach (mandatory)
// This command gets appended to "docker exec ${container}"
"pidCommand": [
//
// Remember taht you can use ${var} to ask for input. I use this to
// call a custom command to returm the PID for a named service, so
// here's an examle:
//
"sh", "-c", "pgrep", "-f", "${filename}"
],
// Command to attach the debugger; %PID% replaced with output of
// pidCommand above (mandatory)
"attachCommand": [
"sh", "-c", "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"--pid", "%PID%"
]
// Optional alternative to attachCommand (if you need to run multiple
// commands)
// "attachCommands": [
// [ /* first command */ ],
// [ /* second command */ ]
// ],
// Optional.... useful with buggy gdbservers to kill -TRAP %PID%
// "initCompleteCommand": [
// /* optional command to run after initialized */
// ]
}
}
}
},
"configurations": {
"remote-launch": {
"adapter": "python-remote",
"remote-request": "launch",
"remote-cmdLine": [
"${RemoteRoot}/${fileBasename}", "*${args}"
],
"configuration": {
"request": "attach",
"pathMappings": [
{
"localRoot": "${workspaceRoot}",
"remoteRoot": "${RemoteRoot}"
}
]
}
},
"remote-attach": {
"variables": {
// Just an example of how to specify a variable manually rather than
// vimspector asking for input from the user
"FileName": "${fileName}"
},
"adapter": "python-remote",
"remote-request": "attach",
"configuration": {
"request": "attach",
"pathMappings": [
{
"localRoot": "${workspaceRoot}",
"remoteRoot": "${RemoteRoot}"
}
]
}
}
}
}
```
## Appendix: Configuration file format
The configuration files are text files which must be UTF-8 encoded. They

View file

@ -78,8 +78,19 @@
"properties": {
"remote": {
"type": "object",
"required": [ "host" ],
"description": "Configures how Vimspector will marshal remote debugging requests. When remote debugging, Vimspector will ssh to 'account'@'host' and run 'pidCommand', 'attachCommands', 'runCommands', etc. based on the 'remote-command' option in the debug configuration. If 'remote-command' is 'launch', it runs 'runCommand(s)', otherwise (it's 'attach') vimspector runs 'pidCommand', followed by 'attachCommand(s)'.Then it starts up the debug adapter with the debug configuration as normal. Usually this is configured with an 'attach' request (whether we remotely 'launched' or not). Once the initialization exchange is complete, Vimspector runs the optional 'initCompleteCommand' which can be used to force the application to break, e.g. by sending it SIGINT. This is required on some platforms which have buggy gdbservers (for example)",
"oneOf": [
{
"required": [
"host"
]
},
{
"required": [
"container"
]
}
],
"description": "Configures how Vimspector will marshal remote debugging requests. When remote debugging, Vimspector will either ssh to 'account'@'host' or docker exec -it to 'container' and run 'pidCommand', 'attachCommands', 'runCommands', etc. based on the 'remote-command' option in the debug configuration. If 'remote-command' is 'launch', it runs 'runCommand(s)', otherwise (it's 'attach') vimspector runs 'pidCommand', followed by 'attachCommand(s)'.Then it starts up the debug adapter with the debug configuration as normal. Usually this is configured with an 'attach' request (whether we remotely 'launched' or not). Once the initialization exchange is complete, Vimspector runs the optional 'initCompleteCommand' which can be used to force the application to break, e.g. by sending it SIGINT. This is required on some platforms which have buggy gdbservers (for example)",
"properties": {
"account": {
"type": "string",
@ -87,7 +98,11 @@
},
"host": {
"type": "string",
"description": "Name of the remote host to connect to (via passwordless SSH). "
"description": "Name of the remote host to connect to (via passwordless SSH)."
},
"container": {
"type": "string",
"description": "Name or container id of the docker run container to connect to (via docker exec -it)."
},
"pidCommand": {
"type": "array",

View file

@ -613,13 +613,13 @@ class DebugSession( object ):
# e.g. expand variables when we use them, not all at once. This would
# remove the whole %PID% hack.
remote = atttach_config[ 'remote' ]
ssh = self._GetSSHCommand( remote )
remote_exec_cmd = self._GetRemoteExecCommand( remote )
# FIXME: Why does this not use self._GetCommands ?
cmd = ssh + remote[ 'pidCommand' ]
pid_cmd = remote_exec_cmd + remote[ 'pidCommand' ]
self._logger.debug( 'Getting PID: %s', cmd )
pid = subprocess.check_output( cmd ).decode( 'utf-8' ).strip()
self._logger.debug( 'Getting PID: %s', pid_cmd )
pid = subprocess.check_output( pid_cmd ).decode( 'utf-8' ).strip()
self._logger.debug( 'Got PID: %s', pid )
if not pid:
@ -628,7 +628,7 @@ class DebugSession( object ):
return
if 'initCompleteCommand' in remote:
initcmd = ssh + remote[ 'initCompleteCommand' ][ : ]
initcmd = remote_exec_cmd + remote[ 'initCompleteCommand' ][ : ]
for index, item in enumerate( initcmd ):
initcmd[ index ] = item.replace( '%PID%', pid )
@ -638,7 +638,7 @@ class DebugSession( object ):
commands = self._GetCommands( remote, 'attach' )
for command in commands:
cmd = ssh + command[ : ]
cmd = remote_exec_cmd + command[ : ]
for index, item in enumerate( cmd ):
cmd[ index ] = item.replace( '%PID%', pid )
@ -665,11 +665,11 @@ class DebugSession( object ):
if 'remote' in run_config:
remote = run_config[ 'remote' ]
ssh = self._GetSSHCommand( remote )
remote_exec_cmd = self._GetRemoteExecCommand( remote )
commands = self._GetCommands( remote, 'run' )
for index, command in enumerate( commands ):
cmd = ssh + command[ : ]
cmd = remote_exec_cmd + command[ : ]
full_cmd = []
for item in cmd:
if isinstance( command_line, list ):
@ -694,6 +694,23 @@ class DebugSession( object ):
return ssh
def _GetDockerCommand( self, remote ):
docker = [ 'docker', 'exec' ]
docker.append( remote[ 'container' ] )
return docker
def _GetRemoteExecCommand( self, remote ):
is_ssh_cmd = any( key in remote for key in [ 'ssh',
'host',
'account', ] )
is_docker_cmd = 'container' in remote
if is_ssh_cmd:
return self._GetSSHCommand( remote )
elif is_docker_cmd:
return self._GetDockerCommand( remote )
raise ValueError( 'Could not determine remote exec command' )
def _GetCommands( self, remote, pfx ):
commands = remote.get( pfx + 'Commands', None )