]> Git Repo - pico-vscode.git/blob - src/utils/globalEnvironmentUtil.mts
Add global env vars and compile button
[pico-vscode.git] / src / utils / globalEnvironmentUtil.mts
1 import { execSync } from "child_process";
2 import { randomBytes } from "crypto";
3 import { existsSync, appendFileSync, readFileSync, writeFileSync } from "fs";
4 import { homedir } from "os";
5 import { v4 as uuidv4 } from "uuid";
6 import Logger from "../logger.mjs";
7 import { dirname, join } from "path";
8 import { fileURLToPath } from "url";
9
10 const BASE62_ALPHABET =
11   "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
12
13 function base62Encode(uuid: string): string {
14   const uuidBytes = Buffer.from(uuid.replace(/-/g, ""), "hex");
15   let value = BigInt("0x" + uuidBytes.toString("hex"));
16   let encoded = "";
17
18   while (value > 0n) {
19     const remainder = Number(value % 62n);
20     encoded = BASE62_ALPHABET[remainder] + encoded;
21     value = value / 62n;
22   }
23
24   return encoded;
25 }
26
27 function getShellConfigFilePaths(): string[] {
28   const zshPofilePath = `${homedir()}/.zprofile`;
29   const bashProfilePath = `${homedir()}/.bash_profile`;
30   const profilePath = `${homedir()}/.profile`;
31
32   return [zshPofilePath, bashProfilePath, profilePath];
33 }
34
35 export function setGlobalEnvVar(variable: string, value: string): void {
36   deleteGlobalEnvVar(variable);
37   switch (process.platform) {
38     case "darwin":
39     case "linux": {
40       const profiles = getShellConfigFilePaths();
41
42       profiles.forEach(profile => {
43         if (existsSync(profile)) {
44           appendFileSync(profile, `\nexport ${variable}=${value}`, {
45             encoding: "utf8",
46           });
47         }
48       });
49       break;
50     }
51     case "win32": {
52       execSync(`setx ${variable} "${value}"`);
53       break;
54     }
55   }
56 }
57
58 export function getGlobalEnvVar(variable: string): string | undefined {
59   switch (process.platform) {
60     case "darwin":
61     case "linux": {
62       const profiles = getShellConfigFilePaths();
63
64       profiles.forEach(profile => {
65         const profileContent = readFileSync(profile, "utf8");
66         const regex = new RegExp(`export ${variable}=(.*)`);
67         const match = profileContent.match(regex);
68
69         if (match && match[1]) {
70           return match[1];
71         }
72       });
73
74       break;
75     }
76     case "win32": {
77       try {
78         const output = execSync(`echo %${variable}%`);
79
80         return output.toString().trim();
81       } catch (error) {
82         return undefined;
83       }
84     }
85   }
86
87   return undefined;
88 }
89
90 export function deleteGlobalEnvVar(variable: string): void {
91   switch (process.platform) {
92     case "darwin":
93     case "linux": {
94       const profiles = getShellConfigFilePaths();
95
96       profiles.forEach(profile => {
97         if (existsSync(profile)) {
98           execSync(
99             `sed -i${
100               process.platform === "darwin" ? " '' " : " "
101             }'/export ${variable}=*/d' "${profile}"`
102           );
103           clearEmptyLinesAtEnd(profile, false);
104         }
105       });
106
107       break;
108     }
109     case "win32": {
110       execSync(`setx ${variable} ""`);
111       break;
112     }
113   }
114 }
115
116 function getScriptsRoot(): string {
117   return join(dirname(fileURLToPath(import.meta.url)), "scripts");
118 }
119
120 export function deleteGlobalEnvVars(startingWith: string): void {
121   switch (process.platform) {
122     case "darwin":
123     case "linux": {
124       const profiles = getShellConfigFilePaths();
125
126       profiles.forEach(profile => {
127         if (existsSync(profile)) {
128           execSync(
129             `sed -i${
130               process.platform === "darwin" ? " '' " : " "
131             }'/export ${startingWith}.*=/d' "${profile}"`
132           );
133           clearEmptyLinesAtEnd(profile, true);
134         }
135       });
136
137       break;
138     }
139     case "win32": {
140       execSync(
141         "powershell.exe -ExecutionPolicy Bypass " +
142           `-File ${getScriptsRoot()}\\deleteAllGlobalEnvVars.ps1 ` +
143           `-EnvVariablePrefix "${startingWith}"`
144       );
145       break;
146     }
147   }
148 }
149
150 export function clearEmptyLinesAtEnd(
151   filePath: string,
152   appendNl: boolean
153 ): void {
154   try {
155     // Read the file
156     const fileContent = readFileSync(filePath, "utf-8");
157
158     // Split the file content into lines
159     const lines = fileContent.split("\n");
160
161     // Remove empty lines from the end until one empty line remains
162     while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
163       lines.pop();
164     }
165
166     // Join the lines back into a single string
167     const updatedContent = lines.join("\n") + (appendNl ? "\n\n" : "");
168
169     // Write the updated content back to the file
170     writeFileSync(filePath, updatedContent, "utf-8");
171   } catch (error) {
172     Logger.log("An error occurred while cleaning the profile.");
173   }
174 }
175
176 export function generateNewEnvVarSuffix(): string {
177   return base62Encode(uuidv4({ random: _v4Bytes() }));
178 }
179
180 /**
181  * Generate random bytes for uuidv4 as crypto.getRandomValues is not supported in vscode extensions
182  *
183  * @returns 16 random bytes
184  */
185 function _v4Bytes(): Uint8Array {
186   return new Uint8Array(randomBytes(16).buffer);
187 }
This page took 0.035794 seconds and 4 git commands to generate.