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";
10 const BASE62_ALPHABET =
11 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
13 function base62Encode(uuid: string): string {
14 const uuidBytes = Buffer.from(uuid.replace(/-/g, ""), "hex");
15 let value = BigInt("0x" + uuidBytes.toString("hex"));
19 const remainder = Number(value % 62n);
20 encoded = BASE62_ALPHABET[remainder] + encoded;
27 function getShellConfigFilePaths(): string[] {
28 const zshPofilePath = `${homedir()}/.zprofile`;
29 const bashProfilePath = `${homedir()}/.bash_profile`;
30 const profilePath = `${homedir()}/.profile`;
32 return [zshPofilePath, bashProfilePath, profilePath];
35 export function setGlobalEnvVar(variable: string, value: string): void {
36 deleteGlobalEnvVar(variable);
37 switch (process.platform) {
40 const profiles = getShellConfigFilePaths();
42 profiles.forEach(profile => {
43 if (existsSync(profile)) {
44 appendFileSync(profile, `\nexport ${variable}=${value}`, {
52 execSync(`setx ${variable} "${value}"`);
58 export function getGlobalEnvVar(variable: string): string | undefined {
59 switch (process.platform) {
62 const profiles = getShellConfigFilePaths();
64 profiles.forEach(profile => {
65 const profileContent = readFileSync(profile, "utf8");
66 const regex = new RegExp(`export ${variable}=(.*)`);
67 const match = profileContent.match(regex);
69 if (match && match[1]) {
78 const output = execSync(`echo %${variable}%`);
80 return output.toString().trim();
90 export function deleteGlobalEnvVar(variable: string): void {
91 switch (process.platform) {
94 const profiles = getShellConfigFilePaths();
96 profiles.forEach(profile => {
97 if (existsSync(profile)) {
100 process.platform === "darwin" ? " '' " : " "
101 }'/export ${variable}=*/d' "${profile}"`
103 clearEmptyLinesAtEnd(profile, false);
110 execSync(`setx ${variable} ""`);
116 function getScriptsRoot(): string {
117 return join(dirname(fileURLToPath(import.meta.url)), "scripts");
120 export function deleteGlobalEnvVars(startingWith: string): void {
121 switch (process.platform) {
124 const profiles = getShellConfigFilePaths();
126 profiles.forEach(profile => {
127 if (existsSync(profile)) {
130 process.platform === "darwin" ? " '' " : " "
131 }'/export ${startingWith}.*=/d' "${profile}"`
133 clearEmptyLinesAtEnd(profile, true);
141 "powershell.exe -ExecutionPolicy Bypass " +
142 `-File ${getScriptsRoot()}\\deleteAllGlobalEnvVars.ps1 ` +
143 `-EnvVariablePrefix "${startingWith}"`
150 export function clearEmptyLinesAtEnd(
156 const fileContent = readFileSync(filePath, "utf-8");
158 // Split the file content into lines
159 const lines = fileContent.split("\n");
161 // Remove empty lines from the end until one empty line remains
162 while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
166 // Join the lines back into a single string
167 const updatedContent = lines.join("\n") + (appendNl ? "\n\n" : "");
169 // Write the updated content back to the file
170 writeFileSync(filePath, updatedContent, "utf-8");
172 Logger.log("An error occurred while cleaning the profile.");
176 export function generateNewEnvVarSuffix(): string {
177 return base62Encode(uuidv4({ random: _v4Bytes() }));
181 * Generate random bytes for uuidv4 as crypto.getRandomValues is not supported in vscode extensions
183 * @returns 16 random bytes
185 function _v4Bytes(): Uint8Array {
186 return new Uint8Array(randomBytes(16).buffer);