Skip to content
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

Remote debugging without extra launch settings locally #142

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/fileSystemConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ export interface FileSystemConfig extends ConnectConfig {
_location?: ConfigLocation;
/** Internal property keeping track of where this config comes from (including merges) */
_locations: ConfigLocation[];
/** Debug port to attach */
debugPort?: number;
/** Task to run before debug session starts. SSH command: e.g. `/opt/vistec/python/bin/python -m ptvsd --host ${config.host} --port ${config.debugPort} --wait ${file}` */
debugPreLaunch?: string;
}

export function invalidConfigName(name: string) {
Expand Down
83 changes: 83 additions & 0 deletions src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,89 @@ export class Manager implements vscode.TreeDataProvider<string | FileSystemConfi
}
root = root.replace(/^~/, home.replace(/\/$/, ''));
}

vscode.debug.registerDebugConfigurationProvider("*", {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we're supposed to use these register methods dynamically, especially without ever unsubscribing them

resolveDebugConfiguration(folder: vscode.WorkspaceFolder, debugConfig: vscode.DebugConfiguration) {

if ((folder.uri.scheme === 'ssh') && config) {
debugConfig['request'] = 'attach';
debugConfig['pathMappings'] = [];
debugConfig['pathMappings'].push({ 'localRoot': 'ssh://' + config.name, 'remoteRoot': config.root });

if (config.debugPort) {
if (debugConfig['port'] && (debugConfig['port'] !== config.port))
Logging.warning(`Invalid port in 'launch.json' working on '${config.name}'`);
debugConfig['port'] = config.debugPort;

if (debugConfig['host'] && (debugConfig['host'] !== config.host))
Logging.warning(`Invalid host in 'launch.json' working on '${config.name}'`);
debugConfig['host'] = config.host;
}

if (debugConfig['port'] === undefined)
Logging.error(`Missing property "debugPort" for remote debugging on '${config.name}'`);

let workspaceFolder = root;
let file = "${file}"; // default to get error message to open an editor
if (vscode.window.activeTextEditor)
file = root + vscode.window.activeTextEditor.document.uri.path; // '${file}' can not be resolved per default
if (debugConfig['program'])
debugConfig['program'] = eval('`' + debugConfig['program'] + '`'); // resolve ${file}, ${workspaceFolder}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit unsafe and a bad practice. A regular (dynamic) string replacement would work here.
I'm also not sure about if vscode will replace things like ${workspaceFolder} before/after this step.

else
debugConfig['program'] = file;
}
return debugConfig;
}
});


vscode.debug.registerDebugAdapterTrackerFactory('*', {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as on line 116

createDebugAdapterTracker(session: vscode.DebugSession) {
if (config && config.debugPreLaunch) {
return {
onWillStartSession: () => {
if (config && config.debugPreLaunch) {
const file = session.configuration['program'];
const command = eval('`' + config.debugPreLaunch + '`'); // resolve ${file} and config.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as on line 142


new Promise((resolve, reject) => {
Logging.info(`Start preLaunch Task for remote debugging: ${command}`);
client.exec(command, (err, stream) => {
if (err) return reject(err);
stream.stderr.on('data', (d) => {
Logging.error(`Stderr from remote debugging: ${d}`);
})
stream.on('data', (d) => {
Logging.debug(`Stdout from remote debugging: ${d}`);
})
stream.on('error', reject);
stream.on('close', (exitCode, signal) => {
if (exitCode || signal) {
return reject(new Error("error listing directory"));
}
resolve();
});
});
});
}}};
}}
});

vscode.debug.registerDebugAdapterTrackerFactory('*', {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as on line 116.
This should also use the Logging facility instead of directly logging to the console.
This whole registerDebugAdapterTrackerFactory could be merged with the one on line 151.

createDebugAdapterTracker(session: vscode.DebugSession) {
if (session.configuration['dapTrace']) {
return {
onWillStartSession: () => console.log(`start: ${session.id}`),
onWillReceiveMessage: m => console.log(`===> ${JSON.stringify(m, undefined, 2)}`),
onDidSendMessage: m => console.log(`<=== ${JSON.stringify(m, undefined, 2)}`),
onWillStopSession: () => console.log(`stop: ${session.id}`),
onError: err => console.log(`error: ${err}`),
onExit: (code, signal) => console.log(`exit: ${code}`)
};
}
}
});

const sftp = await getSFTP(client, config);
const fs = new SSHFileSystem(name, sftp, root, config!);
Logging.info(`Created SSHFileSystem for ${name}, reading root directory...`);
Expand Down
15 changes: 14 additions & 1 deletion webview/src/ConfigEditor/fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,21 @@ export function passphrase(config: FileSystemConfig, onChange: FSCChanged<'passp
return <FieldDropdownWithInput key="passphrase" label="Passphrase" {...{ value, values, description }} onChange={callback} optional={true} />
}

export function debugPort(config: FileSystemConfig, onChange: FSCChanged<'debugPort'>): React.ReactElement {
const callback = (value?: number) => onChange('debugPort', value);
const description = 'Debug port to attach';
return <FieldNumber key="debugPort" label="Remote Debugging Port" value={config.debugPort} onChange={callback} optional={true} description={description} />
}

export function debugPreLaunch(config: FileSystemConfig, onChange: FSCChanged<'debugPreLaunch'>): React.ReactElement {
const callback = (value?: string) => onChange('debugPreLaunch', value);
const description = 'Task to run before debug session starts. SSH command: e.g. `/opt/vistec/python/bin/python -m ptvsd --host ${config.host} --port ${config.debugPort} --wait ${file}`';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit of a long description which doesn't specify that the command will be run locally

return <FieldString key="debugPreLaunch" label="Remote Debugging PreLaunch" value={config.debugPreLaunch} onChange={callback} optional={true} description={description} />
}

export type FieldFactory = (config: FileSystemConfig, onChange: FSCChanged, onChangeMultiple: FSCChangedMultiple) => React.ReactElement | null;
export const FIELDS: FieldFactory[] = [
name, merge, label, group, putty, host, port,
root, agent, username, password, privateKeyPath, passphrase,
PROXY_FIELD];
PROXY_FIELD,
debugPort, debugPreLaunch];
4 changes: 4 additions & 0 deletions webview/src/types/fileSystemConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ export interface FileSystemConfig extends ConnectConfig {
_location?: ConfigLocation;
/** Internal property keeping track of where this config comes from (including merges) */
_locations: ConfigLocation[];
/** Debug port to attach */
debugPort?: number;
/** Task to run before debug session starts. SSH command: e.g. `/opt/vistec/python/bin/python -m ptvsd --host ${config.host} --port ${config.debugPort} --wait ${file}` */
debugPreLaunch?: string;
}

export function invalidConfigName(name: string) {
Expand Down