Skip to content

Commit 4dad47e

Browse files
authored
Merge pull request #233 from raspberrypi/fix-zephyr-component-handling
Fix zephyr component handling
2 parents fe1bb06 + 45dee5c commit 4dad47e

File tree

6 files changed

+156
-0
lines changed

6 files changed

+156
-0
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@
285285
"title": "Get git path",
286286
"category": "Raspberry Pi Pico",
287287
"enablement": "false"
288+
},
289+
{
290+
"command": "raspberry-pi-pico.cleanZephyr",
291+
"title": "Remove Zephyr workspace",
292+
"category": "Raspberry Pi Pico"
288293
}
289294
],
290295
"configuration": {

src/commands/cleanZephyr.mts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { commands, Uri, window, workspace } from "vscode";
2+
import { CLEAN_ZEPHYR } from "./cmdIds.mjs";
3+
import { Command } from "./command.mjs";
4+
import Logger from "../logger.mjs";
5+
import { homedir } from "os";
6+
import { unknownErrorToString } from "../utils/errorHelper.mjs";
7+
import State from "../state.mjs";
8+
9+
export class CleanZephyrCommand extends Command {
10+
private _logger: Logger = new Logger("CleanZephyrCommand");
11+
12+
public constructor() {
13+
super(CLEAN_ZEPHYR);
14+
}
15+
16+
public override async execute(): Promise<void> {
17+
const zephyrWorkspaceUri = Uri.joinPath(
18+
Uri.file(homedir()),
19+
".pico-sdk",
20+
"zephyr_workspace"
21+
);
22+
23+
try {
24+
await workspace.fs.stat(zephyrWorkspaceUri);
25+
26+
await workspace.fs.delete(zephyrWorkspaceUri, { recursive: true });
27+
this._logger.info(
28+
`Zephyr workspace at ${zephyrWorkspaceUri.fsPath} has been removed.`
29+
);
30+
if (State.getInstance().isZephyrProject) {
31+
const answer = await window.showInformationMessage(
32+
"Zephyr workspace has been removed. " +
33+
"Reload the window to reinitialize the Zephyr workspace.",
34+
"Reload Window"
35+
);
36+
37+
if (answer === "Reload Window") {
38+
await commands.executeCommand("workbench.action.reloadWindow");
39+
}
40+
} else {
41+
void window.showInformationMessage(
42+
"Zephyr workspace has been removed."
43+
);
44+
}
45+
} catch (e) {
46+
this._logger.warn(
47+
`Zephyr workspace at ${zephyrWorkspaceUri.fsPath} ` +
48+
`does not exist or could not be accessed: ${unknownErrorToString(e)}`
49+
);
50+
void window.showInformationMessage(
51+
"A Zephyr workspace does not exist or could not be accessed."
52+
);
53+
}
54+
}
55+
}

src/commands/cmdIds.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,5 @@ export const UNINSTALL_PICO_SDK = "uninstallPicoSDK";
4747
export const UPDATE_OPENOCD = "updateOpenOCD";
4848

4949
export const OPEN_UNINSTALLER = "openUninstaller";
50+
51+
export const CLEAN_ZEPHYR = "cleanZephyr";

src/extension.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ import LastUsedDepsStore from "./utils/lastUsedDeps.mjs";
127127
import { getWebviewOptions } from "./webview/sharedFunctions.mjs";
128128
import { UninstallerPanel } from "./webview/uninstallerPanel.mjs";
129129
import OpenUninstallerCommand from "./commands/openUninstaller.mjs";
130+
import { CleanZephyrCommand } from "./commands/cleanZephyr.mjs";
130131

131132
export async function activate(context: ExtensionContext): Promise<void> {
132133
Logger.info(LoggerSource.extension, "Extension activation triggered");
@@ -187,6 +188,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
187188
new SbomTargetPathReleaseCommand(),
188189
new OpenUninstallerCommand(context.extensionUri),
189190
new GetGitPathCommand(settings),
191+
new CleanZephyrCommand(),
190192
];
191193

192194
// register all command handlers

src/utils/setupZephyr.mts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import VersionBundlesLoader, { type VersionBundle } from "./versionBundles.mjs";
2626
import {
2727
CURRENT_DTC_VERSION,
2828
CURRENT_GPERF_VERSION,
29+
GET_PIP_URL,
2930
LICENSE_URL_7ZIP,
3031
OPENOCD_VERSION,
3132
SDK_REPOSITORY_URL,
@@ -355,6 +356,84 @@ async function checkPicotool(latestVb: VersionBundle): Promise<boolean> {
355356
);
356357
}
357358

359+
async function preparePython(python3Path: string): Promise<boolean> {
360+
if (!python3Path.includes(".pico-sdk") || process.platform !== "win32") {
361+
return true;
362+
}
363+
364+
// download get-pip.py and run it
365+
const getPipUrl = new URL(GET_PIP_URL);
366+
const getPipTarget = join(dirname(python3Path), "get-pip.py");
367+
368+
const downloadResult = await downloadFileGot(getPipUrl, getPipTarget);
369+
if (!downloadResult) {
370+
Logger.error(
371+
LoggerSource.zephyrSetup,
372+
"Failed to download get-pip.py for Python setup."
373+
);
374+
375+
return false;
376+
}
377+
378+
const pipInstallCommand: string = `"${python3Path}" "${getPipTarget}"`;
379+
380+
const result = await _runCommand(pipInstallCommand, {
381+
windowsHide: true,
382+
});
383+
if (result !== 0) {
384+
Logger.error(
385+
LoggerSource.zephyrSetup,
386+
"Failed to install pip for Python setup."
387+
);
388+
389+
return false;
390+
}
391+
392+
// add pip to python path by modifying the ._pth file
393+
const dirContents = await workspace.fs.readDirectory(
394+
Uri.file(dirname(python3Path))
395+
);
396+
397+
const pthFile = dirContents.find(item => item[0].endsWith("._pth"));
398+
if (pthFile === undefined) {
399+
Logger.error(
400+
LoggerSource.zephyrSetup,
401+
"Failed to find ._pth file for Python setup."
402+
);
403+
404+
return false;
405+
}
406+
407+
const pthFileUri = Uri.file(join(dirname(python3Path), pthFile[0]));
408+
let pthFileContents = await workspace.fs.readFile(pthFileUri);
409+
let pthFileString = pthFileContents.toString();
410+
pthFileString = pthFileString.replace(
411+
"#import site",
412+
"Lib\\site-packages\nScripts\n.\n\n#import site"
413+
);
414+
pthFileContents = Buffer.from(pthFileString, "utf-8");
415+
await workspace.fs.writeFile(pthFileUri, pthFileContents);
416+
417+
const pipPathCommand: string =
418+
`"${python3Path}" -m pip install --upgrade ` +
419+
"pip setuptools wheel virtualenv";
420+
421+
const pipResult = await _runCommand(pipPathCommand, {
422+
windowsHide: true,
423+
});
424+
425+
if (pipResult !== 0) {
426+
Logger.error(
427+
LoggerSource.zephyrSetup,
428+
"Failed to upgrade pip, setuptools, wheel and virtualenv."
429+
);
430+
431+
return false;
432+
}
433+
434+
return true;
435+
}
436+
358437
async function checkSdk(
359438
extensionUri: Uri,
360439
latestVb: [string, VersionBundle],
@@ -926,6 +1005,18 @@ export async function setupZephyr(
9261005

9271006
return false;
9281007
}
1008+
if (!(await preparePython(python3Path))) {
1009+
progress.report({
1010+
message: "Failed",
1011+
increment: 100,
1012+
});
1013+
void window.showErrorMessage(
1014+
"Failed to prepare Python for Zephyr setup. " +
1015+
"Cannot continue Zephyr setup."
1016+
);
1017+
1018+
return false;
1019+
}
9291020

9301021
// required for svd files
9311022
const sdk = await checkSdk(data.extUri, latestVb, python3Path);

src/utils/sharedConstants.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const WINDOWS_X86_PYTHON_DOWNLOAD_URL =
33
export const WINDOWS_ARM64_PYTHON_DOWNLOAD_URL =
44
"https://www.python.org/ftp/python/3.13.7/python-3.13.7-embed-arm64.zip";
55
export const CURRENT_PYTHON_VERSION = "3.13.7";
6+
export const GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py";
67

78
export const CURRENT_DATA_VERSION = "0.18.0";
89
export const OPENOCD_VERSION = "0.12.0+dev";

0 commit comments

Comments
 (0)