Skip to content

Commit efff31e

Browse files
authored
Add handling for now included GDB redistributable (#388)
* handle list of tools * added customResetCommands to gdbtarget interface * handle builtin gdb path in gdbtarget config resolver * customResetCommands in debug config factory * 'all' script * warning notification if built-in tools not found * update vscode mocks * use file type instead of platform for download script * reviewed .vscodeignore * fix built-in gdb path and resolve only once * add lzma-native, peer dependency of fast-extract for 'xz' format * make sure we pass 'tar.xz' to fast-extract for proper chaining of tar and xz, leave in 'file-type' for later refinement --------- Signed-off-by: Jens Reinecke <jens.reinecke@arm.com>
1 parent a5515e6 commit efff31e

14 files changed

Lines changed: 276 additions & 41 deletions

.vscodeignore

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1+
__mocks__/**/*
12
.github
2-
.gitignore
3+
.qlty
34
.vscode
4-
.vscodeignore
55
*.vsix
6-
DEVELOPMENT.md
7-
__mocks__/**/*
6+
coverage
87
dist/**/*.js.map
8+
images/*.pptx
99
node_modules
10+
scripts
1011
src
12+
test-data
1113
test-workspace
14+
.gitignore
15+
.vscodeignore
16+
DEVELOPMENT.md
17+
test-report.html
1218
tsconfig.json
13-
scripts
14-
tools/**/version.txt
1519
tools/**/target.txt
1620
tools/**/sha256.txt
17-
coverage
1821
*.config.{mjs,js,mts,ts}
1922
*.setup.{mjs,js,mts,ts}

DEVELOPMENT.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ Supported `<target>`s are:
7575
7676
**Note**: At this point, no tests have been added to this repository.
7777
78+
## 'all' script
79+
80+
To simplify setup of you environment, an `all` script exists which runs build, tool download,
81+
and unit tests. Run:
82+
83+
```sh
84+
> yarn all
85+
```
86+
7887
## Updating tool dependencies
7988
8089
Tool dependencies are recorded in `package.json`:

__mocks__/vscode.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ module.exports = {
4747
warn: jest.fn(),
4848
error: jest.fn(),
4949
})),
50+
showWarningMessage: jest.fn(),
5051
},
5152
workspace: {
5253
getConfiguration: jest.fn(() => ({

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"watch": "webpack -w",
9393
"lint": "eslint .",
9494
"test": "jest --reporters=default --reporters=./node_modules/jest-html-reporter",
95+
"all": "yarn && yarn download-tools && yarn test",
9596
"package": "vsce package --yarn",
9697
"tpip:report": "ts-node scripts/tpip-reporter --header docs/tpip-header.md docs/third-party-licenses.json TPIP.md",
9798
"lint:md": "markdownlint **/*.md -c ./.github/markdownlint.jsonc -i ./node_modules ./dist ./coverage ./tools",
@@ -123,6 +124,7 @@
123124
"globby": "^14.1.0",
124125
"jest": "^30.0.4",
125126
"jest-html-reporter": "^4.3.0",
127+
"lzma-native": "8.0.6",
126128
"markdown-link-check": "^3.13.7",
127129
"markdownlint-cli": "^0.45.0",
128130
"node-fetch": "^3.3.2",

scripts/download-tools.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,16 +263,12 @@ async function downloadGDB(target: VsceTarget, dest: string, options?: ToolOptio
263263
console.debug(`Extracting ${downloadFilePath} to ${destPath} ...`);
264264
mkdirSync(dest, { recursive: true });
265265

266-
const {fileTypeFromFile} = await import('file-type');
267-
268-
const fileType = await fileTypeFromFile(downloadFilePath);
269-
270-
if (nodeOs.platform() === 'win32') {
266+
if (ext === 'zip') {
271267
await extractZip(downloadFilePath, { dir: destPath }).catch(error => {
272268
throw new Error(`Failed to extract ${url}`, { cause: error });
273269
});
274270
} else {
275-
await fastExtract(downloadFilePath, destPath, { strip: 1, type: fileType?.ext }).catch(error => {
271+
await fastExtract(downloadFilePath, destPath, { strip: 1, type: ext }).catch(error => {
276272
throw new Error(`Failed to extract ${downloadFilePath}`, { cause: error });
277273
});
278274
}

src/debug-configuration/debug-configuration.factory.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const gdbTargetConfiguration = makeFactory<GDBTargetConfiguration>({
5353
logFile: () => undefined,
5454
openGdbConsole: () => undefined,
5555
initCommands: () => undefined,
56+
customResetCommands: () => undefined,
5657
preRunCommands: () => undefined,
5758
imageAndSymbols: () => undefined,
5859
target: () => undefined,

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { GDBTargetConfigurationProvider } from './gdbtarget-configuration-provider';
17+
import { GDBTargetConfiguration, GDBTargetConfigurationProvider } from '.'; // use index.ts to cover it in one test
1818
import { extensionContextFactory } from '../__test__/vscode.factory';
1919

2020
import * as vscode from 'vscode';
21+
import { URI } from 'vscode-uri';
2122
import { debugConfigurationFactory } from './debug-configuration.factory';
23+
import { BuiltinToolPath } from '../desktop/builtin-tool-path';
24+
import { isWindows } from '../utils';
25+
26+
jest.mock('../desktop/builtin-tool-path');
27+
const BuiltinToolPathMock = BuiltinToolPath as jest.MockedClass<typeof BuiltinToolPath>;
2228

2329
describe('GDBTargetConfigurationProvider', () => {
2430

@@ -49,4 +55,46 @@ describe('GDBTargetConfigurationProvider', () => {
4955

5056
expect(resolvedDebugConfig).toBeDefined();
5157
});
58+
59+
it('resolves debug configuration and keeps gdb path if other than \'arm-none-eabi-gdb\'', async () => {
60+
const absoluteGdbPath = '/absolute/path/to/gdb/arm-none-eabi-gdb';
61+
const debugConfig = debugConfigurationFactory({
62+
gdb: absoluteGdbPath
63+
});
64+
65+
const getAbsolutePathSpy = jest.spyOn(BuiltinToolPath.prototype, 'getAbsolutePath');
66+
67+
const configProvider = new GDBTargetConfigurationProvider([]);
68+
const resolvedDebugConfig = await configProvider.resolveDebugConfigurationWithSubstitutedVariables(
69+
undefined,
70+
debugConfig,
71+
undefined) as GDBTargetConfiguration;
72+
73+
expect(resolvedDebugConfig).toBeDefined();
74+
expect(resolvedDebugConfig.gdb).toEqual(absoluteGdbPath);
75+
expect(getAbsolutePathSpy).not.toHaveBeenCalled();
76+
});
77+
78+
it('resolves debug configuration and replaces \'arm-none-eabi-gdb\' with built-in tool path', async () => {
79+
const absoluteGdbPath = '/absolute/path/to/gdb/arm-none-eabi-gdb';
80+
const expectedGdbPath = isWindows ? absoluteGdbPath.replaceAll('/', '\\') : absoluteGdbPath;
81+
const gdbUri = URI.parse(absoluteGdbPath);
82+
const debugConfig = debugConfigurationFactory({
83+
gdb: 'arm-none-eabi-gdb'
84+
});
85+
86+
const builtinToolMockInstance = {
87+
getAbsolutePath: jest.fn().mockReturnValue(gdbUri),
88+
} as unknown as BuiltinToolPath;
89+
BuiltinToolPathMock.mockImplementation(() => builtinToolMockInstance);
90+
91+
const configProvider = new GDBTargetConfigurationProvider([]);
92+
const resolvedDebugConfig = await configProvider.resolveDebugConfigurationWithSubstitutedVariables(
93+
undefined,
94+
debugConfig,
95+
undefined) as GDBTargetConfiguration;
96+
97+
expect(resolvedDebugConfig).toBeDefined();
98+
expect(resolvedDebugConfig.gdb).toEqual(expectedGdbPath);
99+
});
52100
});

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ import {
2323
JLINK_SERVER_TYPE_REGEXP,
2424
JlinkConfigurationProvider
2525
} from './subproviders';
26+
import { BuiltinToolPath } from '../desktop/builtin-tool-path';
2627

2728
const GDB_TARGET_DEBUGGER_TYPE = 'gdbtarget';
29+
const ARM_NONE_EABI_GDB_NAME = 'arm-none-eabi-gdb';
30+
const ARM_NONE_EABI_GDB_BUILTIN_PATH = 'tools/gdb/bin/arm-none-eabi-gdb';
31+
const ARM_NONE_EABI_GDB_EXECUTABLE_ONLY_REGEXP = /^\s*arm-none-eabi-gdb(|.exe)\s*$/i;
2832

2933
export interface GDBTargetConfigurationSubProvider {
3034
serverRegExp: RegExp;
@@ -40,6 +44,7 @@ const SUPPORTED_SUBPROVIDERS: GDBTargetConfigurationSubProvider[] = [
4044

4145

4246
export class GDBTargetConfigurationProvider implements vscode.DebugConfigurationProvider {
47+
protected builtinArmNoneEabiGdb = new BuiltinToolPath(ARM_NONE_EABI_GDB_BUILTIN_PATH);
4348

4449
public constructor(
4550
protected subProviders: GDBTargetConfigurationSubProvider[] = SUPPORTED_SUBPROVIDERS
@@ -132,6 +137,21 @@ export class GDBTargetConfigurationProvider implements vscode.DebugConfiguration
132137
debugConfiguration: vscode.DebugConfiguration,
133138
token?: vscode.CancellationToken
134139
): Promise<vscode.DebugConfiguration | null | undefined> {
140+
// Only resolve GDB path once, otherwise regexp check will fail
141+
logger.debug('resolveDebugConfigurationWithSubstitutedVariables: Resolve GDB path');
142+
this.resolveGdbPath(debugConfiguration);
135143
return this.resolveDebugConfigurationByResolverType('resolveDebugConfigurationWithSubstitutedVariables', folder, debugConfiguration, token);
136144
}
145+
146+
protected resolveGdbPath(config: GDBTargetConfiguration): void {
147+
const gdb = config.gdb;
148+
const useBuiltin = !gdb || ARM_NONE_EABI_GDB_EXECUTABLE_ONLY_REGEXP.test(gdb);
149+
const updateUri = useBuiltin ? this.builtinArmNoneEabiGdb.getAbsolutePath() : undefined;
150+
if (updateUri) {
151+
config.gdb = updateUri.fsPath;
152+
} else {
153+
vscode.window.showWarningMessage(`Cannot find ${ARM_NONE_EABI_GDB_BUILTIN_PATH} in CMSIS Debugger installation.\nUsing ${ARM_NONE_EABI_GDB_NAME} from PATH instead.`);
154+
}
155+
}
156+
137157
}

src/debug-configuration/gdbtarget-configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export interface GDBTargetConfiguration extends vscode.DebugConfiguration {
6969
logFile?: string;
7070
openGdbConsole?: boolean;
7171
initCommands?: string[];
72+
customResetCommands?: string[];
7273
preRunCommands?: string[];
7374
imageAndSymbols?: ImageAndSymbolsConfiguration;
7475
target?: TargetConfiguration;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
* limitations under the License.
1515
*/
1616

17+
import * as vscode from 'vscode';
1718
import { BaseConfigurationProvider } from './base-configuration-provider';
1819
import { GDBTargetConfiguration, TargetConfiguration } from '../gdbtarget-configuration';
1920
import { BuiltinToolPath } from '../../desktop/builtin-tool-path';
2021
import { getCmsisPackRootPath } from '../../utils';
2122
import { logger } from '../../logger';
2223

24+
const PYOCD_NAME = 'pyocd';
2325
const PYOCD_BUILTIN_PATH = 'tools/pyocd/pyocd';
2426
const PYOCD_EXECUTABLE_ONLY_REGEXP = /^\s*pyocd(|.exe)\s*$/i;
2527
export const PYOCD_SERVER_TYPE_REGEXP = /.*pyocd(|.exe)\s*$/i;
@@ -37,6 +39,8 @@ export class PyocdConfigurationProvider extends BaseConfigurationProvider {
3739
const updateUri = useBuiltin ? this.builtinPyocd.getAbsolutePath() : undefined;
3840
if (updateUri) {
3941
target.server = updateUri.fsPath;
42+
} else {
43+
vscode.window.showWarningMessage(`Cannot find ${PYOCD_BUILTIN_PATH} in CMSIS Debugger installation.\nUsing ${PYOCD_NAME} from PATH instead.`);
4044
}
4145
}
4246

0 commit comments

Comments
 (0)