diff --git a/build.gradle b/build.gradle index 94bae49..c9767de 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile 'org.slf4j:slf4j-simple:2.0.0-alpha1' compile 'com.j2html:j2html:1.4.0' + compile 'org.reflections:reflections:0.9.12' } sourceSets { diff --git a/src/main/java/ley/anvil/modpacktools/Main.java b/src/main/java/ley/anvil/modpacktools/Main.java index a0d6171..42f3017 100644 --- a/src/main/java/ley/anvil/modpacktools/Main.java +++ b/src/main/java/ley/anvil/modpacktools/Main.java @@ -1,49 +1,33 @@ package ley.anvil.modpacktools; -import ley.anvil.modpacktools.commands.Commands; +import ley.anvil.modpacktools.command.CommandLoader; +import ley.anvil.modpacktools.command.CommandReturn; import ley.anvil.modpacktools.util.Config; +import java.util.NoSuchElementException; + public class Main { - public static final Config CONFIG = new Config(); + public static final Config CONFIG = new Config(); + public static final CommandLoader LOADER = new CommandLoader("ley.anvil.modpacktools.commands"); - public static void main(String[] args) { - if(args.length == 0) { - Commands.help(); - return; - } - switch(args[0].toLowerCase() /* ignores case of commands */) { - case "help": - default: - Commands.help(); - break; - case "init": - Commands.init(); - break; - case "addmod": - Commands.addMod(args); - break; - case "buildtwitch": - Commands.buildTwitch(); - break; - case "buildmodpackjson": - Commands.buildModpackJSON(); - break; - case "buildraw": - Commands.buildRaw(); - break; - case "buildserver": - Commands.buildServer(args); - break; - case "downloadmods": - Commands.downloadMods(args); - break; - case "createmodlist": - Commands.createModlist(args); - break; - case "makeserver": - Commands.makeServer(args); - break; - } - } + public static void main(String[] args) { + if(args.length <= 0) { + printHelp(); + return; + } + try { + CommandReturn ret = LOADER.runCommand(args[0], args); + if(!ret.hadSuccess()) + System.out.println(ret.getRet()); + }catch(NoSuchElementException e) { + System.out.println(e.getMessage()); + printHelp(); + } + } + + private static void printHelp() { + System.out.println("Commands:"); + LOADER.getCommands().forEach((k, v) -> System.out.println(k)); + } } diff --git a/src/main/java/ley/anvil/modpacktools/command/CommandLoader.java b/src/main/java/ley/anvil/modpacktools/command/CommandLoader.java new file mode 100644 index 0000000..042b132 --- /dev/null +++ b/src/main/java/ley/anvil/modpacktools/command/CommandLoader.java @@ -0,0 +1,42 @@ +package ley.anvil.modpacktools.command; + +import org.reflections.Reflections; +import org.reflections.scanners.SubTypesScanner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; + +public class CommandLoader { + private final String commandsPkg; + private final Map commands = new HashMap<>(); + + public CommandLoader(String commandsPkg) { + this.commandsPkg = commandsPkg; + loadCommands(); + } + + private void loadCommands() { + Reflections reflections = new Reflections(commandsPkg, new SubTypesScanner(false)); + reflections.getSubTypesOf(ICommand.class).stream() + .filter(t -> t.isAnnotationPresent(LoadCommand.class)) + .forEach(t -> { + try { + commands.put(t.getAnnotation(LoadCommand.class).value(), t.newInstance()); + }catch(InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + }); + } + + public CommandReturn runCommand(String name, String[] args) throws NoSuchElementException { + return commands.computeIfAbsent(name.toLowerCase(), x -> { + throw new NoSuchElementException("Command " + x + " Not Found"); + }).execute(args); + } + + public Map getCommands() { + return Collections.unmodifiableMap(commands); + } +} diff --git a/src/main/java/ley/anvil/modpacktools/command/CommandReturn.java b/src/main/java/ley/anvil/modpacktools/command/CommandReturn.java new file mode 100644 index 0000000..f3c1f7d --- /dev/null +++ b/src/main/java/ley/anvil/modpacktools/command/CommandReturn.java @@ -0,0 +1,31 @@ +package ley.anvil.modpacktools.command; + +public class CommandReturn { + private final String ret; + private final boolean success; + + private CommandReturn(String ret, boolean success) { + this.ret = ret; + this.success = success; + } + + public static CommandReturn fail(String ret) { + return new CommandReturn(ret, false); + } + + public static CommandReturn success() { + return success(""); + } + + public static CommandReturn success(String ret) { + return new CommandReturn(ret, true); + } + + public boolean hadSuccess() { + return success; + } + + public String getRet() { + return ret; + } +} diff --git a/src/main/java/ley/anvil/modpacktools/command/ICommand.java b/src/main/java/ley/anvil/modpacktools/command/ICommand.java new file mode 100644 index 0000000..417e973 --- /dev/null +++ b/src/main/java/ley/anvil/modpacktools/command/ICommand.java @@ -0,0 +1,15 @@ +package ley.anvil.modpacktools.command; + +public interface ICommand { + + /** + * Executes this Command + * @param args Arguments for the Command + * @return If the Command was executed successful + */ + CommandReturn execute(String[] args); + + default String getName() { + return this.getClass().getAnnotation(LoadCommand.class).value(); + } +} diff --git a/src/main/java/ley/anvil/modpacktools/command/LoadCommand.java b/src/main/java/ley/anvil/modpacktools/command/LoadCommand.java new file mode 100644 index 0000000..2c27dae --- /dev/null +++ b/src/main/java/ley/anvil/modpacktools/command/LoadCommand.java @@ -0,0 +1,18 @@ +package ley.anvil.modpacktools.command; + +import java.lang.annotation.*; + +/** + * Tells The {@code CommandLoader} to load this command + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface LoadCommand { + /** + * the name of this command, must be lower case + * + * @return the name of this command + */ + String value(); +} diff --git a/src/main/java/ley/anvil/modpacktools/commands/ModInfo.java b/src/main/java/ley/anvil/modpacktools/commandhelper/ModInfo.java similarity index 97% rename from src/main/java/ley/anvil/modpacktools/commands/ModInfo.java rename to src/main/java/ley/anvil/modpacktools/commandhelper/ModInfo.java index f46030e..1249e1f 100644 --- a/src/main/java/ley/anvil/modpacktools/commands/ModInfo.java +++ b/src/main/java/ley/anvil/modpacktools/commandhelper/ModInfo.java @@ -1,4 +1,4 @@ -package ley.anvil.modpacktools.commands; +package ley.anvil.modpacktools.commandhelper; import com.google.gson.Gson; import com.google.gson.JsonArray; diff --git a/src/main/java/ley/anvil/modpacktools/commands/AddMod.java b/src/main/java/ley/anvil/modpacktools/commands/AddMod.java new file mode 100644 index 0000000..de92e3c --- /dev/null +++ b/src/main/java/ley/anvil/modpacktools/commands/AddMod.java @@ -0,0 +1,114 @@ +package ley.anvil.modpacktools.commands; + +import com.therandomlabs.curseapi.CurseAPI; +import com.therandomlabs.curseapi.CurseException; +import com.therandomlabs.curseapi.project.CurseProject; +import ley.anvil.addonscript.curse.CurseTools; +import ley.anvil.addonscript.v1.AddonscriptJSON; +import ley.anvil.modpacktools.Main; +import ley.anvil.modpacktools.command.CommandReturn; +import ley.anvil.modpacktools.command.ICommand; +import ley.anvil.modpacktools.command.LoadCommand; +import okhttp3.HttpUrl; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@LoadCommand("addmod") +public class AddMod implements ICommand { + + @Override + public CommandReturn execute(String[] args) { + //Check if the command has the correct number of args + if(args.length >= 2) { + //TODO Theres no way this command will work in this state of course + AddonscriptJSON json = null; + AddonscriptJSON.Version version = null; + if (json != null && json.versions != null) { + if (json.versions.size() == 1) { + version = json.versions.get(0); + } else { + for (AddonscriptJSON.Version v : json.versions) { + if (v.versionid == -1) { + version = v; + break; + } + } + } + } + if (version == null) { + throw new RuntimeException("Error: The modpack.json does not include a version with id -1"); + } + //The url must match this + String regex = "(?m)^(http)(s)?://(www\\.)?(curseforge.com/minecraft/mc-mods/)[0-z,\\-]+/(files)/[0-9]+$"; + String endPartRegex = "(/files/)[0-9]+$"; + if(args[1].matches(regex)) { + CurseTools.addCurseRepo(json); + try { + //remove fileID + System.out.println("Getting ID"); + CurseProject project = CurseAPI.project(HttpUrl.get(args[1].replaceAll(endPartRegex, ""))).get(); + int projectID = project.id(); + //extract fileID + Pattern pattern = Pattern.compile("[0-9]+$"); + Matcher matcher = pattern.matcher(args[1]); + int fileID = 0; + if(matcher.find()) { + fileID = Integer.parseInt(matcher.group(0)); + } + File manifestFile = new File(Main.CONFIG.JAR_LOCATION, Main.CONFIG.CONFIG + .getTable("Locations") + .getString("manifestFile")); + System.out.println("Reading Addonscript"); + //Get Mods in manifest file + //Check if Mod already exsits + for(AddonscriptJSON.Relation file : version.relations) { + if (file.file != null) { + String[] parts = file.file.split(":"); + if (parts.length == 3 && parts[0].equals("curse")) { //TODO check, if it is a Curse repo, waiting for Addonscript to update this + int projID = Integer.parseInt(parts[1]); + if (projID == projectID) { + return CommandReturn.fail("The Mod Is already Installed"); + } + } + } + } + System.out.println("Adding Mod " + project.name()); + //Construct Mod + AddonscriptJSON.Relation rel = new AddonscriptJSON.Relation(); + rel.file = CurseTools.toArtifact(projectID, fileID); + rel.type = "included"; + rel.installer = "internal.dir"; + //Add Mod to array + if (version.relations == null) { + version.relations = new ArrayList<>(); + } + version.relations.add(rel); + //Overwrite Old Manifest File + FileWriter manifestWriter = new FileWriter(manifestFile, false); + System.out.println("Printing Manifest"); + json.write(manifestWriter); + manifestWriter.close(); + } catch(CurseException | IOException e) { + e.printStackTrace(); + } + } else { + AddonscriptJSON.Relation rel = new AddonscriptJSON.Relation(); + rel.file = args[1]; + rel.type = "included"; + rel.installer = "internal.dir"; + if (version.relations == null) { + version.relations = new ArrayList<>(); + } + version.relations.add(rel); + } + } else { + return CommandReturn.fail("Syntax: addmod "); + } + return CommandReturn.success(); + } +} diff --git a/src/main/java/ley/anvil/modpacktools/commands/Commands.java b/src/main/java/ley/anvil/modpacktools/commands/Commands.java deleted file mode 100644 index b38efe2..0000000 --- a/src/main/java/ley/anvil/modpacktools/commands/Commands.java +++ /dev/null @@ -1,279 +0,0 @@ -package ley.anvil.modpacktools.commands; - -import com.therandomlabs.curseapi.CurseAPI; -import com.therandomlabs.curseapi.CurseException; -import com.therandomlabs.curseapi.project.CurseProject; -import j2html.TagCreator; -import j2html.tags.ContainerTag; -import ley.anvil.addonscript.curse.CurseTools; -import ley.anvil.addonscript.v1.AddonscriptJSON; -import ley.anvil.modpacktools.Main; -import okhttp3.HttpUrl; -import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVPrinter; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static j2html.TagCreator.*; - -public class Commands { - - /** - * Prints out all available commands - */ - public static void help() { - System.out.println("Help Goes here!"); - } - - /** - * Creates a modpack dev environment in the current folder - */ - public static void init() { - - } - - //Commands for modpack devs (only available in a modpack dev environment) - - /** - * Adds a mod to the modpack - * @param modlink Can be a link to a curseforge file or to a file download - */ - //TODO Renaming? - public static void addMod(String[] modlink) { - //Check if the command has the correct number of args - if(modlink.length >= 2) { - AddonscriptJSON json = getJSON(); - AddonscriptJSON.Version version = null; - if (json != null && json.versions != null) { - if (json.versions.size() == 1) { - version = json.versions.get(0); - } else { - for (AddonscriptJSON.Version v : json.versions) { - if (v.versionid == -1) { - version = v; - break; - } - } - } - } - if (version == null) { - throw new RuntimeException("Error: The modpack.json does not include a version with id -1"); - } - //The url must match this - String regex = "(?m)^(http)(s)?://(www\\.)?(curseforge.com/minecraft/mc-mods/)[0-z,\\-]+/(files)/[0-9]+$"; - String endPartRegex = "(/files/)[0-9]+$"; - if(modlink[1].matches(regex)) { - CurseTools.addCurseRepo(json); - try { - //remove fileID - System.out.println("Getting ID"); - CurseProject project = CurseAPI.project(HttpUrl.get(modlink[1].replaceAll(endPartRegex, ""))).get(); - int projectID = project.id(); - //extract fileID - Pattern pattern = Pattern.compile("[0-9]+$"); - Matcher matcher = pattern.matcher(modlink[1]); - int fileID = 0; - if(matcher.find()) { - fileID = Integer.parseInt(matcher.group(0)); - } - File manifestFile = new File(Main.CONFIG.JAR_LOCATION, Main.CONFIG.CONFIG - .getTable("Locations") - .getString("manifestFile")); - System.out.println("Reading Addonscript"); - //Get Mods in manifest file - //Check if Mod already exsits - for(AddonscriptJSON.Relation file : version.relations) { - if (file.file != null) { - String[] parts = file.file.split(":"); - if (parts.length == 3 && parts[0].equals("curse")) { //TODO check, if it is a Curse repo, waiting for Addonscript to update this - int projID = Integer.parseInt(parts[1]); - if (projID == projectID) { - System.out.println("The mod is already installed!"); - return; - } - } - } - } - System.out.println("Adding Mod " + project.name()); - //Construct Mod - AddonscriptJSON.Relation rel = new AddonscriptJSON.Relation(); - rel.file = CurseTools.toArtifact(projectID, fileID); - rel.type = "included"; - rel.installer = "internal.dir"; - //Add Mod to array - if (version.relations == null) { - version.relations = new ArrayList<>(); - } - version.relations.add(rel); - //Overwrite Old Manifest File - FileWriter manifestWriter = new FileWriter(manifestFile, false); - System.out.println("Printing Manifest"); - json.write(manifestWriter); - manifestWriter.close(); - } catch(CurseException | IOException e) { - e.printStackTrace(); - } - } else { - AddonscriptJSON.Relation rel = new AddonscriptJSON.Relation(); - rel.file = modlink[1]; - rel.type = "included"; - rel.installer = "internal.dir"; - if (version.relations == null) { - version.relations = new ArrayList<>(); - } - version.relations.add(rel); - } - } else { - System.out.println("Syntax: addmod "); - } - } - - /** - * Builds the modpack as a Twitch modpack zip - */ - public static void buildTwitch() { - - } - - /** - * Builds the modpack as a modpack.json - */ - public static void buildModpackJSON() { - - } - - /** - * Builds the modpack as a raw zip file (for example for the Technic Launcher) - */ - public static void buildRaw() { - - } - - /** - * Builds the modpack as a server - * @param dir The directory where to create the server - */ - public static void buildServer(String[] dir) { - - } - - /** - * Downloads all mods in this pack - * @param dir The mods directory - */ - public static void downloadMods(String[] dir) { - - } - - /** - * Creates a modlist of this pack - * @param format 1 Can be html or csv, 2 can be any valid file to write to - */ - public static void createModlist(String[] format) { - if(format.length >= 3) { - if(format[1].equalsIgnoreCase("csv")) { - File csvFile = new File(format[2]); - if(csvFile.exists()) { - System.out.println("Delete " + csvFile); - return; - } - System.out.println("Printing CSV into " + csvFile); - try(CSVPrinter printer = new CSVPrinter(new FileWriter(csvFile), CSVFormat.EXCEL.withDelimiter(';'))) { - printer.printRecord("Name", "Authors", "Link", "Downloads", "ID"); - printer.println(); - ArrayList modlist = ModInfo.getModInfo(); - Collections.sort(modlist, Comparator.comparing(a -> a.getName().toLowerCase())); - for(ModInfo mod : modlist) { - String name = mod.getName(); - String[] authorArr = mod.getAuthors(); - String link = mod.getLink(); - int downloads = mod.getDownloads(); - int id = mod.getId(); - StringBuilder sb = new StringBuilder(); - for(String author : authorArr) { - sb.append(author); - sb.append(", "); - } - String authors = sb.toString(); - authors = authors.substring(0, authors.length() - 2); - - printer.printRecord(name, authors, link, downloads, id); - } - } catch(IOException e) { - e.printStackTrace(); - } - } else if(format[1].equalsIgnoreCase("html")) { - File htmlFile = new File(format[2]); - if(htmlFile.exists()) { - System.out.println("Delete " + htmlFile); - return; - } - ArrayList mods = ModInfo.getModInfo(); - Collections.sort(mods, Comparator.comparing(a -> a.getName().toLowerCase())); - ContainerTag table = body( - TagCreator.table(TagCreator.attrs("#mods"), TagCreator.tbody( - tr(td(b("Name")), - td(b("Authors")), - td(b("ID")), - td(b("Downloads")) - ), - TagCreator.each(mods, i -> { - StringBuilder sb = new StringBuilder(); - for(String author : i.getAuthors()) { - sb.append(author); - sb.append(", "); - } - String authors = sb.toString(); - authors = authors.substring(0, authors.length() - 2); - - return tr(td(a(i.getName()) - .withHref(i.getLink()) - .withRel("noopener noreferrer") - .withTarget("_blank")), - td(authors), - td(String.valueOf(i.getId())), - td(String.valueOf(i.getDownloads()))); - }) - )) - ); - try { - System.out.println("Writing HTML"); - FileWriter htmlWrite = new FileWriter(htmlFile); - htmlWrite.write(table.render()); - htmlWrite.close(); - } catch(IOException e) { - e.printStackTrace(); - } - } else { - System.out.println("Expected Either HTML or CSV as format"); - } - } else { - System.out.println("Syntax: createmodlist "); - } - } - - - //Commands for users (available outside a modpack dev environment) - - /** - * Creates a server from a modpack zip file - * @param args The path to the zip file, The directory where to create the server - */ - public static void makeServer(String[] args) { - - } - - public static AddonscriptJSON getJSON() { - //TODO Return the current AddonscriptJSON/ModpackJSON - return null; - } - - -} diff --git a/src/main/java/ley/anvil/modpacktools/commands/CreateModList.java b/src/main/java/ley/anvil/modpacktools/commands/CreateModList.java new file mode 100644 index 0000000..e9f649f --- /dev/null +++ b/src/main/java/ley/anvil/modpacktools/commands/CreateModList.java @@ -0,0 +1,105 @@ +package ley.anvil.modpacktools.commands; + +import j2html.TagCreator; +import j2html.tags.ContainerTag; +import ley.anvil.modpacktools.command.CommandReturn; +import ley.anvil.modpacktools.command.ICommand; +import ley.anvil.modpacktools.command.LoadCommand; +import ley.anvil.modpacktools.commandhelper.ModInfo; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +import static j2html.TagCreator.*; + +@LoadCommand("createmodlist") +public class CreateModList implements ICommand { + @Override + public CommandReturn execute(String[] args) { + if(args.length >= 3) { + if(args[1].equalsIgnoreCase("csv")) { + File csvFile = new File(args[2]); + if(csvFile.exists()) { + return CommandReturn.fail("Delete " + csvFile); + } + System.out.println("Printing CSV into " + csvFile); + try(CSVPrinter printer = new CSVPrinter(new FileWriter(csvFile), CSVFormat.EXCEL.withDelimiter(';'))) { + printer.printRecord("Name", "Authors", "Link", "Downloads", "ID"); + printer.println(); + ArrayList modlist = ModInfo.getModInfo(); + Collections.sort(modlist, Comparator.comparing(a -> a.getName().toLowerCase())); + for(ModInfo mod : modlist) { + String name = mod.getName(); + String[] authorArr = mod.getAuthors(); + String link = mod.getLink(); + int downloads = mod.getDownloads(); + int id = mod.getId(); + StringBuilder sb = new StringBuilder(); + for(String author : authorArr) { + sb.append(author); + sb.append(", "); + } + String authors = sb.toString(); + authors = authors.substring(0, authors.length() - 2); + + printer.printRecord(name, authors, link, downloads, id); + } + }catch(IOException e) { + e.printStackTrace(); + } + }else if(args[1].equalsIgnoreCase("html")) { + File htmlFile = new File(args[2]); + if(htmlFile.exists()) { + return CommandReturn.fail("Delete " + htmlFile); + } + ArrayList mods = ModInfo.getModInfo(); + Collections.sort(mods, Comparator.comparing(a -> a.getName().toLowerCase())); + ContainerTag table = body( + TagCreator.table(TagCreator.attrs("#mods"), TagCreator.tbody( + tr(td(b("Name")), + td(b("Authors")), + td(b("ID")), + td(b("Downloads")) + ), + TagCreator.each(mods, i -> { + StringBuilder sb = new StringBuilder(); + for(String author : i.getAuthors()) { + sb.append(author); + sb.append(", "); + } + String authors = sb.toString(); + authors = authors.substring(0, authors.length() - 2); + + return tr(td(a(i.getName()) + .withHref(i.getLink()) + .withRel("noopener noreferrer") + .withTarget("_blank")), + td(authors), + td(String.valueOf(i.getId())), + td(String.valueOf(i.getDownloads()))); + }) + )) + ); + try { + System.out.println("Writing HTML"); + FileWriter htmlWrite = new FileWriter(htmlFile); + htmlWrite.write(table.render()); + htmlWrite.close(); + }catch(IOException e) { + e.printStackTrace(); + } + }else { + return CommandReturn.fail("Expected Either HTML or CSV as format"); + } + }else { + return CommandReturn.fail("Syntax: createmodlist "); + } + return CommandReturn.success(); + } +} diff --git a/src/main/java/ley/anvil/modpacktools/commands/ICommand.java b/src/main/java/ley/anvil/modpacktools/commands/ICommand.java deleted file mode 100644 index 0529153..0000000 --- a/src/main/java/ley/anvil/modpacktools/commands/ICommand.java +++ /dev/null @@ -1,12 +0,0 @@ -package ley.anvil.modpacktools.commands; - -public interface ICommand { - - /** - * Executes this Command - * @param args Arguments for the Command - * @return If the Command was executed successful - */ - boolean execure(String[] args); - -}