1 import { readdirSync, renameSync, rmdirSync, statSync } from "fs";
2 import { dirname, join } from "path";
3 import { join as joinPosix } from "path/posix";
4 import Logger from "../logger.mjs";
5 import { exec } from "child_process";
6 import AdmZip from "adm-zip";
7 import { request } from "https";
8 import { fileURLToPath } from "url";
10 export const CURRENT_DATA_VERSION = "0.15.0";
12 export function getDataRoot(): string {
14 dirname(fileURLToPath(import.meta.url)).replaceAll("\\", "/"),
21 export function tryUnzipFiles(
23 targetDirectory: string
26 const zip = new AdmZip(zipFilePath);
27 const zipEntries = zip.getEntries();
28 zipEntries.forEach(function (zipEntry) {
29 if (!zipEntry.isDirectory) {
31 zip.extractEntryTo(zipEntry, targetDirectory, true, true, true);
34 `Error extracting archive file: ${
35 error instanceof Error ? error.message : (error as string)
46 export function unzipFile(
48 targetDirectory: string,
49 enforceSuccess: boolean = false
53 const zip = new AdmZip(zipFilePath);
54 zip.extractAllTo(targetDirectory, true, true);
56 tryUnzipFiles(zipFilePath, targetDirectory);
60 const targetDirContents = readdirSync(targetDirectory);
62 targetDirContents.length === 1
63 ? join(targetDirectory, targetDirContents[0])
66 targetDirContents.length === 1 &&
67 statSync(subfolderPath).isDirectory()
69 // Move all files and folders from the subfolder to targetDirectory
70 readdirSync(subfolderPath).forEach(item => {
71 const itemPath = join(subfolderPath, item);
72 const newItemPath = join(targetDirectory, item);
74 // Use fs.renameSync to move the item
75 renameSync(itemPath, newItemPath);
78 // Remove the empty subfolder
79 rmdirSync(subfolderPath);
85 `Error extracting archive file: ${
86 error instanceof Error ? error.message : (error as string)
95 * Extracts a .xz file using the 'tar' command.
97 * Also supports tar.gz files.
99 * Linux and macOS only.
102 * @param targetDirectory
105 export async function unxzFile(
107 targetDirectory: string
108 ): Promise<boolean> {
109 if (process.platform === "win32") {
113 return new Promise<boolean>(resolve => {
115 // Construct the command to extract the .xz file using the 'tar' command
116 // -J option is redundant in modern versions of tar, but it's still good for compatibility
117 const command = `tar -x${
118 xzFilePath.endsWith(".xz") ? "J" : "z"
119 }f "${xzFilePath}" -C "${targetDirectory}"`;
121 // Execute the 'tar' command in the shell
122 exec(command, error => {
124 Logger.log(`Error extracting archive file: ${error?.message}`);
127 const targetDirContents = readdirSync(targetDirectory);
128 const subfolderPath =
129 targetDirContents.length === 1
130 ? join(targetDirectory, targetDirContents[0])
133 targetDirContents.length === 1 &&
134 statSync(subfolderPath).isDirectory()
136 // Move all files and folders from the subfolder to targetDirectory
137 readdirSync(subfolderPath).forEach(item => {
138 const itemPath = join(subfolderPath, item);
139 const newItemPath = join(targetDirectory, item);
141 // Use fs.renameSync to move the item
142 renameSync(itemPath, newItemPath);
145 // Remove the empty subfolder
146 rmdirSync(subfolderPath);
149 Logger.log(`Extracted archive file: ${xzFilePath}`);
160 * Checks if the internet connection is available (at least to pages.github.com).
162 * @returns True if the internet connection is available, false otherwise.
164 export async function isInternetConnected(): Promise<boolean> {
165 return new Promise<boolean>(resolve => {
167 host: "pages.github.com",
172 // eslint-disable-next-line @typescript-eslint/naming-convention
173 Host: "pages.github.com",
177 const req = request(options, res => {
178 resolve(res.statusCode === 200);
181 req.on("error", () => {