mirror of
https://git.bits.team/Bits/mod-manager.git
synced 2025-06-29 16:49:43 -04:00
Changed Minecraft Version tracking to manual input rather than auto-detecting
This commit is contained in:
@ -6,8 +6,8 @@ export default class InitCommand implements Subcommand {
|
||||
registerCommand(program: Command) {
|
||||
program.command("init")
|
||||
.description("Initialises mod manager")
|
||||
.action(() => {
|
||||
Initialiser.initialise();
|
||||
.action(async () => {
|
||||
await Initialiser.initialise();
|
||||
});
|
||||
}
|
||||
}
|
7
src/errors/minecraft_version_error.ts
Normal file
7
src/errors/minecraft_version_error.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export default class MinecraftVersionError extends Error {
|
||||
constructor(message: string | undefined) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
}
|
@ -2,13 +2,13 @@ import path from "path";
|
||||
import * as https from "https";
|
||||
import {createWriteStream} from "fs";
|
||||
import DownloadError from "../errors/download_error.js";
|
||||
import Mods from "../mods/mods.js";
|
||||
import ModManager from "../mod-manager.js";
|
||||
|
||||
|
||||
export default class FileDownloader {
|
||||
static downloadMod(task: DownloadTask): void {
|
||||
https.get(task.url, res => {
|
||||
const filePath = path.join(Mods.MODS_FOLDER_PATH, task.fileName);
|
||||
const filePath = path.join(ModManager.FilePaths.MODS_FOLDER_PATH, task.fileName);
|
||||
const writeStream = createWriteStream(filePath);
|
||||
res.pipe(writeStream);
|
||||
writeStream.on("finish", () => writeStream.close());
|
||||
|
@ -15,7 +15,6 @@ import {readFileSync, unlinkSync} from "fs";
|
||||
|
||||
export default class ModManager {
|
||||
public static logger: Logger | null = null;
|
||||
private static readonly LOG_FILE: string = path.join(Initialiser.getModManagerFolderPath(), "logs", `${new Date().valueOf()}.log.json`);
|
||||
|
||||
private static program: Command = new Command();
|
||||
|
||||
@ -27,6 +26,15 @@ export default class ModManager {
|
||||
new EssentialCommand()
|
||||
];
|
||||
|
||||
static FilePaths = class {
|
||||
public static readonly MOD_MANAGER_FOLDER_PATH = path.join(".mod-manager");
|
||||
public static readonly LOGS_FOLDER = path.join(this.MOD_MANAGER_FOLDER_PATH, "logs");
|
||||
public static readonly LOG_FILE: string = path.join(this.LOGS_FOLDER, `${new Date().valueOf()}.log.json`);
|
||||
public static readonly MOD_FILE_PATH = path.join(this.MOD_MANAGER_FOLDER_PATH, "mods.json");
|
||||
public static readonly VERSION_FILE_PATH = path.join(this.MOD_MANAGER_FOLDER_PATH, "version")
|
||||
public static readonly MODS_FOLDER_PATH = path.join("mods")
|
||||
}
|
||||
|
||||
static init() {
|
||||
if (Initialiser.isInitialised()) {
|
||||
this.logger = ModManager.createLogger();
|
||||
@ -58,7 +66,7 @@ export default class ModManager {
|
||||
hostname: undefined}
|
||||
},
|
||||
pino.destination({
|
||||
dest: this.LOG_FILE,
|
||||
dest: ModManager.FilePaths.LOG_FILE,
|
||||
sync: true
|
||||
})
|
||||
);
|
||||
@ -71,8 +79,8 @@ export default class ModManager {
|
||||
// If no errors are logged, cleanup the log file when the process exits
|
||||
process.on("exit", () => {
|
||||
// If file is only whitespace, i.e. blank
|
||||
if (!readFileSync(this.LOG_FILE, "utf-8")?.trim().length) {
|
||||
unlinkSync(this.LOG_FILE)
|
||||
if (!readFileSync(ModManager.FilePaths.LOG_FILE, "utf-8")?.trim().length) {
|
||||
unlinkSync(ModManager.FilePaths.LOG_FILE)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
import path from "path";
|
||||
import Initialiser from "../util/initialiser.js";
|
||||
import PrintUtils from "../util/print_utils.js";
|
||||
import ModrinthSource from "./sources/modrinth_source.js";
|
||||
import ModSource from "./sources/mod_source.js";
|
||||
import ModNotFoundError from "../errors/mod_not_found_error.js";
|
||||
import {readFileSync, unlinkSync, writeFileSync} from "fs";
|
||||
import Util from "../util/util.js";
|
||||
import ModManager from "../mod-manager.js";
|
||||
|
||||
|
||||
export default class Mods {
|
||||
public static readonly MOD_FILE = "mods.json";
|
||||
public static readonly MODS_FOLDER_PATH: string = path.join("mods");
|
||||
private static readonly MOD_SOURCES: Array<ModSource> = [
|
||||
new ModrinthSource()
|
||||
];
|
||||
@ -64,10 +62,6 @@ export default class Mods {
|
||||
}
|
||||
}
|
||||
|
||||
public static getModFilePath(): string {
|
||||
return path.join(Initialiser.getModManagerFolderPath(), this.MOD_FILE);
|
||||
}
|
||||
|
||||
private static trackMod(mod: Mod): void {
|
||||
// Read current file
|
||||
const mods = this.getTrackedMods();
|
||||
@ -80,12 +74,12 @@ export default class Mods {
|
||||
}
|
||||
|
||||
public static getTrackedMods(): Array<Mod> {
|
||||
const file = readFileSync(this.getModFilePath(), "utf-8");
|
||||
const file = readFileSync(ModManager.FilePaths.MOD_FILE_PATH, "utf-8");
|
||||
return JSON.parse(file);
|
||||
}
|
||||
|
||||
public static writeFile(mods: Array<Mod>): void {
|
||||
writeFileSync(this.getModFilePath(), JSON.stringify(mods, null, 4));
|
||||
writeFileSync(ModManager.FilePaths.MOD_FILE_PATH, JSON.stringify(mods, null, 4));
|
||||
}
|
||||
|
||||
private static isModInstalled(id: string): boolean {
|
||||
@ -103,7 +97,7 @@ export default class Mods {
|
||||
let mods: Array<Mod> = this.getTrackedMods();
|
||||
|
||||
// Remove mod from list and uninstall it
|
||||
unlinkSync(path.join(this.MODS_FOLDER_PATH, modToUninstall.fileName));
|
||||
unlinkSync(path.join(ModManager.FilePaths.MOD_FILE_PATH, modToUninstall.fileName));
|
||||
mods = mods.filter(item => !Mods.areModsEqual(item, modToUninstall));
|
||||
this.writeFile(mods);
|
||||
spinner.succeed(`${modToUninstall.name} successfully uninstalled!`)
|
||||
|
@ -1,18 +1,21 @@
|
||||
import {existsSync, mkdirSync, writeFileSync} from "fs";
|
||||
import path from "path";
|
||||
import Mods from "../mods/mods.js";
|
||||
import PrintUtils from "./print_utils.js";
|
||||
import ModManager from "../mod-manager.js";
|
||||
import inquirer from "inquirer";
|
||||
import MinecraftUtils from "./minecraft_utils.js";
|
||||
import MinecraftVersionError from "../errors/minecraft_version_error.js";
|
||||
|
||||
export default class Initialiser {
|
||||
private static readonly MOD_MANAGER_FOLDER = ".mod-manager"
|
||||
|
||||
public static initialise(): void {
|
||||
public static async initialise(): Promise<void> {
|
||||
if (!this.isInitialised()) {
|
||||
if (this.isDirFabricServer()) {
|
||||
const success: boolean = this.setupFolderStructure();
|
||||
|
||||
if (success) {
|
||||
const version = await this.getMinecraftVersionFromInput();
|
||||
await MinecraftUtils.updateCurrentMinecraftVersion(version)
|
||||
|
||||
PrintUtils.success("Sucessfully initialised Mod Manager!");
|
||||
|
||||
// Initialise a logger when Mod Manager is initialised
|
||||
@ -32,11 +35,7 @@ export default class Initialiser {
|
||||
}
|
||||
|
||||
public static isInitialised(): boolean {
|
||||
return existsSync(this.getModManagerFolderPath());
|
||||
}
|
||||
|
||||
public static getModManagerFolderPath(): string {
|
||||
return path.join(this.MOD_MANAGER_FOLDER);
|
||||
return existsSync(ModManager.FilePaths.MOD_MANAGER_FOLDER_PATH);
|
||||
}
|
||||
|
||||
private static isDirFabricServer(): boolean {
|
||||
@ -47,14 +46,40 @@ export default class Initialiser {
|
||||
}
|
||||
|
||||
private static setupFolderStructure(): boolean {
|
||||
if (!existsSync(this.getModManagerFolderPath())) {
|
||||
mkdirSync(this.getModManagerFolderPath());
|
||||
writeFileSync(Mods.getModFilePath(), "[]");
|
||||
mkdirSync(path.join(this.getModManagerFolderPath(), "logs"))
|
||||
if (!existsSync(ModManager.FilePaths.MOD_MANAGER_FOLDER_PATH)) {
|
||||
mkdirSync(ModManager.FilePaths.MOD_MANAGER_FOLDER_PATH);
|
||||
writeFileSync(ModManager.FilePaths.MOD_FILE_PATH, "[]");
|
||||
mkdirSync(ModManager.FilePaths.LOGS_FOLDER)
|
||||
writeFileSync(ModManager.FilePaths.VERSION_FILE_PATH, "")
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static async getMinecraftVersionFromInput() {
|
||||
let isVersionValid = false;
|
||||
|
||||
let version: string | undefined = undefined;
|
||||
while (!isVersionValid) {
|
||||
const answer = await inquirer.prompt([{
|
||||
type: "input",
|
||||
name: "minecraft_version",
|
||||
message: "What version of Minecraft is the server running?"
|
||||
}])
|
||||
version = answer.minecraft_version;
|
||||
|
||||
if (await MinecraftUtils.isValidVersion(version)) {
|
||||
isVersionValid = true;
|
||||
} else {
|
||||
PrintUtils.error(`${version} is not a valid Minecraft version for a Fabric server. Please try again`);
|
||||
}
|
||||
}
|
||||
|
||||
if (version == undefined) {
|
||||
throw new MinecraftVersionError("Escaped version input without a valid version")
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
@ -1,14 +1,19 @@
|
||||
import {readdirSync} from "fs";
|
||||
import path from "path";
|
||||
import {readFileSync, writeFileSync} from "fs";
|
||||
import axios from "axios";
|
||||
import ModManager from "../mod-manager.js";
|
||||
import MinecraftVersionError from "../errors/minecraft_version_error.js";
|
||||
|
||||
export default class MinecraftUtils {
|
||||
static async getCurrentMinecraftVersion(): Promise<string> {
|
||||
// Get installed versions as strings
|
||||
const installedVersions: Array<string> = readdirSync(this.getVersionsFolderPath(), {withFileTypes: true})
|
||||
.filter(entry => entry.isDirectory())
|
||||
.map(entry => entry.name);
|
||||
return readFileSync(ModManager.FilePaths.VERSION_FILE_PATH, "utf-8");
|
||||
}
|
||||
|
||||
static async isValidVersion(version: any) {
|
||||
const allMinecraftVersions = await this.getAllMinecraftVersions();
|
||||
return allMinecraftVersions.includes(version);
|
||||
}
|
||||
|
||||
static async getAllMinecraftVersions(): Promise<Array<string>> {
|
||||
// Get a list of Minecraft Versions
|
||||
const response = await axios.get("https://meta.fabricmc.net/v2/versions/game");
|
||||
const data = await response.data;
|
||||
@ -18,27 +23,16 @@ export default class MinecraftUtils {
|
||||
minecraftVersions.push(ele.version);
|
||||
}
|
||||
|
||||
// Find the latest version that is currently installed
|
||||
let index = Number.MAX_VALUE;
|
||||
for (let version of installedVersions) {
|
||||
let currentIndex = minecraftVersions.indexOf(version);
|
||||
|
||||
// If this version, is newer than the previous newest, save it's index
|
||||
if (currentIndex < index) {
|
||||
index = currentIndex;
|
||||
}
|
||||
}
|
||||
|
||||
const latestVersion = minecraftVersions[index];
|
||||
if (latestVersion == undefined) {
|
||||
throw new Error("There are no Minecraft versions available in this server. Is this a valid server installation?");
|
||||
}
|
||||
|
||||
return latestVersion;
|
||||
return minecraftVersions;
|
||||
}
|
||||
|
||||
static getVersionsFolderPath(): string {
|
||||
return path.join("versions")
|
||||
static async updateCurrentMinecraftVersion(version: string) {
|
||||
if (await MinecraftUtils.isValidVersion(version)) {
|
||||
writeFileSync(ModManager.FilePaths.VERSION_FILE_PATH, version);
|
||||
} else {
|
||||
throw new MinecraftVersionError(`Attempted to update version file with invalid version: ${version}`)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user