]> Git Repo - pico-vscode.git/blob - src/utils/examplesUtil.mts
Add rp2350 support
[pico-vscode.git] / src / utils / examplesUtil.mts
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";
10 import {
11   isInternetConnected, CURRENT_DATA_VERSION, getDataRoot
12 } from "./downloadHelpers.mjs";
13
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`;
19
20 export interface Example {
21   path: string;
22   name: string;
23   searchKey: string;
24 }
25
26 interface ExamplesFile {
27   [key: string]: {
28     path: string;
29     name: string;
30   };
31 }
32
33 function buildExamplesPath(): string {
34   return joinPosix(homedir().replaceAll("\\", "/"), ".pico-sdk", "examples");
35 }
36
37 function parseExamplesJson(data: string): Example[] {
38   try {
39     const examples = JSON.parse(data.toString()) as ExamplesFile;
40
41     return Object.keys(examples).map(key => ({
42       path: examples[key].path,
43       name: examples[key].name,
44       searchKey: key,
45     }));
46   } catch {
47     Logger.log("Failed to parse examples.json");
48
49     return [];
50   }
51 }
52
53 export async function loadExamples(): Promise<Example[]> {
54   try {
55     if (!(await isInternetConnected())) {
56       throw new Error(
57         "Error while downloading examples list. " +
58           "No internet connection"
59       );
60     }
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) {
65           reject(
66             new Error(
67               "Error while downloading examples list. " +
68                 `Status code: ${response.statusCode}`
69             )
70           );
71         }
72         let data = "";
73
74         // Append data as it arrives
75         response.on("data", chunk => {
76           data += chunk;
77         });
78
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));
83         });
84
85         // Handle errors
86         response.on("error", error => {
87           reject(error);
88         });
89       });
90     });
91
92     // TODO: Logger.debug
93     Logger.log(`Successfully downloaded examples list from the internet.`);
94
95     return result;
96   } catch (error) {
97     Logger.log(error instanceof Error ? error.message : (error as string));
98
99     try {
100       const examplesFile = readFileSync(
101         joinPosix(getDataRoot(), "examples.json")
102       );
103
104       return parseExamplesJson(examplesFile.toString("utf-8"));
105     } catch (e) {
106       Logger.log("Failed to load examples.json");
107
108       return [];
109     }
110   }
111 }
112
113 export async function setupExample(
114   example: Example,
115   targetPath: string
116 ): Promise<boolean> {
117   const examplesRepoPath = buildExamplesPath();
118   const absoluteExamplePath = joinPosix(examplesRepoPath, example.path);
119
120   const settings = Settings.getInstance();
121   if (settings === undefined) {
122     Logger.log("Error: Settings not initialized.");
123
124     return false;
125   }
126
127   // TODO: this does take about 2s - may be reduced
128   const requirementsCheck = await checkForInstallationRequirements(
129     settings
130   );
131   if (!requirementsCheck) {
132     return false;
133   }
134
135   const gitPath = await getGit(settings);
136
137   if (!existsSync(examplesRepoPath)) {
138     const result = await sparseCloneRepository(
139       EXAMPLES_REPOSITORY_URL,
140       "master",
141       examplesRepoPath,
142       gitPath
143     );
144
145     if (!result) {
146       return result;
147     }
148   }
149
150   Logger.log(`Spare-checkout selected example: ${example.name}`);
151   const result = await sparseCheckout(
152     examplesRepoPath,
153     example.path,
154     gitPath
155   );
156   if (!result) {
157     return result;
158   }
159
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), {
163     recursive: true,
164   });
165   Logger.log("Done copying example.");
166
167   return result;
168 }
This page took 0.048171 seconds and 4 git commands to generate.