Skip to content

Commit 4c740b9

Browse files
authored
Resolve pyOCD server parameters to reduce required configs (#7)
* Refactoring to support both possible resolver functions in subproviders * Initial resolver functionality for pyOCD * Remove serverParameters for pyOCD --------- Signed-off-by: Jens Reinecke <[email protected]>
1 parent 835e586 commit 4c740b9

File tree

4 files changed

+109
-45
lines changed

4 files changed

+109
-45
lines changed

package.json

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,6 @@
6464
],
6565
"target": {
6666
"server": "pyOCD",
67-
"serverParameters": [
68-
"gdbserver",
69-
"--target",
70-
"${command:cmsis-csolution.getDeviceName}",
71-
"--pack",
72-
"${command:cmsis-csolution.getDfpPath}",
73-
"--port",
74-
"3333",
75-
"!!!REMOVE THIS AND FOLLOWING NOT YET SUPPORTED OPTIONS!!!",
76-
"--cbuild-run",
77-
"${command:cmsis-csolution.getCbuildRunPath}"
78-
],
7967
"port": "3333"
8068
},
8169
"cmsis": {
@@ -102,18 +90,6 @@
10290
],
10391
"target": {
10492
"server": "pyOCD",
105-
"serverParameters": [
106-
"gdbserver",
107-
"--target",
108-
"^\"\\${command:cmsis-csolution.getDeviceName}\"",
109-
"--pack",
110-
"^\"\\${command:cmsis-csolution.getDfpPath}\"",
111-
"--port",
112-
"3333",
113-
"!!!REMOVE THIS AND FOLLOWING NOT YET SUPPORTED OPTIONS!!!",
114-
"--cbuild-run",
115-
"^\"\\${command:cmsis-csolution.getCbuildRunPath}\""
116-
],
11793
"port": "3333"
11894
},
11995
"cmsis": {

src/debug-configuration/gdbtarget-configuration-provider.ts

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface GDBTargetConfigurationSubProvider {
3131
provider: vscode.DebugConfigurationProvider;
3232
}
3333

34+
type ResolverType = 'resolveDebugConfiguration' | 'resolveDebugConfigurationWithSubstitutedVariables';
35+
3436
const SUPPORTED_SUBPROVIDERS: GDBTargetConfigurationSubProvider[] = [
3537
{ serverRegExp: PYOCD_SERVER_TYPE_REGEXP, provider: new PyocdConfigurationProvider() },
3638
{ serverRegExp: JLINK_SERVER_TYPE_REGEXP, provider: new JlinkConfigurationProvider() },
@@ -49,47 +51,77 @@ export class GDBTargetConfigurationProvider implements vscode.DebugConfiguration
4951
);
5052
}
5153

52-
private isRelevantSubprovider(serverType: string, subProvider: GDBTargetConfigurationSubProvider): boolean {
54+
private isRelevantSubprovider(resolverType: ResolverType, serverType: string, subProvider: GDBTargetConfigurationSubProvider): boolean {
5355
const serverTypeMatch = subProvider.serverRegExp.test(serverType);
54-
const hasResolverFunction = !!subProvider.provider.resolveDebugConfigurationWithSubstitutedVariables;
56+
const hasResolverFunction = !!subProvider.provider[resolverType];
5557
return serverTypeMatch && hasResolverFunction;
5658
}
5759

58-
private getRelevantSubproviders(serverType?: string): GDBTargetConfigurationSubProvider[] {
60+
private getRelevantSubproviders(resolverType: ResolverType, serverType?: string): GDBTargetConfigurationSubProvider[] {
5961
if (!serverType) {
6062
return [];
6163
}
62-
return this.subProviders.filter(subProvider => this.isRelevantSubprovider(serverType, subProvider));
64+
return this.subProviders.filter(subProvider => this.isRelevantSubprovider(resolverType, serverType, subProvider));
65+
}
66+
67+
private getRelevantSubprovider(resolverType: ResolverType, serverType?: string): GDBTargetConfigurationSubProvider | undefined {
68+
const subproviders = this.getRelevantSubproviders(resolverType, serverType);
69+
if (!subproviders.length) {
70+
logger.debug('No relevant configuration subproviders found');
71+
return undefined;
72+
}
73+
if (subproviders.length > 1) {
74+
logger.warn('Multiple configuration subproviders detected. Using first in list:');
75+
subproviders.forEach((subprovider, index) => logger.warn(`#${index}: '${subprovider.serverRegExp}'`));
76+
}
77+
return subproviders[0];
6378
}
6479

65-
public async resolveDebugConfigurationWithSubstitutedVariables(
80+
private async resolveDebugConfigurationByResolverType(
81+
resolverType: ResolverType,
6682
folder: vscode.WorkspaceFolder | undefined,
6783
debugConfiguration: vscode.DebugConfiguration,
6884
token?: vscode.CancellationToken
6985
): Promise<vscode.DebugConfiguration | null | undefined> {
70-
logger.debug('Check for relevant configuration subproviders');
86+
logger.debug(`${resolverType}: Check for relevant configuration subproviders`);
7187
const gdbTargetConfig: GDBTargetConfiguration = debugConfiguration;
7288
const gdbServerType = gdbTargetConfig.target?.server;
73-
const relevantSubproviders = this.getRelevantSubproviders(gdbServerType);
74-
if (!relevantSubproviders.length) {
75-
logger.debug('No relevant configuration subproviders found');
89+
const subprovider = this.getRelevantSubprovider(resolverType, gdbServerType);
90+
if (!subprovider) {
7691
return debugConfiguration;
7792
}
78-
if (relevantSubproviders.length > 1) {
79-
logger.warn(`Multiple subproviders detected for '${debugConfiguration.request}' configuration '${debugConfiguration.name}'. Using first in list:`);
80-
relevantSubproviders.forEach((subprovider, index) => logger.warn(`#${index}: '${subprovider.serverRegExp}'`));
81-
}
82-
const selectedSubprovider = relevantSubproviders[0];
83-
if (!selectedSubprovider.provider.resolveDebugConfigurationWithSubstitutedVariables) {
84-
logger.debug(`Subprovider '${selectedSubprovider.serverRegExp}' does not implement 'resolveDebugConfigurationWithSubstitutedVariables'.`);
93+
if (!subprovider.provider[resolverType]) {
94+
logger.debug(`${resolverType}: Subprovider '${subprovider.serverRegExp}' does not implement '${resolverType}'.`);
8595
return debugConfiguration;
8696
}
87-
logger.debug(`Resolve config with subprovider '${selectedSubprovider.serverRegExp}'`);
88-
const resolvedConfig = await selectedSubprovider.provider.resolveDebugConfigurationWithSubstitutedVariables(folder, debugConfiguration, token);
97+
logger.debug(`${resolverType}: Resolve config with subprovider '${subprovider.serverRegExp}'`);
98+
logger.debug(`${resolverType}: original config:`);
99+
logger.debug(JSON.stringify(debugConfiguration));
100+
const resolvedConfig = await subprovider.provider[resolverType](folder, debugConfiguration, token);
89101
if (!resolvedConfig) {
90-
logger.error(`Resolving config failed with subprovider '${selectedSubprovider.serverRegExp}'`);
102+
logger.error(`${resolverType}: Resolving config failed with subprovider '${subprovider.serverRegExp}'`);
91103
}
104+
logger.debug(`${resolverType}: resolved config:`);
105+
logger.debug(JSON.stringify(resolvedConfig));
106+
logger.debug(`${resolverType}: expected server command line:`);
107+
const resolvedGDBConfig = resolvedConfig as GDBTargetConfiguration;
108+
logger.debug(`${resolvedGDBConfig.target?.server} ${resolvedGDBConfig.target?.serverParameters?.join(' ')}`);
92109
return resolvedConfig;
93110
}
94111

112+
public resolveDebugConfiguration(
113+
folder: vscode.WorkspaceFolder | undefined,
114+
debugConfiguration: vscode.DebugConfiguration,
115+
token?: vscode.CancellationToken
116+
): Promise<vscode.DebugConfiguration | null | undefined> {
117+
return this.resolveDebugConfigurationByResolverType('resolveDebugConfiguration', folder, debugConfiguration, token);
118+
}
119+
120+
public resolveDebugConfigurationWithSubstitutedVariables(
121+
folder: vscode.WorkspaceFolder | undefined,
122+
debugConfiguration: vscode.DebugConfiguration,
123+
token?: vscode.CancellationToken
124+
): Promise<vscode.DebugConfiguration | null | undefined> {
125+
return this.resolveDebugConfigurationByResolverType('resolveDebugConfigurationWithSubstitutedVariables', folder, debugConfiguration, token);
126+
}
95127
}

src/debug-configuration/gdbtarget-configuration.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ interface TargetConfiguration {
5656
uart?: UARTConfiguration;
5757
};
5858

59+
interface CMSISConfiguration {
60+
cbuildRunPath: string;
61+
}
62+
5963
export interface GDBTargetConfiguration extends vscode.DebugConfiguration {
6064
program?: string; // required as per 'gdbtarget' debugger contribution, but can be omitted anyway
6165
gdb?: string;
@@ -70,4 +74,5 @@ export interface GDBTargetConfiguration extends vscode.DebugConfiguration {
7074
preRunCommands?: string[];
7175
imageAndSymbols?: ImageAndSymbolsConfiguration;
7276
target?: TargetConfiguration;
77+
cmsis?: CMSISConfiguration;
7378
};

src/debug-configuration/subproviders/pyocd-configuration-provider.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,69 @@
1616

1717
import * as vscode from 'vscode';
1818
import { logger } from '../../logger';
19+
import { GDBTargetConfiguration } from '../gdbtarget-configuration';
1920

2021
export const PYOCD_SERVER_TYPE_REGEXP = /.*pyocd(|.exe)\s*$/i;
2122

2223
export class PyocdConfigurationProvider implements vscode.DebugConfigurationProvider {
2324

24-
public async resolveDebugConfigurationWithSubstitutedVariables(
25+
protected async hasCommand(commandName: string): Promise<boolean> {
26+
const commands = await vscode.commands.getCommands();
27+
return !!commands.find(command => command === commandName);
28+
};
29+
30+
protected hasParam(name: string, params: string[]): boolean {
31+
return !!params.find(param => param.trim() === name);
32+
}
33+
34+
protected async shouldAppendParam(params: string[], paramName: string, commandName?: string): Promise<boolean> {
35+
return !this.hasParam(paramName, params) && (!commandName || await this.hasCommand(commandName));
36+
}
37+
38+
protected async resolveServerParameters(debugConfiguration: GDBTargetConfiguration): Promise<GDBTargetConfiguration> {
39+
if (!debugConfiguration.target) {
40+
return debugConfiguration;
41+
}
42+
const parameters = debugConfiguration.target.serverParameters ??= [];
43+
// gdbserver
44+
if (await this.shouldAppendParam(parameters, 'gdbserver')) {
45+
parameters.push('gdbserver');
46+
}
47+
// target
48+
if (await this.shouldAppendParam(parameters, '--target')) {
49+
parameters.push('--target');
50+
parameters.push('${command:cmsis-csolution.getDeviceName}');
51+
}
52+
// pack
53+
if (await this.shouldAppendParam(parameters, '--pack')) {
54+
parameters.push('--pack');
55+
parameters.push('${command:cmsis-csolution.getDfpPath}');
56+
}
57+
// port (use value defined in 'port' outside 'serverParamters')
58+
const port = debugConfiguration.target?.port;
59+
if (await this.shouldAppendParam(parameters, '--port') && port) {
60+
parameters.push('--port');
61+
parameters.push(`${port}`);
62+
}
63+
// cbuild-run (ToDo: comment in the code when pyOCD supports it)
64+
/*
65+
const cbuildRunPath = debugConfiguration.cmsis?.cbuildRunPath;
66+
if (await this.shouldAppendParam(parameters, '--cbuild-run') && cbuildRunPath) {
67+
parameters.push('--cbuild-run');
68+
parameters.push(`${cbuildRunPath}`);
69+
}
70+
*/
71+
return debugConfiguration;
72+
}
73+
74+
public async resolveDebugConfiguration(
2575
_folder: vscode.WorkspaceFolder | undefined,
2676
debugConfiguration: vscode.DebugConfiguration,
2777
_token?: vscode.CancellationToken
2878
): Promise<vscode.DebugConfiguration | null | undefined> {
2979
logger.debug('Resolving pyOCD configuration');
30-
return debugConfiguration;
80+
const resolvedConfig = await this.resolveServerParameters(debugConfiguration);
81+
return resolvedConfig;
3182
}
3283

3384
}

0 commit comments

Comments
 (0)