1 import { join as joinPosix } from "path/posix";
2 import Logger from "../logger.mjs";
3 import { existsSync, readFileSync } from "fs";
4 import { homedir } from "os";
5 import { getGit, sparseCheckout, sparseCloneRepository } from "./gitUtil.mjs";
6 import Settings from "../settings.mjs";
7 import { checkForInstallationRequirements } from "./requirementsUtil.mjs";
8 import { cp } from "fs/promises";
9 import { get } from "https";
11 isInternetConnected, CURRENT_DATA_VERSION, getDataRoot
12 } from "./downloadHelpers.mjs";
14 const EXAMPLES_REPOSITORY_URL =
15 "https://github.com/raspberrypi/pico-examples.git";
16 const EXAMPLES_JSON_URL =
17 "https://raspberrypi.github.io/pico-vscode/" +
18 `${CURRENT_DATA_VERSION}/examples.json`;
20 export interface Example {
26 interface ExamplesFile {
33 function buildExamplesPath(): string {
34 return joinPosix(homedir().replaceAll("\\", "/"), ".pico-sdk", "examples");
37 function parseExamplesJson(data: string): Example[] {
39 const examples = JSON.parse(data.toString()) as ExamplesFile;
41 return Object.keys(examples).map(key => ({
42 path: examples[key].path,
43 name: examples[key].name,
47 Logger.log("Failed to parse examples.json");
53 export async function loadExamples(): Promise<Example[]> {
55 if (!(await isInternetConnected())) {
57 "Error while downloading examples list. " +
58 "No internet connection"
61 const result = await new Promise<Example[]>((resolve, reject) => {
62 // Download the INI file
63 get(EXAMPLES_JSON_URL, response => {
64 if (response.statusCode !== 200) {
67 "Error while downloading examples list. " +
68 `Status code: ${response.statusCode}`
74 // Append data as it arrives
75 response.on("data", chunk => {
79 // Parse the INI data when the download is complete
80 response.on("end", () => {
81 // Resolve with the array of SupportedToolchainVersion
82 resolve(parseExamplesJson(data));
86 response.on("error", error => {
93 Logger.log(`Successfully downloaded examples list from the internet.`);
97 Logger.log(error instanceof Error ? error.message : (error as string));
100 const examplesFile = readFileSync(
101 joinPosix(getDataRoot(), "examples.json")
104 return parseExamplesJson(examplesFile.toString("utf-8"));
106 Logger.log("Failed to load examples.json");
113 export async function setupExample(
116 ): Promise<boolean> {
117 const examplesRepoPath = buildExamplesPath();
118 const absoluteExamplePath = joinPosix(examplesRepoPath, example.path);
120 const settings = Settings.getInstance();
121 if (settings === undefined) {
122 Logger.log("Error: Settings not initialized.");
127 // TODO: this does take about 2s - may be reduced
128 const requirementsCheck = await checkForInstallationRequirements(
131 if (!requirementsCheck) {
135 const gitPath = await getGit(settings);
137 if (!existsSync(examplesRepoPath)) {
138 const result = await sparseCloneRepository(
139 EXAMPLES_REPOSITORY_URL,
150 Logger.log(`Spare-checkout selected example: ${example.name}`);
151 const result = await sparseCheckout(
160 Logger.log(`Copying example from ${absoluteExamplePath} to ${targetPath}`);
161 // TODO: use example.name or example.search key for project folder name?
162 await cp(absoluteExamplePath, joinPosix(targetPath, example.searchKey), {
165 Logger.log("Done copying example.");