Inceptum/launcher-cli/src/main/java/io/gitlab/jfronny/inceptum/cli/commands/ModCommand.java

190 lines
8.4 KiB
Java

package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.commons.throwable.ThrowingBiFunction;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Mod;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.launcher.util.Unchecked;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ModCommand extends Command {
//TODO ModAddCommand (search and install)
public ModCommand() {
super("Allows managing mods in instances", "", List.of("mod"), List.of(
new ModListCommand(),
new ModUpdateCommand(),
new ModRemoveCommand()
));
}
@Override
protected void invoke(CommandArgs args) {
Utils.LOGGER.error("No known mod command was specified");
}
public static class ModListCommand extends BaseInstanceCommand {
private final boolean filterUpdatable;
public ModListCommand() {
this("Lists the mods in an instance", List.of("list", "ls"), List.of(
new ModListCommand("List only updatable mods", List.of("updatable"), List.of(), true)
), false);
}
private ModListCommand(String help, List<String> aliases, List<Command> subCommands, boolean filterUpdatable) {
super(help, "", aliases, subCommands);
this.filterUpdatable = filterUpdatable;
}
@Override
protected void invoke(CommandArgs args, Instance instance) throws IOException {
if (!instance.isFabric) {
System.err.println("This is not a fabric instance");
return;
}
System.out.println("Scanning installed mods, this might take a while");
instance.mds.runOnce((path, mod) -> {
boolean hasSources = !mod.metadata.sources.isEmpty;
boolean updatable = hasSources && mod.metadata.sources.values().stream().anyMatch(Optional::isPresent);
if (filterUpdatable && !updatable) return;
System.out.println("- " + path.fileName.toString());
System.out.println(" " + mod.name);
for (String s : mod.description) {
System.out.println(" " + s);
}
if (hasSources) {
System.out.println(" Sources:");
for (var entry : mod.metadata.sources) {
System.out.println(" - " + entry.key.name + " (" + entry.key.version + ")");
System.out.println(" Local: " + entry.key.jarPath.toString());
if (entry.value.isPresent) System.out.println(" Updatable to: " + entry.value.get().version);
}
}
});
}
}
public static class ModRemoveCommand extends BaseInstanceCommand {
private final boolean ignoreDependencies;
public ModRemoveCommand() {
this("Removes mods from an instance", List.of("remove", "delete", "rm", "del"), List.of(
new ModRemoveCommand("Skip dependency checks", List.of("ignore-dependencies"), List.of(), true)
), false);
}
private ModRemoveCommand(String help, List<String> aliases, List<Command> subCommands, boolean ignoreDependencies) {
super(help, "<mod file>...", aliases, subCommands);
this.ignoreDependencies = ignoreDependencies;
}
@Override
protected void invoke(CommandArgs args, Instance instance) throws IOException {
if (!instance.isFabric()) {
Utils.LOGGER.error("This is not a fabric instance");
return;
}
if (args.length == 0) {
Utils.LOGGER.error("You must specify mods to remove");
return;
}
Set<Path> mods = new HashSet<>();
for (String arg : args) {
Path p = instance.modsDir.resolve(arg);
if (!Files.exists(p)) p = instance.modsDir.resolve(arg + ".imod");
if (!Files.exists(p)) {
Utils.LOGGER.error("Nonexistant mod file: " + instance.modsDir.resolve(arg));
return;
}
mods.add(p);
}
ModsDirScanner mds = instance.mds;
if (!ignoreDependencies && !mds.isComplete) {
Utils.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}
for (Path mod : mods) {
try {
mds[mod].delete();
} catch (IOException e) {
Utils.LOGGER.error("Could not delete " + mod, e);
return;
}
}
}
}
public static class ModUpdateCommand extends BaseInstanceCommand {
private final ThrowingBiFunction<CommandArgs, Path, Set<Path>, IOException> pathSupplier;
public ModUpdateCommand() {
this("Update mods in an instance", "<mod file>...", List.of("update", "upgrade", "up"), List.of(
new ModUpdateCommand("Update all mods in an instance", "", List.of("all"), List.of(), (args, instancePath) -> Set.copyOf(JFiles.list(instancePath)))
), (args, instancePath) -> {
Set<Path> mods = new HashSet<>();
for (String arg : args) {
Path p = instancePath.resolve("mods").resolve(arg);
if (!Files.exists(p)) p = instancePath.resolve("mods").resolve(arg + ".imod");
if (!Files.exists(p)) {
throw new FileNotFoundException("Nonexistant mod file: " + instancePath.resolve("mods").resolve(arg));
}
mods.add(p);
}
return mods;
});
}
private ModUpdateCommand(String help, String usage, List<String> aliases, List<Command> subCommands, ThrowingBiFunction<CommandArgs, Path, Set<Path>, IOException> pathSupplier) {
super(help, usage, aliases, subCommands);
this.pathSupplier = pathSupplier;
}
@Override
protected void invoke(CommandArgs args, Instance instance) throws IOException {
if (!instance.isFabric()) {
throw new IOException("This is not a fabric instance");
}
if (args.length == 0) {
throw new IllegalArgumentException("You must specify mods to remove");
}
Set<Path> mods = pathSupplier.apply(args, instance.path);
ModsDirScanner mds = instance.mds;
if (!mds.isComplete) {
Utils.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}
for (Path mod : mods) {
try {
Mod md = mds[mod];
md.delete();
md.metadata.sources.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.ifPresentOrElse(update -> {
try {
Utils.LOGGER.info("Updating " + mod + " to " + update.version);
md.update(update);
Utils.LOGGER.info("Update completed");
} catch (IOException e) {
throw new Unchecked(e);
}
}, () -> Utils.LOGGER.error("Could not find any update for " + mod));
} catch (IOException e) {
throw new IOException("Could not delete " + mod, e);
} catch (Unchecked e) {
throw new IOException("Could not delete " + mod, e.exception);
}
}
}
}
}