Skip to content

Commit 66cbd91

Browse files
paulacamargo25eleanorjboyd
authored andcommitted
Remove DI from debug configuration providers (microsoft#19785)
Closed: microsoft#19766
1 parent 6c95c81 commit 66cbd91

27 files changed

+600
-914
lines changed

src/client/debugger/extension/configuration/debugConfigurationService.ts

+29-7
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@ import { cloneDeep } from 'lodash';
88
import { CancellationToken, DebugConfiguration, QuickPickItem, WorkspaceFolder } from 'vscode';
99
import { DebugConfigStrings } from '../../../common/utils/localize';
1010
import {
11-
IMultiStepInput,
1211
IMultiStepInputFactory,
1312
InputStep,
1413
IQuickPickParameters,
14+
MultiStepInput,
1515
} from '../../../common/utils/multiStepInput';
1616
import { AttachRequestArguments, DebugConfigurationArguments, LaunchRequestArguments } from '../../types';
1717
import { DebugConfigurationState, DebugConfigurationType, IDebugConfigurationService } from '../types';
18-
import { IDebugConfigurationProviderFactory, IDebugConfigurationResolver } from './types';
18+
import { buildDjangoLaunchDebugConfiguration } from './providers/djangoLaunch';
19+
import { buildFastAPILaunchDebugConfiguration } from './providers/fastapiLaunch';
20+
import { buildFileLaunchDebugConfiguration } from './providers/fileLaunch';
21+
import { buildFlaskLaunchDebugConfiguration } from './providers/flaskLaunch';
22+
import { buildModuleLaunchConfiguration } from './providers/moduleLaunch';
23+
import { buildPidAttachConfiguration } from './providers/pidAttach';
24+
import { buildPyramidLaunchConfiguration } from './providers/pyramidLaunch';
25+
import { buildRemoteAttachConfiguration } from './providers/remoteAttach';
26+
import { IDebugConfigurationResolver } from './types';
1927

2028
@injectable()
2129
export class PythonDebugConfigurationService implements IDebugConfigurationService {
@@ -27,8 +35,6 @@ export class PythonDebugConfigurationService implements IDebugConfigurationServi
2735
@inject(IDebugConfigurationResolver)
2836
@named('launch')
2937
private readonly launchResolver: IDebugConfigurationResolver<LaunchRequestArguments>,
30-
@inject(IDebugConfigurationProviderFactory)
31-
private readonly providerFactory: IDebugConfigurationProviderFactory,
3238
@inject(IMultiStepInputFactory) private readonly multiStepFactory: IMultiStepInputFactory,
3339
) {}
3440

@@ -102,7 +108,7 @@ export class PythonDebugConfigurationService implements IDebugConfigurationServi
102108
}
103109

104110
protected async pickDebugConfiguration(
105-
input: IMultiStepInput<DebugConfigurationState>,
111+
input: MultiStepInput<DebugConfigurationState>,
106112
state: DebugConfigurationState,
107113
): Promise<InputStep<DebugConfigurationState> | void> {
108114
type DebugConfigurationQuickPickItem = QuickPickItem & { type: DebugConfigurationType };
@@ -148,6 +154,22 @@ export class PythonDebugConfigurationService implements IDebugConfigurationServi
148154
description: DebugConfigStrings.pyramid.selectConfiguration.description,
149155
},
150156
];
157+
const debugConfigurations = new Map<
158+
DebugConfigurationType,
159+
(
160+
input: MultiStepInput<DebugConfigurationState>,
161+
state: DebugConfigurationState,
162+
) => Promise<void | InputStep<DebugConfigurationState>>
163+
>();
164+
debugConfigurations.set(DebugConfigurationType.launchDjango, buildDjangoLaunchDebugConfiguration);
165+
debugConfigurations.set(DebugConfigurationType.launchFastAPI, buildFastAPILaunchDebugConfiguration);
166+
debugConfigurations.set(DebugConfigurationType.launchFile, buildFileLaunchDebugConfiguration);
167+
debugConfigurations.set(DebugConfigurationType.launchFlask, buildFlaskLaunchDebugConfiguration);
168+
debugConfigurations.set(DebugConfigurationType.launchModule, buildModuleLaunchConfiguration);
169+
debugConfigurations.set(DebugConfigurationType.pidAttach, buildPidAttachConfiguration);
170+
debugConfigurations.set(DebugConfigurationType.remoteAttach, buildRemoteAttachConfiguration);
171+
debugConfigurations.set(DebugConfigurationType.launchPyramid, buildPyramidLaunchConfiguration);
172+
151173
state.config = {};
152174
const pick = await input.showQuickPick<
153175
DebugConfigurationQuickPickItem,
@@ -159,8 +181,8 @@ export class PythonDebugConfigurationService implements IDebugConfigurationServi
159181
items: items,
160182
});
161183
if (pick) {
162-
const provider = this.providerFactory.create(pick.type);
163-
return provider.buildConfiguration.bind(provider);
184+
const pickedDebugConfiguration = debugConfigurations.get(pick.type)!;
185+
return pickedDebugConfiguration(input, state);
164186
}
165187
}
166188
}

src/client/debugger/extension/configuration/providers/djangoLaunch.ts

+63-72
Original file line numberDiff line numberDiff line change
@@ -3,93 +3,84 @@
33

44
'use strict';
55

6-
import { inject, injectable } from 'inversify';
6+
import * as vscode from 'vscode';
77
import * as path from 'path';
8-
import { Uri, WorkspaceFolder } from 'vscode';
9-
import { IWorkspaceService } from '../../../../common/application/types';
10-
import { IFileSystem } from '../../../../common/platform/types';
11-
import { IPathUtils } from '../../../../common/types';
8+
import * as fs from 'fs-extra';
129
import { DebugConfigStrings } from '../../../../common/utils/localize';
1310
import { MultiStepInput } from '../../../../common/utils/multiStepInput';
14-
import { SystemVariables } from '../../../../common/variables/systemVariables';
1511
import { sendTelemetryEvent } from '../../../../telemetry';
1612
import { EventName } from '../../../../telemetry/constants';
1713
import { DebuggerTypeName } from '../../../constants';
1814
import { LaunchRequestArguments } from '../../../types';
19-
import { DebugConfigurationState, DebugConfigurationType, IDebugConfigurationProvider } from '../../types';
15+
import { DebugConfigurationState, DebugConfigurationType } from '../../types';
16+
import { resolveVariables } from '../utils/common';
2017

2118
const workspaceFolderToken = '${workspaceFolder}';
2219

23-
@injectable()
24-
export class DjangoLaunchDebugConfigurationProvider implements IDebugConfigurationProvider {
25-
constructor(
26-
@inject(IFileSystem) private fs: IFileSystem,
27-
@inject(IWorkspaceService) private readonly workspace: IWorkspaceService,
28-
@inject(IPathUtils) private pathUtils: IPathUtils,
29-
) {}
30-
public async buildConfiguration(input: MultiStepInput<DebugConfigurationState>, state: DebugConfigurationState) {
31-
const program = await this.getManagePyPath(state.folder);
32-
let manuallyEnteredAValue: boolean | undefined;
33-
const defaultProgram = `${workspaceFolderToken}${this.pathUtils.separator}manage.py`;
34-
const config: Partial<LaunchRequestArguments> = {
35-
name: DebugConfigStrings.django.snippet.name,
36-
type: DebuggerTypeName,
37-
request: 'launch',
38-
program: program || defaultProgram,
39-
args: ['runserver'],
40-
django: true,
41-
justMyCode: true,
42-
};
43-
if (!program) {
44-
const selectedProgram = await input.showInputBox({
45-
title: DebugConfigStrings.django.enterManagePyPath.title,
46-
value: defaultProgram,
47-
prompt: DebugConfigStrings.django.enterManagePyPath.prompt,
48-
validate: (value) => this.validateManagePy(state.folder, defaultProgram, value),
49-
});
50-
if (selectedProgram) {
51-
manuallyEnteredAValue = true;
52-
config.program = selectedProgram;
53-
}
20+
export async function buildDjangoLaunchDebugConfiguration(
21+
input: MultiStepInput<DebugConfigurationState>,
22+
state: DebugConfigurationState,
23+
) {
24+
const program = await getManagePyPath(state.folder);
25+
let manuallyEnteredAValue: boolean | undefined;
26+
const defaultProgram = `${workspaceFolderToken}${path.sep}manage.py`;
27+
const config: Partial<LaunchRequestArguments> = {
28+
name: DebugConfigStrings.django.snippet.name,
29+
type: DebuggerTypeName,
30+
request: 'launch',
31+
program: program || defaultProgram,
32+
args: ['runserver'],
33+
django: true,
34+
justMyCode: true,
35+
};
36+
if (!program) {
37+
const selectedProgram = await input.showInputBox({
38+
title: DebugConfigStrings.django.enterManagePyPath.title,
39+
value: defaultProgram,
40+
prompt: DebugConfigStrings.django.enterManagePyPath.prompt,
41+
validate: (value) => validateManagePy(state.folder, defaultProgram, value),
42+
});
43+
if (selectedProgram) {
44+
manuallyEnteredAValue = true;
45+
config.program = selectedProgram;
5446
}
47+
}
5548

56-
sendTelemetryEvent(EventName.DEBUGGER_CONFIGURATION_PROMPTS, undefined, {
57-
configurationType: DebugConfigurationType.launchDjango,
58-
autoDetectedDjangoManagePyPath: !!program,
59-
manuallyEnteredAValue,
60-
});
61-
Object.assign(state.config, config);
49+
sendTelemetryEvent(EventName.DEBUGGER_CONFIGURATION_PROMPTS, undefined, {
50+
configurationType: DebugConfigurationType.launchDjango,
51+
autoDetectedDjangoManagePyPath: !!program,
52+
manuallyEnteredAValue,
53+
});
54+
55+
Object.assign(state.config, config);
56+
}
57+
58+
export async function validateManagePy(
59+
folder: vscode.WorkspaceFolder | undefined,
60+
defaultValue: string,
61+
selected?: string,
62+
): Promise<string | undefined> {
63+
const error = DebugConfigStrings.django.enterManagePyPath.invalid;
64+
if (!selected || selected.trim().length === 0) {
65+
return error;
6266
}
63-
public async validateManagePy(
64-
folder: WorkspaceFolder | undefined,
65-
defaultValue: string,
66-
selected?: string,
67-
): Promise<string | undefined> {
68-
const error = DebugConfigStrings.django.enterManagePyPath.invalid;
69-
if (!selected || selected.trim().length === 0) {
70-
return error;
71-
}
72-
const resolvedPath = this.resolveVariables(selected, folder ? folder.uri : undefined);
73-
if (selected !== defaultValue && !(await this.fs.fileExists(resolvedPath))) {
74-
return error;
75-
}
76-
if (!resolvedPath.trim().toLowerCase().endsWith('.py')) {
77-
return error;
78-
}
79-
return;
67+
const resolvedPath = resolveVariables(selected, undefined, folder);
68+
69+
if (selected !== defaultValue && !(await fs.pathExists(resolvedPath))) {
70+
return error;
8071
}
81-
protected resolveVariables(pythonPath: string, resource: Uri | undefined): string {
82-
const systemVariables = new SystemVariables(resource, undefined, this.workspace);
83-
return systemVariables.resolveAny(pythonPath);
72+
if (!resolvedPath.trim().toLowerCase().endsWith('.py')) {
73+
return error;
8474
}
75+
return;
76+
}
8577

86-
protected async getManagePyPath(folder: WorkspaceFolder | undefined): Promise<string | undefined> {
87-
if (!folder) {
88-
return;
89-
}
90-
const defaultLocationOfManagePy = path.join(folder.uri.fsPath, 'manage.py');
91-
if (await this.fs.fileExists(defaultLocationOfManagePy)) {
92-
return `${workspaceFolderToken}${this.pathUtils.separator}manage.py`;
93-
}
78+
export async function getManagePyPath(folder: vscode.WorkspaceFolder | undefined): Promise<string | undefined> {
79+
if (!folder) {
80+
return;
81+
}
82+
const defaultLocationOfManagePy = path.join(folder.uri.fsPath, 'manage.py');
83+
if (await fs.pathExists(defaultLocationOfManagePy)) {
84+
return `${workspaceFolderToken}${path.sep}manage.py`;
9485
}
9586
}

src/client/debugger/extension/configuration/providers/fastapiLaunch.ts

+46-51
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,64 @@
33

44
'use strict';
55

6-
import { inject, injectable } from 'inversify';
76
import * as path from 'path';
7+
import * as fs from 'fs-extra';
88
import { WorkspaceFolder } from 'vscode';
9-
import { IFileSystem } from '../../../../common/platform/types';
109
import { DebugConfigStrings } from '../../../../common/utils/localize';
1110
import { MultiStepInput } from '../../../../common/utils/multiStepInput';
1211
import { sendTelemetryEvent } from '../../../../telemetry';
1312
import { EventName } from '../../../../telemetry/constants';
1413
import { DebuggerTypeName } from '../../../constants';
1514
import { LaunchRequestArguments } from '../../../types';
16-
import { DebugConfigurationState, DebugConfigurationType, IDebugConfigurationProvider } from '../../types';
15+
import { DebugConfigurationState, DebugConfigurationType } from '../../types';
1716

18-
@injectable()
19-
export class FastAPILaunchDebugConfigurationProvider implements IDebugConfigurationProvider {
20-
constructor(@inject(IFileSystem) private fs: IFileSystem) {}
21-
public isSupported(debugConfigurationType: DebugConfigurationType): boolean {
22-
return debugConfigurationType === DebugConfigurationType.launchFastAPI;
23-
}
24-
public async buildConfiguration(input: MultiStepInput<DebugConfigurationState>, state: DebugConfigurationState) {
25-
const application = await this.getApplicationPath(state.folder);
26-
let manuallyEnteredAValue: boolean | undefined;
27-
const config: Partial<LaunchRequestArguments> = {
28-
name: DebugConfigStrings.fastapi.snippet.name,
29-
type: DebuggerTypeName,
30-
request: 'launch',
31-
module: 'uvicorn',
32-
args: ['main:app'],
33-
jinja: true,
34-
justMyCode: true,
35-
};
17+
export async function buildFastAPILaunchDebugConfiguration(
18+
input: MultiStepInput<DebugConfigurationState>,
19+
state: DebugConfigurationState,
20+
) {
21+
const application = await getApplicationPath(state.folder);
22+
let manuallyEnteredAValue: boolean | undefined;
23+
const config: Partial<LaunchRequestArguments> = {
24+
name: DebugConfigStrings.fastapi.snippet.name,
25+
type: DebuggerTypeName,
26+
request: 'launch',
27+
module: 'uvicorn',
28+
args: ['main:app'],
29+
jinja: true,
30+
justMyCode: true,
31+
};
3632

37-
if (!application) {
38-
const selectedPath = await input.showInputBox({
39-
title: DebugConfigStrings.fastapi.enterAppPathOrNamePath.title,
40-
value: 'main.py',
41-
prompt: DebugConfigStrings.fastapi.enterAppPathOrNamePath.prompt,
42-
validate: (value) =>
43-
Promise.resolve(
44-
value && value.trim().length > 0
45-
? undefined
46-
: DebugConfigStrings.fastapi.enterAppPathOrNamePath.invalid,
47-
),
48-
});
49-
if (selectedPath) {
50-
manuallyEnteredAValue = true;
51-
config.args = [`${path.basename(selectedPath, '.py').replace('/', '.')}:app`];
52-
}
33+
if (!application) {
34+
const selectedPath = await input.showInputBox({
35+
title: DebugConfigStrings.fastapi.enterAppPathOrNamePath.title,
36+
value: 'main.py',
37+
prompt: DebugConfigStrings.fastapi.enterAppPathOrNamePath.prompt,
38+
validate: (value) =>
39+
Promise.resolve(
40+
value && value.trim().length > 0
41+
? undefined
42+
: DebugConfigStrings.fastapi.enterAppPathOrNamePath.invalid,
43+
),
44+
});
45+
if (selectedPath) {
46+
manuallyEnteredAValue = true;
47+
config.args = [`${path.basename(selectedPath, '.py').replace('/', '.')}:app`];
5348
}
49+
}
5450

55-
sendTelemetryEvent(EventName.DEBUGGER_CONFIGURATION_PROMPTS, undefined, {
56-
configurationType: DebugConfigurationType.launchFastAPI,
57-
autoDetectedFastAPIMainPyPath: !!application,
58-
manuallyEnteredAValue,
59-
});
60-
Object.assign(state.config, config);
51+
sendTelemetryEvent(EventName.DEBUGGER_CONFIGURATION_PROMPTS, undefined, {
52+
configurationType: DebugConfigurationType.launchFastAPI,
53+
autoDetectedFastAPIMainPyPath: !!application,
54+
manuallyEnteredAValue,
55+
});
56+
Object.assign(state.config, config);
57+
}
58+
export async function getApplicationPath(folder: WorkspaceFolder | undefined): Promise<string | undefined> {
59+
if (!folder) {
60+
return;
6161
}
62-
protected async getApplicationPath(folder: WorkspaceFolder | undefined): Promise<string | undefined> {
63-
if (!folder) {
64-
return;
65-
}
66-
const defaultLocationOfManagePy = path.join(folder.uri.fsPath, 'main.py');
67-
if (await this.fs.fileExists(defaultLocationOfManagePy)) {
68-
return 'main.py';
69-
}
62+
const defaultLocationOfManagePy = path.join(folder.uri.fsPath, 'main.py');
63+
if (await fs.pathExists(defaultLocationOfManagePy)) {
64+
return 'main.py';
7065
}
7166
}

src/client/debugger/extension/configuration/providers/fileLaunch.ts

+18-21
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,28 @@
33

44
'use strict';
55

6-
import { injectable } from 'inversify';
76
import { DebugConfigStrings } from '../../../../common/utils/localize';
87
import { MultiStepInput } from '../../../../common/utils/multiStepInput';
9-
import { captureTelemetry } from '../../../../telemetry';
8+
import { sendTelemetryEvent } from '../../../../telemetry';
109
import { EventName } from '../../../../telemetry/constants';
1110
import { DebuggerTypeName } from '../../../constants';
1211
import { LaunchRequestArguments } from '../../../types';
13-
import { DebugConfigurationState, DebugConfigurationType, IDebugConfigurationProvider } from '../../types';
12+
import { DebugConfigurationState, DebugConfigurationType } from '../../types';
1413

15-
@injectable()
16-
export class FileLaunchDebugConfigurationProvider implements IDebugConfigurationProvider {
17-
@captureTelemetry(
18-
EventName.DEBUGGER_CONFIGURATION_PROMPTS,
19-
{ configurationType: DebugConfigurationType.launchFile },
20-
false,
21-
)
22-
public async buildConfiguration(_input: MultiStepInput<DebugConfigurationState>, state: DebugConfigurationState) {
23-
const config: Partial<LaunchRequestArguments> = {
24-
name: DebugConfigStrings.file.snippet.name,
25-
type: DebuggerTypeName,
26-
request: 'launch',
27-
program: '${file}',
28-
console: 'integratedTerminal',
29-
justMyCode: true,
30-
};
31-
Object.assign(state.config, config);
32-
}
14+
export async function buildFileLaunchDebugConfiguration(
15+
_input: MultiStepInput<DebugConfigurationState>,
16+
state: DebugConfigurationState,
17+
) {
18+
const config: Partial<LaunchRequestArguments> = {
19+
name: DebugConfigStrings.file.snippet.name,
20+
type: DebuggerTypeName,
21+
request: 'launch',
22+
program: '${file}',
23+
console: 'integratedTerminal',
24+
justMyCode: true,
25+
};
26+
sendTelemetryEvent(EventName.DEBUGGER_CONFIGURATION_PROMPTS, undefined, {
27+
configurationType: DebugConfigurationType.launchFastAPI,
28+
});
29+
Object.assign(state.config, config);
3330
}

0 commit comments

Comments
 (0)