-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for remote debugging with experimental debugger #1230
Changes from 13 commits
2fd50a7
b9d6c0b
4a1dcb0
5d6223c
15249b3
febe297
35afa54
c24183b
3275dd5
0e5f0f6
9032acf
4f855f0
08dc364
39dcd34
22d710d
5c1dcfb
8ec6576
80b1903
10297ef
9bf271a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Add prelimnary support for remote debugging using the experimental debugger. | ||
Attach to a Python program started using the command `python -m ptvsd --server --port 9091 --file pythonFile.py` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
'use strict'; | ||
|
||
// tslint:disable:quotemark ordered-imports no-any no-empty curly member-ordering one-line max-func-body-length no-var-self prefer-const cyclomatic-complexity prefer-template | ||
|
||
import { DebugSession } from "vscode-debugadapter"; | ||
import { IPythonProcess, IDebugServer, AttachRequestArguments } from "../Common/Contracts"; | ||
import { connect, Socket } from "net"; | ||
import { BaseDebugServer } from "./BaseDebugServer"; | ||
|
||
export class RemoteDebugServerV2 extends BaseDebugServer { | ||
private args: AttachRequestArguments; | ||
private socket?: Socket; | ||
constructor(debugSession: DebugSession, pythonProcess: IPythonProcess, args: AttachRequestArguments) { | ||
super(debugSession, pythonProcess); | ||
this.args = args; | ||
} | ||
|
||
public Stop() { | ||
if (this.socket) { | ||
this.socket.destroy(); | ||
} | ||
} | ||
public Start(): Promise<IDebugServer> { | ||
return new Promise<IDebugServer>((resolve, reject) => { | ||
let portNumber = this.args.port; | ||
let options = { port: portNumber! }; | ||
if (typeof this.args.host === "string" && this.args.host.length > 0) { | ||
(<any>options).host = this.args.host; | ||
} | ||
try { | ||
let connected = false; | ||
const socket = connect(options, () => { | ||
connected = true; | ||
this.socket = socket; | ||
this.clientSocket.resolve(socket); | ||
resolve(options); | ||
}); | ||
socket.on('error', ex => { | ||
if (connected) { | ||
return; | ||
} | ||
reject(ex); | ||
}); | ||
} catch (ex) { | ||
reject(ex); | ||
} | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,17 +11,18 @@ import { PythonLanguage } from '../../common/constants'; | |
import { IFileSystem, IPlatformService } from '../../common/platform/types'; | ||
import { IConfigurationService } from '../../common/types'; | ||
import { IServiceContainer } from '../../ioc/types'; | ||
import { DebuggerType, DebugOptions, LaunchRequestArguments } from '../Common/Contracts'; | ||
import { AttachRequestArguments, DebuggerType, DebugOptions, LaunchRequestArguments } from '../Common/Contracts'; | ||
|
||
// tslint:disable:no-invalid-template-strings | ||
|
||
export type PythonDebugConfiguration = DebugConfiguration & LaunchRequestArguments; | ||
export type PythonLaunchDebugConfiguration = DebugConfiguration & LaunchRequestArguments; | ||
export type PythonAttachDebugConfiguration = DebugConfiguration & AttachRequestArguments; | ||
|
||
@injectable() | ||
export abstract class BaseConfigurationProvider implements DebugConfigurationProvider { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth splitting into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately there can only be one debug configuration, that handles both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There could be one class that contains a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
constructor(@unmanaged() public debugType: DebuggerType, protected serviceContainer: IServiceContainer) { } | ||
public resolveDebugConfiguration(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration> { | ||
const config = debugConfiguration as PythonDebugConfiguration; | ||
const config = debugConfiguration as PythonLaunchDebugConfiguration; | ||
const numberOfSettings = Object.keys(config); | ||
const workspaceFolder = this.getWorkspaceFolder(folder, config); | ||
|
||
|
@@ -35,10 +36,30 @@ export abstract class BaseConfigurationProvider implements DebugConfigurationPro | |
config.env = {}; | ||
} | ||
|
||
this.provideDefaults(workspaceFolder, config); | ||
if (config.request === 'attach') { | ||
// tslint:disable-next-line:no-any | ||
this.provideAttachDefaults(workspaceFolder, config as any as PythonAttachDebugConfiguration); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting - why is getting casted twice There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} else { | ||
this.provideLaunchDefaults(workspaceFolder, config); | ||
} | ||
return config; | ||
} | ||
protected provideDefaults(workspaceFolder: Uri | undefined, debugConfiguration: PythonDebugConfiguration): void { | ||
protected provideAttachDefaults(workspaceFolder: Uri | undefined, debugConfiguration: PythonAttachDebugConfiguration): void { | ||
if (!Array.isArray(debugConfiguration.debugOptions)) { | ||
debugConfiguration.debugOptions = []; | ||
} | ||
// Always redirect output. | ||
if (debugConfiguration.debugOptions.indexOf(DebugOptions.RedirectOutput) === -1) { | ||
debugConfiguration.debugOptions.push(DebugOptions.RedirectOutput); | ||
} | ||
if (!debugConfiguration.host) { | ||
debugConfiguration.host = 'localhost'; | ||
} | ||
if (!debugConfiguration.localRoot && workspaceFolder) { | ||
debugConfiguration.localRoot = workspaceFolder.fsPath; | ||
} | ||
} | ||
protected provideLaunchDefaults(workspaceFolder: Uri | undefined, debugConfiguration: PythonLaunchDebugConfiguration): void { | ||
this.resolveAndUpdatePythonPath(workspaceFolder, debugConfiguration); | ||
if (typeof debugConfiguration.cwd !== 'string' && workspaceFolder) { | ||
debugConfiguration.cwd = workspaceFolder.fsPath; | ||
|
@@ -75,7 +96,7 @@ export abstract class BaseConfigurationProvider implements DebugConfigurationPro | |
} | ||
} | ||
} | ||
private getWorkspaceFolder(folder: WorkspaceFolder | undefined, config: PythonDebugConfiguration): Uri | undefined { | ||
private getWorkspaceFolder(folder: WorkspaceFolder | undefined, config: PythonLaunchDebugConfiguration): Uri | undefined { | ||
if (folder) { | ||
return folder.uri; | ||
} | ||
|
@@ -94,14 +115,14 @@ export abstract class BaseConfigurationProvider implements DebugConfigurationPro | |
} | ||
} | ||
} | ||
private getProgram(config: PythonDebugConfiguration): string | undefined { | ||
private getProgram(config: PythonLaunchDebugConfiguration): string | undefined { | ||
const documentManager = this.serviceContainer.get<IDocumentManager>(IDocumentManager); | ||
const editor = documentManager.activeTextEditor; | ||
if (editor && editor.document.languageId === PythonLanguage.language) { | ||
return editor.document.fileName; | ||
} | ||
} | ||
private resolveAndUpdatePythonPath(workspaceFolder: Uri | undefined, debugConfiguration: PythonDebugConfiguration): void { | ||
private resolveAndUpdatePythonPath(workspaceFolder: Uri | undefined, debugConfiguration: PythonLaunchDebugConfiguration): void { | ||
if (!debugConfiguration) { | ||
return; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Evil double quotes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aaah, copy paste.