diff --git a/README.md b/README.md index 05c9d8c..4fc1e16 100644 --- a/README.md +++ b/README.md @@ -112,9 +112,9 @@ For further context, see this discussion in the Zephyr project: https://github.c ## Additonal Zephyr Prerequisites -> On Raspberry Pi OS Trixie these come pre-installed. +> On Raspberry Pi OS Trixie all of those come pre-installed. -* **wget** - Required for sdk-ng to download toolchains. Install via your package manager (e.g., `brew install wget` on macOS or `sudo apt install wget` on Debian based Linux distributions). +* **wget** - Required for sdk-ng to download toolchains. ### Linux and macOS only diff --git a/package-lock.json b/package-lock.json index 6fb8e1f..c06dda0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "raspberry-pi-pico", - "version": "0.18.0", + "version": "0.18.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "raspberry-pi-pico", - "version": "0.18.0", + "version": "0.18.1", "cpu": [ "x64", "arm64" diff --git a/package.json b/package.json index e98fce4..49f9ef5 100644 --- a/package.json +++ b/package.json @@ -279,6 +279,12 @@ "command": "raspberry-pi-pico.openUninstaller", "title": "Open Uninstaller", "category": "Raspberry Pi Pico" + }, + { + "command": "raspberry-pi-pico.getGitPath", + "title": "Get git path", + "category": "Raspberry Pi Pico", + "enablement": "false" } ], "configuration": { diff --git a/src/commands/cmdIds.mts b/src/commands/cmdIds.mts index 51ee884..114b8b9 100644 --- a/src/commands/cmdIds.mts +++ b/src/commands/cmdIds.mts @@ -21,6 +21,7 @@ export const GET_SVD_PATH = "getSVDPath"; export const GET_WEST_PATH = "getWestPath"; export const GET_ZEPHYR_WORKSPACE_PATH = "getZephyrWorkspacePath"; export const GET_ZEPHYR_SDK_PATH = "getZephyrSDKPath"; +export const GET_GIT_PATH = "getGitPath"; export const IMPORT_PROJECT = "importProject"; diff --git a/src/commands/getPaths.mts b/src/commands/getPaths.mts index f7b5d36..cc2bd86 100644 --- a/src/commands/getPaths.mts +++ b/src/commands/getPaths.mts @@ -35,6 +35,7 @@ import { GET_CXX_COMPILER_PATH, GET_ENV_PATH, GET_GDB_PATH, + GET_GIT_PATH, GET_OPENOCD_ROOT, GET_PICOTOOL_PATH, GET_PYTHON_PATH, @@ -54,6 +55,7 @@ import { ZEPHYR_PICO2_W, ZEPHYR_PICO_W, } from "../models/zephyrBoards.mjs"; +import { ensureGit } from "../utils/gitUtil.mjs"; export class GetPythonPathCommand extends CommandWithResult { constructor() { @@ -628,9 +630,28 @@ export class GetZephyrSDKPathCommand extends CommandWithResult< await workspace.fs.stat(Uri.file(result)); const zephyrSdkVersion = await getZephyrSDKVersion(); - return joinPosix(result, `zephyr-sdk-${zephyrSdkVersion}`); + return joinPosix(result, `zephyr-sdk-${zephyrSdkVersion ?? "unknown"}`); } catch { return undefined; } } } + +export class GetGitPathCommand extends CommandWithResult { + constructor(private readonly _settings: Settings) { + super(GET_GIT_PATH); + } + + async execute(): Promise { + const gitPath = await ensureGit(this._settings, { returnPath: true }); + if ( + typeof gitPath !== "string" || + gitPath.length === 0 || + !gitPath.includes("/") + ) { + return ""; + } + + return gitPath; + } +} diff --git a/src/extension.mts b/src/extension.mts index 198415d..0fe0fbf 100644 --- a/src/extension.mts +++ b/src/extension.mts @@ -56,6 +56,7 @@ import { GetWestPathCommand, GetZephyrWorkspacePathCommand, GetZephyrSDKPathCommand, + GetGitPathCommand, } from "./commands/getPaths.mjs"; import { downloadAndInstallCmake, @@ -184,6 +185,7 @@ export async function activate(context: ExtensionContext): Promise { new SbomTargetPathDebugCommand(), new SbomTargetPathReleaseCommand(), new OpenUninstallerCommand(context.extensionUri), + new GetGitPathCommand(settings), ]; // register all command handlers diff --git a/src/utils/download.mts b/src/utils/download.mts index f99c3e8..25a030d 100644 --- a/src/utils/download.mts +++ b/src/utils/download.mts @@ -520,6 +520,7 @@ export async function downloadAndInstallSDK( return false; } + // TODO: option to parse already resolved path into this function // TODO: this does take about 2s - may be reduced const gitPath = await ensureGit(settings, { returnPath: true }); if (typeof gitPath !== "string" || gitPath.length === 0) { diff --git a/src/utils/projectGeneration/projectZephyr.mts b/src/utils/projectGeneration/projectZephyr.mts index 225269f..da8bc3f 100644 --- a/src/utils/projectGeneration/projectZephyr.mts +++ b/src/utils/projectGeneration/projectZephyr.mts @@ -1,6 +1,6 @@ /* eslint-disable max-len */ /* eslint-disable @typescript-eslint/naming-convention */ -import { dirname, join } from "path"; +import { join } from "path"; import { dirname as dirnamePosix } from "path/posix"; import Logger, { LoggerSource } from "../../logger.mjs"; import { unknownErrorToString } from "../errorHelper.mjs"; @@ -27,10 +27,12 @@ import { import { homedir } from "os"; import { GET_CHIP_UPPERCASE, + GET_GIT_PATH, GET_OPENOCD_ROOT, GET_PICOTOOL_PATH, GET_TARGET, GET_WEST_PATH, + GET_ZEPHYR_SDK_PATH, GET_ZEPHYR_WORKSPACE_PATH, } from "../../commands/cmdIds.mjs"; import { getZephyrSDKVersion, getZephyrVersion } from "../setupZephyr.mjs"; @@ -69,8 +71,7 @@ async function generateVSCodeConfig( ninjaPath: string, cmakePath: string, te: TextEncoder = new TextEncoder(), - data: ZephyrSubmitMessageValue, - gitPath: string + data: ZephyrSubmitMessageValue ): Promise { const vsc = join(projectRoot, ".vscode"); @@ -164,7 +165,7 @@ async function generateVSCodeConfig( toolchainPrefix: "arm-zephyr-eabi", armToolchainPath: // TODO: maybe just full get zephyr compiler path command - `\${command:${extensionName}.${GET_ZEPHYR_WORKSPACE_PATH}}/zephyr-sdk/arm-zephyr-eabi/bin`, + `\${command:${extensionName}.${GET_ZEPHYR_SDK_PATH}}/arm-zephyr-eabi/bin`, // TODO: get chip dynamically maybe: chip: `\${command:${extensionName}.${GetChipCommand.id}}`, // meaning only one cfg required device: `\${command:${extensionName}.${GET_CHIP_UPPERCASE}}`, @@ -179,6 +180,8 @@ async function generateVSCodeConfig( openOCDLaunchCommands: ["adapter speed 5000"], // TODO: add zephyr build support to support this. rtos: "Zephyr", + // TODO: maybe get into launch target path command like in c/c++ projects + preLaunchTask: "Compile Project", }, ], }; @@ -205,15 +208,13 @@ async function generateVSCodeConfig( "terminal.integrated.env.windows": { // remove gperf and dtc for now // \${env:USERPROFILE}/.pico-sdk/dtc/${CURRENT_DTC_VERSION}/bin;\${env:USERPROFILE}/.pico-sdk/gperf/${CURRENT_GPERF_VERSION} - Path: `${dirname( - gitPath - )};\${env:USERPROFILE}/.pico-sdk/7zip;\${env:Path};`, + Path: "${env:USERPROFILE}/.pico-sdk/7zip;${env:Path};", }, "terminal.integrated.env.osx": { - PATH: `${dirname(gitPath)}:\${env:PATH}:`, + PATH: "${env:PATH}:", }, "terminal.integrated.env.linux": { - PATH: `${dirname(gitPath)}:\${env:PATH}:`, + PATH: "${env:PATH}:", }, "raspberry-pi-pico.cmakeAutoConfigure": true, "raspberry-pi-pico.useCmakeTools": false, @@ -331,9 +332,15 @@ async function generateVSCodeConfig( problemMatcher: "$gcc", options: { cwd: `\${command:${extensionName}.${GET_ZEPHYR_WORKSPACE_PATH}}`, + env: { + PATH: `\${command:${extensionName}.${GET_GIT_PATH}}:\${env:PATH}:`, + }, }, windows: { options: { + env: { + Path: `\${command:${extensionName}.${GET_GIT_PATH}};\${env:Path};`, + }, shell: { executable: "cmd.exe", args: ["/d", "/c"], @@ -365,6 +372,8 @@ async function generateVSCodeConfig( panel: "dedicated", }, problemMatcher: [], + dependsOrder: "sequence", + dependsOn: "Compile Project", }, ], }; @@ -1170,8 +1179,7 @@ export async function generateZephyrProject( latestVb: [string, VersionBundle], ninjaPath: string, cmakePath: string, - data: ZephyrSubmitMessageValue, - gitPath: string + data: ZephyrSubmitMessageValue ): Promise { const projectRoot = join(projectFolder, projectName); @@ -1245,8 +1253,7 @@ export async function generateZephyrProject( ninjaPath, cmakePath, te, - data, - gitPath + data ); if (!result) { Logger.debug( diff --git a/src/utils/setupZephyr.mts b/src/utils/setupZephyr.mts index 5bf6b36..fbd4e97 100644 --- a/src/utils/setupZephyr.mts +++ b/src/utils/setupZephyr.mts @@ -685,6 +685,126 @@ async function checkOpenOCD(): Promise { ); } +async function fetchBinaryBlobs( + westExe: string, + zephyrWorkspaceDirectory: string, + customEnv: NodeJS.ProcessEnv +): Promise { + const sleep = (ms: number): Promise => + new Promise(res => setTimeout(res, ms)); + + const runOnce = async (): Promise => + window.withProgress( + { + location: ProgressLocation.Notification, + title: "Fetching Zephyr binary blobs", + cancellable: false, + }, + async progress2 => { + const westBlobsFetchCommand: string = + `"${westExe}" blobs fetch ` + "hal_infineon"; + + const result = await _runCommand(westBlobsFetchCommand, { + cwd: zephyrWorkspaceDirectory, + windowsHide: true, + env: customEnv, + }); + + if (result === 0) { + progress2.report({ + message: "Success", + increment: 100, + }); + + return true; + } else { + progress2.report({ + message: "Failed", + increment: 100, + }); + + return false; + } + } + ); + + // first attempt + const first = await runOnce(); + if (first) { + return true; + } + + // retry once after a brief delay + await sleep(1000); + + return runOnce(); +} + +async function installWestPyDeps( + westExe: string, + zephyrWorkspaceDirectory: string, + customEnv: NodeJS.ProcessEnv +): Promise { + const sleep = (ms: number): Promise => + new Promise(res => setTimeout(res, ms)); + + const runOnce = async (): Promise => + window.withProgress( + { + location: ProgressLocation.Notification, + title: "Installing West Python dependencies", + cancellable: false, + }, + async progress2 => { + const westPipPackagesCommand: string = + `"${westExe}" packages ` + "pip --install"; + + const result = await _runCommand(westPipPackagesCommand, { + cwd: zephyrWorkspaceDirectory, + windowsHide: true, + env: customEnv, + }); + + if (result === 0) { + Logger.debug( + LoggerSource.zephyrSetup, + "West Python dependencies installed." + ); + progress2.report({ + message: "Success", + increment: 100, + }); + + return true; + } else { + Logger.error( + LoggerSource.zephyrSetup, + "Error installing West Python dependencies." + ); + progress2.report({ + message: "Failed", + increment: 100, + }); + + return false; + } + } + ); + + const first = await runOnce(); + if (first) { + return true; + } + Logger.debug( + LoggerSource.zephyrSetup, + "Retrying installation of West Python dependencies..." + ); + + await sleep(1000); + + return runOnce(); +} + export async function setupZephyr( data: ZephyrSetupValue, gitExe?: string @@ -785,7 +905,10 @@ export async function setupZephyr( } // install python (if necessary) - const python3Path = await findPython(); + const python3Path = (await findPython())?.replace( + HOME_VAR, + homedir().replaceAll("\\", "/") + ); if (!python3Path) { progress.report({ message: "Failed", @@ -957,6 +1080,10 @@ export async function setupZephyr( message: "Failed", increment: 100, }); + void window.showErrorMessage( + "Failed to create Python virtual environment for Zephyr. " + + "Cannot continue Zephyr setup." + ); return false; } @@ -1003,6 +1130,10 @@ export async function setupZephyr( message: "Failed", increment: 100, }); + void window.showErrorMessage( + "Failed to install West and / or pyelftools in the Zephyr Python " + + "virtual environment. Cannot continue Zephyr setup." + ); return false; } @@ -1059,6 +1190,8 @@ export async function setupZephyr( return false; } + + await updateZephyrBase("zephyr-main", true); } const westUpdateCommand: string = `"${westExe}" update`; @@ -1090,6 +1223,10 @@ export async function setupZephyr( message: "Failed", increment: 100, }); + void window.showErrorMessage( + "Failed to setup West workspace and / or download zephyr. " + + "Cannot continue Zephyr setup." + ); return false; } @@ -1117,94 +1254,40 @@ export async function setupZephyr( return false; } - installedSuccessfully = await window.withProgress( - { - location: ProgressLocation.Notification, - title: "Installing West Python dependencies", - cancellable: false, - }, - async progress2 => { - const westPipPackagesCommand: string = - `"${westExe}" packages ` + "pip --install"; - - result = await _runCommand(westPipPackagesCommand, { - cwd: zephyrWorkspaceDirectory, - windowsHide: true, - env: customEnv, - }); - - if (result === 0) { - Logger.debug( - LoggerSource.zephyrSetup, - "West Python dependencies installed." - ); - progress2.report({ - message: "Success", - increment: 100, - }); - - return true; - } else { - Logger.error( - LoggerSource.zephyrSetup, - "Error installing West Python dependencies." - ); - progress2.report({ - message: "Failed", - increment: 100, - }); - - return false; - } - } + installedSuccessfully = await installWestPyDeps( + westExe, + zephyrWorkspaceDirectory, + customEnv ); if (!installedSuccessfully) { progress.report({ message: "Failed", increment: 100, }); + void window.showErrorMessage( + "Failed to install West Python dependencies. " + + "Cannot continue Zephyr setup. " + + "See extension host output for more details." + ); return false; } - installedSuccessfully = await window.withProgress( - { - location: ProgressLocation.Notification, - title: "Fetching Zephyr binary blobs", - cancellable: false, - }, - async progress2 => { - const westBlobsFetchCommand: string = - `"${westExe}" blobs fetch ` + "hal_infineon"; - - result = await _runCommand(westBlobsFetchCommand, { - cwd: zephyrWorkspaceDirectory, - windowsHide: true, - env: customEnv, - }); - - if (result === 0) { - progress2.report({ - message: "Success", - increment: 100, - }); - - return true; - } else { - progress2.report({ - message: "Failed", - increment: 100, - }); - - return false; - } - } + installedSuccessfully = await fetchBinaryBlobs( + westExe, + zephyrWorkspaceDirectory, + customEnv ); if (!installedSuccessfully) { progress.report({ message: "Failed", increment: 100, }); + void window.showErrorMessage( + "Failed to fetch Zephyr binary blobs. " + + "Cannot continue Zephyr setup. " + + "See extension host output for more details." + ); return false; } @@ -1429,7 +1512,7 @@ export async function getZephyrSDKVersion( const zephyrWorkspaceDirectory = buildZephyrWorkspacePath(); const sdkVersionFile = joinPosix( zephyrWorkspaceDirectory, - `zephyr-${zephyrVersion}`, + `zephyr-${zVersion}`, "SDK_VERSION" ); diff --git a/src/webview/newZephyrProjectPanel.mts b/src/webview/newZephyrProjectPanel.mts index f273b90..5c03054 100644 --- a/src/webview/newZephyrProjectPanel.mts +++ b/src/webview/newZephyrProjectPanel.mts @@ -345,8 +345,7 @@ export class NewZephyrProjectPanel { zephyrSetupOutputs.latestVb, zephyrSetupOutputs.ninjaExecutable, zephyrSetupOutputs.cmakeExecutable, - data, - gitPath + data ); if (!result) { progress.report({