Skip to content

Commit 8d99a43

Browse files
author
Magpie Embedded
committed
Add support for different Ninja setups
1 parent ebe4abd commit 8d99a43

File tree

3 files changed

+233
-14
lines changed

3 files changed

+233
-14
lines changed

src/utils/setupZephyr.mts

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Progress as GotProgress } from "got";
99

1010
import {
1111
buildCMakePath,
12+
buildNinjaPath,
1213
buildZephyrWorkspacePath,
1314
downloadAndInstallArchive,
1415
downloadAndInstallCmake,
@@ -50,10 +51,14 @@ interface ZephyrSetupValue {
5051
cmakeMode: number;
5152
cmakePath: string;
5253
cmakeVersion: string;
54+
ninjaMode: number;
55+
ninjaPath: string;
56+
ninjaVersion: string;
5357
}
5458

5559
interface ZephyrSetupOutputs {
5660
cmakeExecutable: string;
61+
ninjaExecutable: string;
5762
}
5863

5964
function _runCommand(
@@ -89,7 +94,7 @@ export async function setupZephyr(
8994
return;
9095
}
9196

92-
let output: ZephyrSetupOutputs = { cmakeExecutable: "" };
97+
let output: ZephyrSetupOutputs = { cmakeExecutable: "", ninjaExecutable: "" };
9398

9499
let python3Path = "";
95100
let isWindows = false;
@@ -214,6 +219,89 @@ export async function setupZephyr(
214219

215220
return;
216221
}
222+
223+
switch (data.ninjaMode) {
224+
case 0:
225+
// eslint-disable-next-line no-fallthrough
226+
case 2:
227+
installedSuccessfully = false;
228+
prog2LastState = 0;
229+
await window.withProgress(
230+
{
231+
location: ProgressLocation.Notification,
232+
title: "Download and install Ninja",
233+
cancellable: false,
234+
},
235+
async progress2 => {
236+
if (
237+
await downloadAndInstallNinja(
238+
data.ninjaVersion,
239+
(prog: GotProgress) => {
240+
const per = prog.percent * 100;
241+
progress2.report({
242+
increment: per - prog2LastState,
243+
});
244+
prog2LastState = per;
245+
}
246+
)
247+
) {
248+
progress2.report({
249+
message: "Successfully downloaded and installed Ninja.",
250+
increment: 100,
251+
});
252+
253+
installedSuccessfully = true;
254+
} else {
255+
installedSuccessfully = false;
256+
progress2.report({
257+
message: "Failed",
258+
increment: 100,
259+
});
260+
}
261+
}
262+
);
263+
264+
if (!installedSuccessfully) {
265+
progress.report({
266+
message: "Failed",
267+
increment: 100,
268+
});
269+
void window.showErrorMessage(
270+
"Failed to download and install ninja. \
271+
Make sure all requirements are met."
272+
);
273+
274+
return;
275+
} else {
276+
output.ninjaExecutable = joinPosix(
277+
buildNinjaPath(data.ninjaVersion),
278+
"ninja"
279+
);
280+
}
281+
break;
282+
case 1:
283+
output.ninjaExecutable = "ninja";
284+
break;
285+
case 3:
286+
// normalize path returned by the os selector to posix path for the settings json
287+
// and cross platform compatibility
288+
output.ninjaExecutable =
289+
process.platform === "win32"
290+
? joinPosix(...data.ninjaPath.split("\\"))
291+
: data.ninjaPath;
292+
break;
293+
294+
default:
295+
progress.report({
296+
message: "Failed",
297+
increment: 100,
298+
});
299+
void window.showErrorMessage("Unknown ninja selection.");
300+
301+
return;
302+
}
303+
304+
// Handle ninja install
217305
await window.withProgress(
218306
{
219307
location: ProgressLocation.Notification,
@@ -528,15 +616,10 @@ export async function setupZephyr(
528616

529617
const customPath = [
530618
dirname(output.cmakeExecutable.replaceAll("\\", "/")),
619+
dirname(output.ninjaExecutable.replaceAll("\\", "/")),
531620
joinPosix(homedir().replaceAll("\\", "/"), ".pico-sdk", "dtc", "bin"),
532621
joinPosix(homedir().replaceAll("\\", "/"), ".pico-sdk", "git", "cmd"),
533622
joinPosix(homedir().replaceAll("\\", "/"), ".pico-sdk", "gperf", "bin"),
534-
joinPosix(
535-
homedir().replaceAll("\\", "/"),
536-
".pico-sdk",
537-
"ninja",
538-
"v1.12.1"
539-
),
540623
joinPosix(
541624
homedir().replaceAll("\\", "/"),
542625
".pico-sdk",

src/webview/newZephyrProjectPanel.mts

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { homedir } from "os";
1515
import { join as joinPosix } from "path/posix";
1616
import Settings from "../settings.mjs";
1717
import Logger from "../logger.mjs";
18+
import { compare } from "../utils/semverUtil.mjs";
1819
import type { WebviewMessage } from "./newProjectPanel.mjs";
1920
import {
2021
getNonce,
@@ -28,7 +29,7 @@ import { PythonExtension } from "@vscode/python-extension";
2829
import { unknownErrorToString } from "../utils/errorHelper.mjs";
2930
import { buildZephyrWorkspacePath } from "../utils/download.mjs";
3031
import { setupZephyr, type ZephyrSetupOutputs } from "../utils/setupZephyr.mjs";
31-
import { getCmakeReleases } from "../utils/githubREST.mjs";
32+
import { getCmakeReleases, getNinjaReleases } from "../utils/githubREST.mjs";
3233

3334
enum BoardType {
3435
pico = "pico",
@@ -49,6 +50,9 @@ interface SubmitMessageValue {
4950
wifiFeature: boolean;
5051
sensorFeature: boolean;
5152
shellFeature: boolean;
53+
ninjaMode: number;
54+
ninjaPath: string;
55+
ninjaVersion: string;
5256
cmakeMode: number;
5357
cmakePath: string;
5458
cmakeVersion: string;
@@ -139,7 +143,8 @@ export class NewZephyrProjectPanel {
139143
// CMake, Ninja, Python, etc
140144
private static createSettingsJson(
141145
homePath: string,
142-
cmakePath: string
146+
cmakePath: string,
147+
ninjaPath: string
143148
): string {
144149
// Helper functions
145150
const getDirName = (s: string): string => dirname(joinPosix(s));
@@ -149,6 +154,11 @@ export class NewZephyrProjectPanel {
149154
);
150155
console.log(subbedCmakePath);
151156

157+
const subbedNinjaPath = getDirName(
158+
ninjaPath.replace(homePath, "${userHome}")
159+
);
160+
console.log(subbedNinjaPath);
161+
152162
const settingsJson = {
153163
/* eslint-disable @typescript-eslint/naming-convention */
154164
"cmake.options.statusBarVisibility": "hidden",
@@ -175,30 +185,35 @@ export class NewZephyrProjectPanel {
175185
Path:
176186
"${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1/bin;${env:USERPROFILE}/.pico-sdk/picotool/2.1.1/picotool;" +
177187
`${getDirName(cmakePath.replace(homePath, "${env:USERPROFILE}"))};` +
178-
"${env:USERPROFILE}/.pico-sdk/ninja/v1.12.1;${env:PATH}",
188+
`${getDirName(ninjaPath.replace(homePath, "${env:USERPROFILE}"))};` +
189+
"${env:PATH}",
179190
},
180191
"terminal.integrated.env.osx": {
181192
PICO_SDK_PATH: "${env:HOME}/.pico-sdk/sdk/2.1.1",
182193
PICO_TOOLCHAIN_PATH: "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1",
183194
PATH:
184195
"${env:HOME}/.pico-sdk/toolchain/14_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.1.1/picotool:" +
185196
`${getDirName(cmakePath.replace(homePath, "{env:HOME}"))}:` +
186-
"${env:HOME}/.pico-sdk/ninja/v1.12.1:${env:PATH}",
197+
`${getDirName(ninjaPath.replace(homePath, "{env:HOME}"))}:` +
198+
"${env:PATH}",
187199
},
188200
"terminal.integrated.env.linux": {
189201
PICO_SDK_PATH: "${env:HOME}/.pico-sdk/sdk/2.1.1",
190202
PICO_TOOLCHAIN_PATH: "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1",
191203
PATH:
192204
"${env:HOME}/.pico-sdk/toolchain/14_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.1.1/picotool:" +
193205
`${getDirName(cmakePath.replace(homePath, "{env:HOME}"))}:` +
194-
"${env:HOME}/.pico-sdk/ninja/v1.12.1:${env:PATH}",
206+
`${getDirName(ninjaPath.replace(homePath, "{env:HOME}"))}:` +
207+
"${env:PATH}",
195208
},
196209
"raspberry-pi-pico.cmakeAutoConfigure": true,
197210
"raspberry-pi-pico.useCmakeTools": false,
198211
"raspberry-pi-pico.cmakePath": `${getDirName(
199212
cmakePath.replace(homePath, "${HOME}")
200213
)};`,
201-
"raspberry-pi-pico.ninjaPath": "${HOME}/.pico-sdk/ninja/v1.12.1/ninja",
214+
"raspberry-pi-pico.ninjaPath": `${getDirName(
215+
ninjaPath.replace(homePath, "${HOME}")
216+
)};`,
202217
};
203218

204219
/* eslint-enable @typescript-eslint/naming-convention */
@@ -478,6 +493,9 @@ export class NewZephyrProjectPanel {
478493
cmakeMode: data.cmakeMode,
479494
cmakePath: data.cmakePath,
480495
cmakeVersion: data.cmakeVersion,
496+
ninjaMode: data.ninjaMode,
497+
ninjaPath: data.ninjaPath,
498+
ninjaVersion: data.ninjaVersion,
481499
});
482500

483501
if (zephyrSetupOutputs === null) {
@@ -581,7 +599,8 @@ export class NewZephyrProjectPanel {
581599
// Create settings JSON and write to new folder
582600
const settingsJson = NewZephyrProjectPanel.createSettingsJson(
583601
homeDirectory.replaceAll("\\", "/"),
584-
zephyrSetupOutputs?.cmakeExecutable || ""
602+
zephyrSetupOutputs?.cmakeExecutable || "",
603+
zephyrSetupOutputs?.ninjaExecutable || ""
585604
);
586605
await workspace.fs.writeFile(
587606
Uri.file(settingJsonFile),
@@ -693,6 +712,18 @@ export class NewZephyrProjectPanel {
693712
const knownEnvironments = environments?.known;
694713
const activeEnv = environments?.getActiveEnvironmentPath();
695714

715+
let ninjasHtml = "";
716+
const ninjaReleases = await getNinjaReleases();
717+
console.debug(ninjaReleases);
718+
const latestNinjaRelease = ninjaReleases[0];
719+
ninjaReleases
720+
.sort((a, b) => compare(b.replace("v", ""), a.replace("v", "")))
721+
.forEach(ninja => {
722+
ninjasHtml += `<option ${
723+
ninjasHtml.length === 0 ? "selected " : ""
724+
}value="${ninja}">${ninja}</option>`;
725+
});
726+
696727
let cmakesHtml = "";
697728
const cmakeReleases = await getCmakeReleases();
698729
console.debug(cmakeReleases);
@@ -708,6 +739,9 @@ export class NewZephyrProjectPanel {
708739
(await which("python3", { nothrow: true })) !== null ||
709740
(await which("python", { nothrow: true })) !== null;
710741

742+
const isNinjaSystemAvailable =
743+
(await which("ninja", { nothrow: true })) !== null;
744+
711745
const isCmakeSystemAvailable =
712746
(await which("cmake", { nothrow: true })) !== null;
713747

@@ -974,6 +1008,41 @@ export class NewZephyrProjectPanel {
9741008
</div>
9751009
</div>
9761010
1011+
<div class="col-span-2">
1012+
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Ninja Version:</label>
1013+
${
1014+
latestNinjaRelease !== undefined
1015+
? `<div class="flex items-center mb-2">
1016+
<input type="radio" id="ninja-radio-default-version" name="ninja-version-radio" value="0" class="mr-1 text-blue-500" checked="checked">
1017+
<label id="ninja-radio-latest-version" name=${latestNinjaRelease} for="ninja-radio-default-version" class="text-gray-900 dark:text-white">Default version</label>
1018+
</div>`
1019+
: ""
1020+
}
1021+
1022+
${
1023+
isNinjaSystemAvailable
1024+
? `<div class="flex items-center mb-2" >
1025+
<input type="radio" id="ninja-radio-system-version" name="ninja-version-radio" value="1" class="mr-1 text-blue-500">
1026+
<label for="ninja-radio-system-version" class="text-gray-900 dark:text-white">Use system version</label>
1027+
</div>`
1028+
: ""
1029+
}
1030+
1031+
<div class="flex items-center mb-2">
1032+
<input type="radio" id="ninja-radio-select-version" name="ninja-version-radio" value="2" class="mr-1 text-blue-500">
1033+
<label for="ninja-radio-select-version" class="text-gray-900 dark:text-white">Select version:</label>
1034+
<select id="sel-ninja" class="ml-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
1035+
${ninjasHtml}
1036+
</select>
1037+
</div>
1038+
1039+
<div class="flex items-center mb-2">
1040+
<input type="radio" id="ninja-radio-path-executable" name="ninja-version-radio" value="3" class="mr-1 text-blue-500">
1041+
<label for="ninja-radio-path-executable" class="text-gray-900 dark:text-white">Path to executable:</label>
1042+
<input type="file" id="ninja-path-executable" multiple="false" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 ms-2">
1043+
</div>
1044+
</div>
1045+
9771046
<div class="bottom-3 mt-8 mb-12 w-full flex justify-end">
9781047
<button id="btn-cancel" class="focus:outline-none bg-transparent ring-2 focus:ring-4 ring-red-400 dark:ring-red-700 font-medium rounded-lg text-lg px-4 py-2 mr-4 hover:bg-red-500 dark:hover:bg-red-700 focus:ring-red-600 dark:focus:ring-red-800">Cancel</button>
9791048
<button id="btn-create" class="focus:outline-none bg-transparent ring-2 focus:ring-4 ring-green-400 dark:ring-green-700 font-medium rounded-lg text-lg px-4 py-2 mr-2 hover:bg-green-500 dark:hover:bg-green-700 focus:ring-green-600 dark:focus:ring-green-800">

web/zephyr/main.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,70 @@ var submitted = false;
173173
"shell-features-cblist"
174174
).checked;
175175

176+
// Handle Ninja version
177+
// selected ninja version
178+
const ninjaVersionRadio = document.getElementsByName("ninja-version-radio");
179+
let ninjaMode = null;
180+
let ninjaPath = null;
181+
let ninjaVersion = null;
182+
for (let i = 0; i < ninjaVersionRadio.length; i++) {
183+
if (ninjaVersionRadio[i].checked) {
184+
ninjaMode = Number(ninjaVersionRadio[i].value);
185+
break;
186+
}
187+
}
188+
if (ninjaVersionRadio.length === 0) {
189+
// default to ninja mode 1 == System version
190+
ninjaMode = 1;
191+
}
192+
193+
// if ninja version is null or not a number, smaller than 0 or bigger than 3, set it to 0
194+
if (
195+
ninjaMode === null ||
196+
isNaN(ninjaMode) ||
197+
ninjaMode < 0 ||
198+
ninjaMode > 4
199+
) {
200+
ninjaMode = 0;
201+
console.debug("Invalid ninja version value: " + ninjaMode.toString());
202+
vscode.postMessage({
203+
command: CMD_ERROR,
204+
value: "Please select a valid ninja version.",
205+
});
206+
submitted = false;
207+
208+
return;
209+
}
210+
211+
if (ninjaMode === 0) {
212+
const ninjaLatestElement = document.getElementById(
213+
"ninja-radio-latest-version"
214+
);
215+
ninjaVersion = ninjaLatestElement.getAttribute("name");
216+
} else if (ninjaMode === 2) {
217+
ninjaVersion = document.getElementById("sel-ninja").value;
218+
} else if (ninjaMode == 3) {
219+
const files = document.getElementById("ninja-path-executable").files;
220+
221+
if (files.length === 1) {
222+
ninjaPath = files[0].name;
223+
} else {
224+
console.debug("Please select a valid ninja executable file");
225+
vscode.postMessage({
226+
command: CMD_ERROR,
227+
value: "Please select a valid ninja executable file.",
228+
});
229+
submitted = false;
230+
231+
return;
232+
}
233+
}
234+
235+
console.log(
236+
`Ninja Mode: ${ninjaMode}, path: ${ninjaPath}, version: ${ninjaVersion}`
237+
);
238+
239+
// Handle CMake Version
176240
const cmakeVersionRadio = document.getElementsByName("cmake-version-radio");
177241
let cmakeMode = null;
178242
let cmakePath = null;
@@ -253,6 +317,9 @@ var submitted = false;
253317
cmakeMode: Number(cmakeMode),
254318
cmakePath: cmakePath,
255319
cmakeVersion: cmakeVersion,
320+
ninjaMode: Number(ninjaMode),
321+
ninjaPath: ninjaPath,
322+
ninjaVersion: ninjaVersion,
256323
},
257324
});
258325
};

0 commit comments

Comments
 (0)