Skip to content

Commit 38505c1

Browse files
committed
✨ remote path mapping
1 parent 3e40ce2 commit 38505c1

File tree

4 files changed

+84
-16
lines changed

4 files changed

+84
-16
lines changed

package.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,31 @@
10171017
},
10181018
"default": []
10191019
},
1020+
"pathMappings": {
1021+
"type": "array",
1022+
"label": "Additional path mappings.",
1023+
"items": {
1024+
"type": "object",
1025+
"label": "Path mapping",
1026+
"required": [
1027+
"localRoot",
1028+
"remoteRoot"
1029+
],
1030+
"properties": {
1031+
"localRoot": {
1032+
"type": "string",
1033+
"label": "Local source root.",
1034+
"default": ""
1035+
},
1036+
"remoteRoot": {
1037+
"type": "string",
1038+
"label": "Remote source root.",
1039+
"default": ""
1040+
}
1041+
}
1042+
},
1043+
"default": []
1044+
},
10201045
"logToFile": {
10211046
"type": "boolean",
10221047
"description": "Enable logging of debugger events to a log file.",

src/client/debugger/Common/Contracts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum
8080
host?: string;
8181
secret?: string;
8282
logToFile?: boolean;
83+
pathMappings?: { localRoot: string; remoteRoot: string }[];
84+
debugOptions?: DebugOptions[];
8385
}
8486

8587
export interface IDebugServer {

src/client/debugger/configProviders/pythonV2Provider.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,13 @@ export class PythonV2DebugConfigurationProvider extends BaseConfigurationProvide
3939
if (this.serviceContainer.get<IPlatformService>(IPlatformService).isWindows) {
4040
debugConfiguration.debugOptions.push(DebugOptions.FixFilePathCase);
4141
}
42+
43+
if (!debugConfiguration.pathMappings) {
44+
debugConfiguration.pathMappings = [];
45+
}
46+
debugConfiguration.pathMappings!.push({
47+
localRoot: debugConfiguration.localRoot,
48+
remoteRoot: debugConfiguration.remoteRoot
49+
});
4250
}
4351
}

src/test/debugger/attach.ptvsd.test.ts

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
import { ChildProcess, spawn } from 'child_process';
99
import * as getFreePort from 'get-port';
1010
import * as path from 'path';
11+
import * as TypeMoq from 'typemoq';
12+
import { DebugConfiguration, Uri } from 'vscode';
1113
import { DebugClient } from 'vscode-debugadapter-testsupport';
1214
import { EXTENSION_ROOT_DIR } from '../../client/common/constants';
1315
import '../../client/common/extensions';
14-
import { DebugOptions } from '../../client/debugger/Common/Contracts';
16+
import { IS_WINDOWS } from '../../client/common/platform/constants';
17+
import { PlatformService } from '../../client/common/platform/platformService';
18+
import { IPlatformService } from '../../client/common/platform/types';
19+
import { PythonV2DebugConfigurationProvider } from '../../client/debugger';
20+
import { AttachRequestArguments, DebugOptions } from '../../client/debugger/Common/Contracts';
21+
import { IServiceContainer } from '../../client/ioc/types';
1522
import { sleep } from '../common';
1623
import { initialize, IS_APPVEYOR, IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize';
1724
import { continueDebugging, createDebugAdapter } from './utils';
@@ -43,21 +50,17 @@ suite('Attach Debugger - Experimental', () => {
4350
} catch { }
4451
}
4552
});
46-
test('Confirm we are able to attach to a running program', async function () {
47-
this.timeout(20000);
48-
// Lets skip this test on AppVeyor (very flaky on AppVeyor).
49-
if (IS_APPVEYOR) {
50-
return;
51-
}
52-
53+
async function testAttachingToRemoteProcess(localRoot: string, remoteRoot: string, pathSeparator: string) {
5354
const port = await getFreePort({ host: 'localhost', port: 3000 });
5455
const customEnv = { ...process.env };
5556

5657
// Set the path for PTVSD to be picked up.
5758
// tslint:disable-next-line:no-string-literal
58-
customEnv['PYTHONPATH'] = ptvsdPath;
59-
const pythonArgs = ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', fileToDebug.fileToCommandArgument()];
59+
customEnv['PYTHONPATH'] = '/home/don/Desktop/development/vscode/ptvsd';
60+
const pythonArgs = ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', fileToDebug];
6061
procToKill = spawn('python', pythonArgs, { env: customEnv, cwd: path.dirname(fileToDebug) });
62+
// wait for remote socket to start
63+
await sleep(1000);
6164

6265
// Send initialize, attach
6366
const initializePromise = debugClient.initializeRequest({
@@ -69,15 +72,23 @@ suite('Attach Debugger - Experimental', () => {
6972
supportsVariableType: true,
7073
supportsVariablePaging: true
7174
});
72-
const attachPromise = debugClient.attachRequest({
73-
localRoot: path.dirname(fileToDebug),
74-
remoteRoot: path.dirname(fileToDebug),
75+
const options: AttachRequestArguments & DebugConfiguration = {
76+
name: 'attach',
77+
request: 'attach',
78+
localRoot,
79+
remoteRoot,
7580
type: 'pythonExperimental',
7681
port: port,
7782
host: 'localhost',
78-
logToFile: false,
83+
logToFile: true,
7984
debugOptions: [DebugOptions.RedirectOutput]
80-
});
85+
};
86+
const serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
87+
serviceContainer.setup(c => c.get(IPlatformService, TypeMoq.It.isAny())).returns(() => new PlatformService());
88+
const configProvider = new PythonV2DebugConfigurationProvider(serviceContainer.object);
89+
90+
const launchArgs = await configProvider.resolveDebugConfiguration({ index: 0, name: 'root', uri: Uri.file(localRoot) }, options);
91+
const attachPromise = debugClient.attachRequest(launchArgs);
8192

8293
await Promise.all([
8394
initializePromise,
@@ -90,7 +101,9 @@ suite('Attach Debugger - Experimental', () => {
90101
const stdOutPromise = debugClient.assertOutput('stdout', 'this is stdout');
91102
const stdErrPromise = debugClient.assertOutput('stderr', 'this is stderr');
92103

93-
const breakpointLocation = { path: fileToDebug, column: 1, line: 12 };
104+
// Don't use path utils, as we're building the paths manually (mimic windows paths on unix test servers and vice versa).
105+
const localFileName = `${localRoot}${pathSeparator}${path.basename(fileToDebug)}`;
106+
const breakpointLocation = { path: localFileName, column: 1, line: 12 };
94107
const breakpointPromise = debugClient.setBreakpointsRequest({
95108
lines: [breakpointLocation.line],
96109
breakpoints: [{ line: breakpointLocation.line, column: breakpointLocation.column }],
@@ -111,5 +124,25 @@ suite('Attach Debugger - Experimental', () => {
111124
debugClient.waitForEvent('exited'),
112125
debugClient.waitForEvent('terminated')
113126
]);
127+
}
128+
test('Confirm we are able to attach to a running program', async function () {
129+
this.timeout(20000);
130+
// Lets skip this test on AppVeyor (very flaky on AppVeyor).
131+
if (IS_APPVEYOR) {
132+
return;
133+
}
134+
135+
await testAttachingToRemoteProcess(path.dirname(fileToDebug), path.dirname(fileToDebug), path.sep);
136+
});
137+
test('Confirm localpath translations are done correctly', async function () {
138+
this.timeout(20000);
139+
// Lets skip this test on AppVeyor (very flaky on AppVeyor).
140+
if (IS_APPVEYOR) {
141+
return;
142+
}
143+
144+
const localWorkspace = IS_WINDOWS ? '/home/user/Desktop/project/src' : 'C:\\Project\\src';
145+
const pathSeparator = IS_WINDOWS ? '\\' : '/';
146+
await testAttachingToRemoteProcess(localWorkspace, path.dirname(fileToDebug), pathSeparator);
114147
});
115148
});

0 commit comments

Comments
 (0)