]> Git Repo - pico-vscode.git/blob - src/utils/toolchainUtil.mts
Merge branch 'main' into main
[pico-vscode.git] / src / utils / toolchainUtil.mts
1 import { get } from "https";
2 import * as ini from "ini";
3 import { homedir } from "os";
4 import { join } from "path";
5 import Logger from "../logger.mjs";
6 import { readdirSync, statSync, readFileSync } from "fs";
7 import { getDataRoot } from "./downloadHelpers.mjs";
8 import {
9   isInternetConnected,
10   CURRENT_DATA_VERSION,
11 } from "./downloadHelpers.mjs";
12
13 const iniUrl =
14   "https://raspberrypi.github.io/pico-vscode/" +
15   `${CURRENT_DATA_VERSION}/supportedToolchains.ini`;
16 const supportedDistros = [
17   "win32_x64",
18   "darwin_arm64",
19   "darwin_x64",
20   "linux_x64",
21   "linux_arm64",
22 ];
23
24 export interface SupportedToolchainVersion {
25   version: string;
26   /// { [key in (typeof supportedDistros)[number]]?: string }
27   downloadUrls: { [key: string]: string };
28 }
29
30 export interface InstalledToolchain {
31   version: string;
32   path: string;
33 }
34
35 function parseIni(data: string): SupportedToolchainVersion[] {
36   const parsedIni: { [key: string]: { [key: string]: string } } =
37     ini.parse(data);
38   const supportedToolchains: SupportedToolchainVersion[] = [];
39
40   // Iterate through sections
41   for (const version in parsedIni) {
42     const section: { [key: string]: string } = parsedIni[version];
43
44     const downloadUrls: {
45       [key in (typeof supportedDistros)[number]]: string;
46     } = {};
47
48     // Create an object with supported distros and their URLs
49     for (const distro of supportedDistros) {
50       if (section[distro]) {
51         downloadUrls[distro] = section[distro];
52       }
53     }
54
55     // Add the version and downloadUrls to the result array
56     supportedToolchains.push({ version, downloadUrls });
57   }
58
59   return supportedToolchains;
60 }
61
62 export async function getSupportedToolchains(): Promise<
63   SupportedToolchainVersion[]
64 > {
65   try {
66     if (!(await isInternetConnected())) {
67       throw new Error(
68         "Error while downloading supported toolchains list. " +
69           "No internet connection"
70       );
71     }
72     const result = await new Promise<SupportedToolchainVersion[]>(
73       (resolve, reject) => {
74         // Download the INI file
75         get(iniUrl, response => {
76           if (response.statusCode !== 200) {
77             reject(
78               new Error(
79                 "Error while downloading supported toolchains list. " +
80                   `Status code: ${response.statusCode}`
81               )
82             );
83           }
84           let data = "";
85
86           // Append data as it arrives
87           response.on("data", chunk => {
88             data += chunk;
89           });
90
91           // Parse the INI data when the download is complete
92           response.on("end", () => {
93             // Resolve with the array of SupportedToolchainVersion
94             resolve(parseIni(data));
95           });
96
97           // Handle errors
98           response.on("error", error => {
99             reject(error);
100           });
101         });
102       }
103     );
104
105     return result;
106   } catch (error) {
107     Logger.log(
108       error instanceof Error
109         ? error.message
110         : typeof error === "string"
111         ? error
112         : "Unknown error"
113     );
114
115     try {
116       // try to load local supported toolchains list
117       const supportedToolchains = parseIni(
118         readFileSync(join(getDataRoot(), "supportedToolchains.ini")).toString(
119           "utf-8"
120         )
121       );
122
123       return supportedToolchains;
124     } catch {
125       Logger.log("Error while loading local supported toolchains list.");
126
127       return [];
128     }
129   }
130 }
131
132 export function detectInstalledToolchains(): InstalledToolchain[] {
133   // detect installed toolchains by foldernames in $HOME/.pico-sdk/toolchain/<version>
134   const homeDirectory = homedir();
135   const toolchainDirectory = join(homeDirectory, ".pico-sdk", "toolchain");
136
137   try {
138     // check if pico-sdk directory exists
139     if (!statSync(toolchainDirectory).isDirectory()) {
140       Logger.log("No installed toolchain found.");
141
142       return [];
143     }
144   } catch {
145     Logger.log("No installed toolchain found.");
146
147     return [];
148   }
149
150   // scan foldernames in picoSDKDirectory/toolchain
151   const installedToolchains: InstalledToolchain[] = [];
152   try {
153     const versions = readdirSync(toolchainDirectory);
154     // TODO: better regex or alternative
155     for (const version of versions.filter(
156       version =>
157         /^\d+_\d+_(?:\w+(?:-|\.))?(\d+)$/.test(version) &&
158         statSync(`${toolchainDirectory}/${version}`).isDirectory()
159     )) {
160       const toolchainPath = join(toolchainDirectory, version);
161
162       installedToolchains.push({ version, path: toolchainPath });
163     }
164   } catch {
165     Logger.log("Error while detecting installed Toolchains.");
166   }
167
168   return installedToolchains;
169 }
This page took 0.031699 seconds and 4 git commands to generate.