-Reworked Repository System
-Cleanup
-Get multiple metas
This commit is contained in:
Timo Ley 2020-07-26 23:55:27 +02:00
parent 04c6ecb541
commit d83074cc1e
13 changed files with 205 additions and 314 deletions

View File

@ -14,7 +14,6 @@ repositories {
dependencies {
compile 'com.google.code.gson:gson:+'
compile 'org.python:jython-standalone:2.7.0'
compile "com.github.TheRandomLabs:CurseAPI:master-SNAPSHOT"
compile 'com.google.code.findbugs:jsr305:3.0.2'

View File

@ -0,0 +1,49 @@
package ley.anvil.addonscript.curse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ley.anvil.addonscript.wrapper.MetaData;
import java.util.List;
public class CurseMeta {
static Gson gson = new GsonBuilder().create();
public static CurseMeta fromJSON(String json) {
return gson.fromJson(json, CurseMeta.class);
}
public MetaData toMeta() {
MetaData meta = new MetaData();
meta.website = websiteUrl;
meta.name = name;
for (Author a : authors) {
meta.contributors.put(a.name, new String[]{"author"});
}
meta.description = new String[1];
meta.description[0] = summary;
for (Attachment a : attachments) {
if (a.isDefault)
meta.icon = a.url;
}
return meta;
}
public int id;
public String name;
public List<Author> authors;
public List<Attachment> attachments;
public String websiteUrl;
public String summary;
public static class Author {
public String name;
}
public static class Attachment {
public boolean isDefault;
public String url;
}
}

View File

@ -1,65 +0,0 @@
package ley.anvil.addonscript.curse;
import com.therandomlabs.curseapi.CurseAPI;
import com.therandomlabs.curseapi.CurseException;
import com.therandomlabs.curseapi.project.CurseProject;
import ley.anvil.addonscript.v1.AddonscriptJSON;
import java.util.ArrayList;
import java.util.Optional;
public class CurseTools {
public static void addCurseRepo(AddonscriptJSON as) {
if (as.repositories == null) {
as.repositories = new ArrayList<>();
}
boolean alreadyAdded = false;
for (AddonscriptJSON.Repository repo : as.repositories) {
if (repo.type != null && repo.type.equals("curseforge")) {
alreadyAdded = true;
}
}
if (!alreadyAdded) {
AddonscriptJSON.Repository curseRepo = new AddonscriptJSON.Repository();
curseRepo.id = "curse";
curseRepo.type = "curseforge";
curseRepo.url = "https://www.curseforge.com/minecraft/";
as.repositories.add(curseRepo);
}
}
public static AddonscriptJSON.File toArtifact(int projectID, int fileID) {
AddonscriptJSON.File artifact = new AddonscriptJSON.File();
artifact.artifact = "curse:" + projectID + ":" + fileID;
return artifact;
}
public static boolean isCurseArtifact(String artifact, AddonscriptJSON as) {
String[] parts = artifact.split(":");
if (parts.length == 3 && parts[0].equals("curse")) {
try {
int proj = Integer.parseInt(parts[1]);
int file = Integer.parseInt(parts[0]);
return true;
} catch (NumberFormatException e) {
return false;
}
}
return false;
}
public static String getID(int projectID) {
try {
Optional<CurseProject> project = CurseAPI.project(projectID);
if (project.isPresent()) {
CurseProject proj = project.get();
return proj.slug();
}
} catch (CurseException e) {
return "NOID";
}
return "NOID";
}
}

View File

@ -1,62 +0,0 @@
package ley.anvil.addonscript.curse;
import com.therandomlabs.curseapi.CurseAPI;
import com.therandomlabs.curseapi.CurseException;
import com.therandomlabs.curseapi.file.CurseFile;
import com.therandomlabs.curseapi.project.CurseProject;
import ley.anvil.addonscript.util.IRepository;
import ley.anvil.addonscript.wrapper.MetaData;
import java.util.Optional;
public class CurseforgeRepository implements IRepository {
@Override
public String getFileURL(String artifact) {
CurseFile file = getFile(artifact);
if (file != null) {
return file.downloadURL().toString();
}
return "";
}
@Override
public MetaData getMeta(String artifact) {
MetaData meta = null;
CurseFile file = getFile(artifact);
if (file != null) {
meta = new MetaData();
try {
CurseProject project = file.project();
meta.name = project.name();
String desc = project.descriptionPlainText();
meta.description = desc.split("\n");
meta.website = project.url().toString();
meta.contributors.put(project.author().name(), new String[]{"owner"});
meta.icon = project.logo().url().toString();
} catch (CurseException e) {
e.printStackTrace();
}
} else {
System.out.println("WARNUNG: No file for Curseforge artifact " + artifact + " found!");
}
return meta;
}
public CurseFile getFile(String artifact) {
String[] parts = artifact.split(":");
if (parts.length >= 3 && parts[0].equals("curse")) {
int projectID = Integer.parseInt(parts[1]);
int fileID = Integer.parseInt(parts[2]);
try {
Optional<CurseFile> file = CurseAPI.file(projectID, fileID);
if (file.isPresent())
return file.get();
} catch (CurseException e) {
e.printStackTrace();
}
}
return null;
}
}

View File

@ -62,7 +62,10 @@ public class ManifestJSON extends JSON {
public AddonscriptJSON.Relation toRelation() {
AddonscriptJSON.Relation rel = new AddonscriptJSON.Relation();
rel.file = CurseTools.toArtifact(projectID, fileID);
rel.file = new AddonscriptJSON.File();
rel.file.repository = "curse";
rel.file.artifact = "curse.maven:" + projectID + ":" + fileID;
rel.file.installer = "internal.dir:mods";
rel.options = new ArrayList<>();
rel.options.add(required ? "required" : "optional");
rel.options.add("client");
@ -121,7 +124,12 @@ public class ManifestJSON extends JSON {
as.meta.contributors.add(getAuthor());
as.versions.add(getVersion());
CurseTools.addCurseRepo(as);
as.repositories = new ArrayList<>();
AddonscriptJSON.Repository curseRepo = new AddonscriptJSON.Repository();
curseRepo.id = "curse";
curseRepo.type = "curseforge";
curseRepo.url = "https://www.cursemaven.com/";
as.repositories.add(curseRepo);
return as;
}

View File

@ -1,52 +1,69 @@
package ley.anvil.addonscript.maven;
import java.util.Arrays;
import java.util.List;
import ley.anvil.addonscript.util.Utils;
public class ArtifactDestination {
public String repo;
public String group;
public String id;
public String version;
public String[] others;
public String packaging;
public String addition;
public ArtifactDestination(String dest) {
List<String> parts = Arrays.asList(dest.split(":"));
if (parts.size() >= 3) {
group = parts.get(0);
id = parts.get(1);
version = parts.get(2);
others = parts.subList(3, parts.size()).toArray(new String[0]);
} else {
throw new RuntimeException("Invalid artifact: " + dest);
public ArtifactDestination(String artifact, String repoLink) {
this(artifact, repoLink, "jar");
}
public ArtifactDestination(String artifact, String repoLink, String packaging) {
String[] parts = artifact.split(":");
if (parts.length >= 3) {
group = parts[0];
id = parts[1];
version = parts[2];
}
if (parts.length >= 4) {
addition = parts[3];
}
repo = repoLink;
this.packaging = packaging;
}
public String getPOMPath() {
return getFile("pom", null);
}
public String getPath() {
return getFile(packaging, addition);
}
private String getFile(String type, String addition) {
StringBuilder sb = new StringBuilder();
sb.append(Utils.slashEnd(repo));
for (String s : group.split("\\.")) {
sb.append(s).append("/");
}
sb.append(id).append("/").append(version).append("/");
sb.append(id).append("-").append(version);
sb.append(".pom");
if (addition != null)
sb.append("-").append(addition);
sb.append(".").append(type);
return sb.toString();
}
public String getPath(String filetype) {
StringBuilder sb = new StringBuilder();
for (String s : group.split("\\.")) {
sb.append(s).append("/");
}
sb.append(id).append("/").append(version).append("/");
sb.append(id).append("-").append(version);
for (String s : others) {
sb.append("-").append(s);
}
sb.append(".").append(filetype);
//Curseforge specific
return sb.toString();
public boolean isCurseforge() {
return repo.equals("https://www.cursemaven.com/") && group.equals("curse.maven");
}
public int getFileID() {
return Integer.parseInt(version);
}
public int getProjectID() {
return Integer.parseInt(id);
}
}

View File

@ -1,25 +0,0 @@
package ley.anvil.addonscript.maven;
import ley.anvil.addonscript.util.IRepository;
import ley.anvil.addonscript.wrapper.MetaData;
public class MavenRepository implements IRepository {
//TODO Complete this
String url;
public MavenRepository(String url) {
this.url = url;
}
@Override
public String getFileURL(String artifact) {
ArtifactDestination dest = new ArtifactDestination(artifact);
return dest.getPath(".jar");
}
@Override
public MetaData getMeta(String artifact) {
return null;
}
}

View File

@ -1,29 +0,0 @@
package ley.anvil.addonscript.util;
import ley.anvil.addonscript.wrapper.MetaData;
/**
* Interface for all repository types
*/
public interface IRepository {
/**
* Gets the file URL from an artifact
* @param artifact The artifact without the repo ID prefix
* @return The URL of the file
*/
@HTTPRequest
String getFileURL(String artifact);
/**
* Gets meta information about an artifact.
* Empty Object if nothing was found.
* @param artifact The artifact without the repo ID prefix
* @return A Meta object with meta information
*/
@HTTPRequest
MetaData getMeta(String artifact);
}

View File

@ -4,9 +4,13 @@ import ley.anvil.addonscript.v1.AddonscriptJSON;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class Utils {
@ -20,11 +24,42 @@ public class Utils {
}
public static boolean notEmpty(@Nullable String s) {
return s != null && !s.equals("");
return s != null && !s.isEmpty();
}
public static String slashEnd(@Nonnull String s) {
return s + (s.endsWith("/") ? "" : "/");
}
public static String httpJSONPost(String link, String payload, Map<String, String> headers) {
try {
URL url = new URL(link);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
for (String k : headers.keySet()) {
con.setRequestProperty(k, headers.get(k));
}
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
byte[] input = payload.getBytes("utf-8");
os.write(input, 0, input.length);
}
try (BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
return response.toString();
}
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}

View File

@ -1,10 +1,7 @@
package ley.anvil.addonscript.v1;
import com.google.gson.annotations.Expose;
import ley.anvil.addonscript.curse.CurseforgeRepository;
import ley.anvil.addonscript.maven.MavenRepository;
import ley.anvil.addonscript.util.ASBase;
import ley.anvil.addonscript.util.IRepository;
import java.io.Reader;
import java.util.List;
@ -173,6 +170,7 @@ public class AddonscriptJSON extends ASBase {
* Currently supported: curseforge, forge
*/
@Expose
@Deprecated
public String type;
/**
* The base url of this repository
@ -180,14 +178,6 @@ public class AddonscriptJSON extends ASBase {
@Expose
public String url;
public IRepository getRepository() {
switch (type) {
case "curseforge": return new CurseforgeRepository();
case "maven": return new MavenRepository(url);
default: return null;
}
}
}
public static class File {
@ -219,6 +209,10 @@ public class AddonscriptJSON extends ASBase {
*/
@Expose
public String artifact;
@Expose
public String repository;
@Expose
public String packaging;
/**
* Optional: Defaults if empty
* (Defaults = required, client, server)

View File

@ -1,8 +1,15 @@
package ley.anvil.addonscript.wrapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import jdk.nashorn.api.scripting.URLReader;
import ley.anvil.addonscript.curse.CurseMeta;
import ley.anvil.addonscript.forge.ForgeMeta;
import ley.anvil.addonscript.installer.IInstaller;
import ley.anvil.addonscript.installer.InternalDirInstaller;
import ley.anvil.addonscript.maven.ArtifactDestination;
import ley.anvil.addonscript.util.HTTPRequest;
import ley.anvil.addonscript.util.Utils;
import ley.anvil.addonscript.v1.AddonscriptJSON;
@ -12,37 +19,39 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
public class ASWrapper {
AddonscriptJSON json;
Indexes indexes;
RepoManager repoManager;
Map<String, String> REPOSITORIES;
public Map<String, IInstaller> INSTALLERS;
public Map<String, AddonscriptJSON> ADDONS;
public Map<Integer, ASWrapper.VersionWrapper> VERSIONS;
public ASWrapper(AddonscriptJSON json) {
this.json = json;
indexes = new Indexes();
repoManager = new RepoManager();
indexes.INSTALLERS.put("internal.dir", new InternalDirInstaller());
REPOSITORIES = new HashMap<>();
INSTALLERS = new HashMap<>();
ADDONS = new HashMap<>();
VERSIONS = new HashMap<>();
INSTALLERS.put("internal.dir", new InternalDirInstaller());
if (json.repositories != null) {
for (AddonscriptJSON.Repository r : json.repositories) {
repoManager.addRepository(r.id, r.getRepository());
REPOSITORIES.put(r.id, r.url);
}
}
if (json.index != null) {
for (AddonscriptJSON.IndexEntry e : json.index) {
if (e.type != null && e.type.equals("addon"))
indexes.ADDONS.put(e.id, Utils.getFromURL(e.link));
ADDONS.put(e.id, Utils.getFromURL(e.link));
//TODO external versions
}
}
if (json.versions != null) {
for (AddonscriptJSON.Version v : json.versions) {
if (!indexes.VERSIONS.containsKey(v.versionid))
indexes.VERSIONS.put(v.versionid, new VersionWrapper(v));
if (!VERSIONS.containsKey(v.versionid))
VERSIONS.put(v.versionid, new VersionWrapper(v));
}
}
}
@ -64,10 +73,6 @@ public class ASWrapper {
return json.toJSON();
}
public RepoManager getRepositories() {
return repoManager;
}
//Options
public List<String> defaultOptions() {
@ -78,6 +83,7 @@ public class ASWrapper {
return list;
}
//Versions
public VersionWrapper getDefaultVersion() {
@ -91,8 +97,8 @@ public class ASWrapper {
}
public VersionWrapper getVersion(int versionid) {
if (indexes.VERSIONS.containsKey(versionid))
return indexes.VERSIONS.get(versionid);
if (VERSIONS.containsKey(versionid))
return VERSIONS.get(versionid);
return new VersionWrapper();
}
@ -195,7 +201,7 @@ public class ASWrapper {
@HTTPRequest
public String getLink() {
if (!Utils.notEmpty(link) && Utils.notEmpty(file.artifact)) {
String l = repoManager.resolveArtifact(file.artifact);
String l = getArtifact().getPath();
if (Utils.notEmpty(l))
link = l;
}
@ -205,13 +211,21 @@ public class ASWrapper {
}
public boolean isArtifact() {
return Utils.notEmpty(file.artifact);
return Utils.notEmpty(file.artifact) && Utils.notEmpty(file.repository);
}
public String getArtifact() {
if (isArtifact())
return file.artifact;
return "";
public ArtifactDestination getArtifact() {
if (isArtifact()) {
if (REPOSITORIES.containsKey(file.repository)) {
if (Utils.notEmpty(file.packaging))
return new ArtifactDestination(file.artifact, REPOSITORIES.get(file.repository), file.packaging);
else
return new ArtifactDestination(file.artifact, REPOSITORIES.get(file.repository));
}
else
throw new RuntimeException("Repository " + file.repository + " not existing");
}
throw new RuntimeException("This has no artifact");
}
@Deprecated
@ -240,7 +254,7 @@ public class ASWrapper {
}
public boolean isInIndex() {
return indexes.ADDONS.containsKey(relation.id);
return ADDONS.containsKey(relation.id);
}
public boolean isModloader() {
@ -264,9 +278,32 @@ public class ASWrapper {
return new MetaData();
}
}
public static Map<ArtifactDestination, MetaData> getMetaData(ArtifactDestination[] artifacts) {
Map<ArtifactDestination, MetaData> meta = new HashMap<>();
List<Integer> curseRequest = new ArrayList<>();
for (ArtifactDestination dest : artifacts) {
if (dest.isCurseforge())
curseRequest.add(dest.getProjectID());
}
if (curseRequest.size() >= 1) {
Gson gson = new GsonBuilder().create();
String request = gson.toJson(curseRequest);
String response = Utils.httpJSONPost("https://addons-ecs.forgesvc.net/api/v2/addon", request, new HashMap<>());
JsonArray arr = gson.fromJson(response, JsonArray.class);
for (JsonElement e : arr) {
CurseMeta m = gson.fromJson(e, CurseMeta.class);
for (ArtifactDestination a : artifacts) {
if (a.id.equals(String.valueOf(m.id))) {
meta.put(a, m.toMeta());
break;
}
}
}
}
return meta;
}
}

View File

@ -1,21 +0,0 @@
package ley.anvil.addonscript.wrapper;
import ley.anvil.addonscript.installer.IInstaller;
import ley.anvil.addonscript.v1.AddonscriptJSON;
import java.util.HashMap;
import java.util.Map;
public class Indexes {
public Indexes() {
INSTALLERS = new HashMap<>();
ADDONS = new HashMap<>();
VERSIONS = new HashMap<>();
}
public Map<String, IInstaller> INSTALLERS;
public Map<String, AddonscriptJSON> ADDONS;
public Map<Integer, ASWrapper.VersionWrapper> VERSIONS;
}

View File

@ -1,46 +0,0 @@
package ley.anvil.addonscript.wrapper;
import ley.anvil.addonscript.util.HTTPRequest;
import ley.anvil.addonscript.util.IRepository;
import ley.anvil.addonscript.util.Utils;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
public class RepoManager {
HashMap<String, IRepository> repositories;
public RepoManager() {
repositories = new HashMap<>();
}
public void addRepository(@Nonnull String id, @Nonnull IRepository repo) {
repositories.put(id, repo);
}
@HTTPRequest
public String resolveArtifact(@Nonnull String artifact) {
for (IRepository repo : repositories.values()) {
String link = repo.getFileURL(artifact);
if (Utils.notEmpty(link))
return link;
}
throw new RuntimeException(artifact + " was not found in a known repository");
}
@HTTPRequest
public Map<String, MetaData> getMeta(@Nonnull String[] artifacts) {
Map<String, MetaData> metas = new HashMap<>();
for (String a : artifacts) {
for (IRepository r : repositories.values()) {
MetaData data = r.getMeta(a);
if (data != null)
metas.put(a, data);
}
}
return metas;
}
}