diff --git a/src/commands/install_command.ts b/src/commands/install_command.ts index fb18737..708f436 100644 --- a/src/commands/install_command.ts +++ b/src/commands/install_command.ts @@ -9,10 +9,11 @@ export default class InstallCommand implements Subcommand { .description("Installs the provided mods") .argument("", "The mods to install") .option("-e, --essential", "Marks these mods as essential", false) - .action(function () { + .option("-f, --force", "Automatically confirms the confirmation prompt", false) + .action((mods, options) => { ModManager.execute(async () => { - for (const mod of this.args) { - await Mods.install(mod, this.opts().essential); + for (const mod of mods) { + await Mods.install(mod, options.essential, options.force); } }) }); diff --git a/src/mods/mods.ts b/src/mods/mods.ts index c70a2f8..d065579 100644 --- a/src/mods/mods.ts +++ b/src/mods/mods.ts @@ -7,7 +7,6 @@ import Util from "../util/util.js"; import ModManager from "../mod-manager.js"; import MinecraftUtils from "../util/minecraft_utils.js"; import MigrateError from "../errors/migrate_error.js"; -import inquirer from "inquirer"; import { StringBuilder } from 'typescript-string-operations'; import chalk from "chalk"; @@ -24,34 +23,36 @@ export default class Mods { this.MOD_SOURCES.push(source); } - public static async install(mod: string, essential: boolean): Promise { - let success: boolean = false; - + public static async install(mod: string, essential: boolean, confirm: boolean): Promise { // Go through each mod source for (const source of this.MOD_SOURCES) { - // If we have not yet successfully installed the queried mod - if (!success) { - const spinner = new PrintUtils.Spinner(`Searching for ${mod}...`); - spinner.start(); + const spinner = new PrintUtils.Spinner(`Searching for ${mod}...`); + spinner.start(); - // Search for the mod - let id: string | undefined; - try { - id = await source.search(mod); - } catch (e) { - if (e instanceof ModNotFoundError) { - spinner.stop(`Mod ${mod} not found on ${source.getSourceName()}`) - } else { - spinner.error(`An error occurred searching for ${mod} on ${source.getSourceName()}. Skipping ${source.getSourceName()}`) - // Try the next source - continue; - } + // Search for the mod + let id: string | undefined; + try { + id = await source.search(mod); + } catch (e) { + if (e instanceof ModNotFoundError) { + spinner.stop(`Mod ${mod} not found on ${source.getSourceName()}`) + } else { + spinner.error(`An error occurred searching for ${mod} on ${source.getSourceName()}. Skipping ${source.getSourceName()}`) + } + } + + // If a mod is found + if (id != undefined) { + const projectName = await source.getProjectName(id); + + // Ask user whether this mod is correct + if (!confirm) { + spinner.pause(); + confirm = await Util.getYesNoFromUser(`Confirm installation of ${projectName} from ${source.getSourceName()}? (y/n)`) } - // If a mod is found, install it - if (id != undefined) { - const projectName = await source.getProjectName(id); - + // If user has confirmed installation + if (confirm) { // If mod is not already installed if (!this.isModInstalled(id)) { spinner.updateText(`Installing ${projectName}...`) @@ -61,7 +62,7 @@ export default class Mods { await source.install(latestVersion, essential); spinner.succeed(`Successfully installed ${projectName}`); - success = true; + return; } catch (e) { // Log the error, and continue to next source spinner.error(e); @@ -120,20 +121,8 @@ export default class Mods { spinner.pause(); const dependantMods = Mods.getDependantMods(modToUninstall.id); - const answer = await inquirer.prompt([{ - type: "input", - name: "delete", - message: chalk.yellowBright(`${modToUninstall.name} is depended on by ${Mods.modListToSting(dependantMods)}. Are you sure you would like to uninstall? (y/n)`), - async validate(input: any): Promise { - const lowerInput = input.toLowerCase(); - const valid = lowerInput === "y" || lowerInput === "n" ; - if (!valid) { - return "Please answer either y or n" - } - return valid - }, - }]) - del = Util.getBoolFromYesNo(answer.delete); + const question = chalk.yellowBright(`${modToUninstall.name} is depended on by ${Mods.modListToSting(dependantMods)}. Are you sure you would like to uninstall? (y/n)`); + del = await Util.getYesNoFromUser(question); } // If we are deleting this mod, uninstall it diff --git a/src/util/util.ts b/src/util/util.ts index 7e553e6..c9f04a2 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,4 +1,5 @@ import {stringSimilarity} from "string-similarity-js"; +import inquirer from "inquirer"; export default class Util { private static readonly SIMILARITY_THRESHOLD: number = 0.8; @@ -22,7 +23,24 @@ export default class Util { return stringSimilarity(master, compare) >= this.SIMILARITY_THRESHOLD; } - static getBoolFromYesNo(answer: string) { + static async getYesNoFromUser(question: string) { + const answer = await inquirer.prompt([{ + type: "input", + name: "confirm", + message: question, + async validate(input: any): Promise { + const lowerInput = input.toLowerCase(); + const valid = lowerInput === "y" || lowerInput === "n" ; + if (!valid) { + return "Please answer either y or n" + } + return valid + }, + }]) + return Util.getBoolFromYesNo(answer.confirm); + } + + private static getBoolFromYesNo(answer: string) { if (answer.toLowerCase() === "y") { return true; } else if (answer.toLowerCase() === "n") {