Use Repository

This commit is contained in:
Timo Ley 2021-06-01 15:33:08 +02:00
parent 45292c9909
commit b75a0cfbdf
12 changed files with 318 additions and 195 deletions

View file

@ -14,9 +14,13 @@ repositories {
url "https://libraries.minecraft.net"
name "minecraft"
}
maven {
url "https://data.tilera.xyz/maven/"
}
}
dependencies {
implementation "ley.anvil:addonscript:1.0-SNAPSHOT"
implementation group: 'net.lingala.zip4j', name: 'zip4j', version: '2.8.0'
compileOnly group: 'com.google.code.gson', name: 'gson', version: '2.8.7'
compileOnly group: "net.minecraft", name: "launchwrapper", version: "1.12"

View file

@ -1,7 +1,10 @@
package ley.modding.tcu;
import ley.modding.tcu.model.VersionDiff;
import ley.anvil.addonscript.v1.AddonscriptJSON;
import ley.modding.tcu.model.Config;
import ley.modding.tcu.model.RelationFile;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import java.io.BufferedInputStream;
import java.io.File;
@ -9,6 +12,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
public class FileHandler {
@ -37,38 +41,55 @@ public class FileHandler {
out.close();
}
public void processDiff(VersionDiff diff) {
for (VersionDiff.RemoveFile rem : diff.remove) {
File f = getFile(rem.dir, rem.filename);
if (f.exists()) {
boolean del = f.delete();
if (!del)
throw new RuntimeException("File deletion error");
}
public void removeFiles(List<RelationFile> rels) {
for (RelationFile rel : rels) {
File f = getFile(rel.dir, rel.filename());
if (f.exists())
f.delete();
}
}
for (VersionDiff.AddFile add : diff.add) {
public void addFiles(List<RelationFile> rels) {
for (RelationFile rel : rels) {
try {
downloadFile(add.dir, add.filename, new URL(add.url));
} catch (Exception e) {
System.out.println("Downloading " + rel.id);
downloadFile(rel.dir, rel.filename(), new URL(rel.url));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void processOverrides(URL overrides) {
public void processOverrides(String overrides, AddonscriptJSON as, Config config) {
try {
downloadFile(".", "temp.zip", overrides);
System.out.println("Downloading overrides...");
downloadFile(".", "temp.zip", new URL(overrides));
File tmp = getFile(".", "temp.zip");
ZipFile zip = new ZipFile(tmp);
zip.extractAll(gamedir.getPath());
for (AddonscriptJSON.File f : as.versions.get(0).files) {
if (f.installer.equals("internal.override")) {
String loc = buildPath(config.repository, f.link);
List<FileHeader> headers = zip.getFileHeaders();
for (FileHeader header : headers) {
if (header.toString().startsWith(loc) && !header.isDirectory())
zip.extractFile(header, ".", header.toString().replace(loc, ""));
}
}
}
tmp.delete();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String buildPath(String repo, String loc) {
String fileloc = loc.replace("file://", "");
if (fileloc.startsWith("..")) {
fileloc = fileloc.replace("..", "");
} else {
fileloc = "/src/" + fileloc;
}
return repo + fileloc + "/";
}
}

View file

@ -0,0 +1,68 @@
package ley.modding.tcu;
import ley.anvil.addonscript.v1.AddonscriptJSON;
import ley.modding.tcu.model.Release;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GiteaAPI {
String baseURL;
String repo;
String owner;
public GiteaAPI(String baseURL, String owner, String repo) {
this.baseURL = baseURL;
this.repo = repo;
this.owner = owner;
if (!this.baseURL.endsWith("/")) {
this.baseURL += "/";
}
}
public AddonscriptJSON getASFromTag(String tag) {
String url = baseURL + owner + "/" + repo + "/raw/tag/" + tag + "/src/modpack.json";
try {
URL u = new URL(url);
HttpURLConnection con = (HttpURLConnection) u.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
if (con.getResponseCode() != 200) {
return null;
}
InputStreamReader reader = new InputStreamReader(con.getInputStream());
AddonscriptJSON as = AddonscriptJSON.read(reader);
reader.close();
return as;
} catch (IOException e) {
return null;
}
}
public List<Release> getReleases() {
String url = baseURL + "api/v1/repos/" + owner + "/" + repo + "/releases";
try {
URL u = new URL(url);
HttpURLConnection con = (HttpURLConnection) u.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
if (con.getResponseCode() != 200) {
return new ArrayList<>();
}
InputStreamReader reader = new InputStreamReader(con.getInputStream());
Release[] releases = Release.fromJSON(reader);
reader.close();
return Arrays.asList(releases);
} catch (IOException e) {
return new ArrayList<>();
}
}
}

View file

@ -1,12 +1,14 @@
package ley.modding.tcu;
import ley.modding.tcu.model.LocalPack;
import ley.modding.tcu.model.VersionDiff;
import ley.anvil.addonscript.v1.AddonscriptJSON;
import ley.modding.tcu.model.Config;
import ley.modding.tcu.model.RelationFile;
import ley.modding.tcu.model.Version;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;
import java.io.File;
import java.net.URL;
import java.io.FileWriter;
import java.util.List;
public class UpdateTweaker implements ITweaker {
@ -32,20 +34,25 @@ public class UpdateTweaker implements ITweaker {
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
this.classLoader = classLoader;
try {
File modpack = new File(gameDir.getAbsolutePath() + "/modpack.json");
if (modpack.exists()) {
String[] ver = Util.checkVersion(modpack);
if (ver.length == 0)
File configfile = new File(gameDir.getAbsolutePath() + "/pack.json");
if (configfile.exists()) {
Config config = Util.getConfig(configfile);
Version version = Util.checkVersion(config);
if (version.isLatest())
return;
VersionDiff diff = Util.buildDiff(ver);
System.out.println(version.current + " is outdated, starting update...");
AddonscriptJSON oldAS = config.getAPI().getASFromTag(version.current);
AddonscriptJSON newAS = config.getAPI().getASFromTag(version.latest);
List<RelationFile> oldRel = Util.getRelations(oldAS);
List<RelationFile> newRel = Util.getRelations(newAS);
FileHandler handler = new FileHandler(gameDir);
handler.processDiff(diff);
URL overrides = Util.getOverrides();
if (overrides != null)
handler.processOverrides(overrides);
LocalPack pack = Util.getLocal(modpack);
pack.version = ver[ver.length - 1];
Util.writeLocal(modpack);
handler.removeFiles(Util.getToRemove(oldRel, newRel));
handler.addFiles(Util.getToAdd(oldRel, newRel));
handler.processOverrides(version.overrides, newAS, config);
config.version = version.latest;
FileWriter writer = new FileWriter(configfile);
config.toJson(writer);
writer.close();
}
} catch (Exception e) {
throw new RuntimeException(e);

View file

@ -1,119 +1,104 @@
package ley.modding.tcu;
import ley.modding.tcu.model.LocalPack;
import ley.modding.tcu.model.RemotePack;
import ley.modding.tcu.model.VersionDiff;
import ley.anvil.addonscript.v1.AddonscriptJSON;
import ley.modding.tcu.model.Config;
import ley.modding.tcu.model.RelationFile;
import ley.modding.tcu.model.Release;
import ley.modding.tcu.model.Version;
import java.io.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Util {
private static RemotePack rcache = null;
private static LocalPack lcache = null;
public static RemotePack getRemote(LocalPack pack) throws IOException {
if (rcache != null)
return rcache;
URL url = new URL(pack.packURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
int status = con.getResponseCode();
if (status != 200) {
return null;
}
InputStreamReader r2 = new InputStreamReader(con.getInputStream());
RemotePack ret = RemotePack.fromJSON(r2);
r2.close();
rcache = ret;
return ret;
}
public static LocalPack getLocal(File local) throws IOException {
if (lcache != null)
return lcache;
public static Config getConfig(File local) throws IOException {
Reader r = new FileReader(local);
LocalPack pack = LocalPack.fromJSON(r);
Config cfg = Config.fromJSON(r);
r.close();
lcache = pack;
return pack;
return cfg;
}
public static void writeLocal(File local) throws IOException {
Writer w = new FileWriter(local);
lcache.toJson(w);
w.close();
public static Version checkVersion(Config conf) {
GiteaAPI api = conf.getAPI();
List<Release> releases = api.getReleases();
return new Version(releases.get(0).tag, conf.version, releases.get(0).zipUrl);
}
public static String[] checkVersion(File local) throws IOException {
LocalPack lpack = getLocal(local);
public static String resolve(String url) {
try {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
con.setInstanceFollowRedirects(false);
int status = con.getResponseCode();
if (status == 301 || status == 302) {
String loc = con.getHeaderField("location");
return loc;
} else {
return url;
}
} catch (IOException e) {
return url;
}
}
RemotePack rpack = getRemote(lpack);
public static List<RelationFile> getRelations(AddonscriptJSON as) {
List<RelationFile> relations = new ArrayList<>();
Map<String, String> repos = new HashMap<>();
if (rpack != null && rpack.versions.contains(lpack.version)) {
int index = rpack.versions.indexOf(lpack.version);
int lastIndex = rpack.versions.size() - 1;
if (index == lastIndex) {
return new String[0];
} else {
String[] ret = new String[lastIndex - index];
int j = 0;
for (int i = index + 1; i <= lastIndex; i++) {
ret [j] = rpack.versions.get(i);
j++;
for (AddonscriptJSON.Repository r : as.repositories) {
String url = r.url;
if (!url.endsWith("/")) {
url += "/";
}
repos.put(r.id, url);
}
for (AddonscriptJSON.Relation r : as.versions.get(0).relations) {
if (r.type.equals("modloader"))
continue;
RelationFile rel = new RelationFile();
rel.id = r.id;
rel.dir = r.file.installer.split(":")[1];
if (r.file.link != null && !r.file.link.isEmpty()) {
rel.url = r.file.link;
} else {
String[] parts = r.file.artifact.split(":");
if (parts[0].equals("curse.maven")) {
parts[1] = parts[1] + "-" + parts[1];
}
return ret;
}
}
return new String[0];
}
public static VersionDiff buildDiff(String[] versions) throws IOException {
VersionDiff diff = new VersionDiff();
diff.add = new ArrayList<>();
diff.remove = new ArrayList<>();
RemotePack pack = getRemote(lcache);
for (String ver : versions) {
VersionDiff vdiff = pack.diff.get(ver);
if (vdiff != null) {
if (vdiff.remove != null) {
for (VersionDiff.RemoveFile f : vdiff.remove) {
boolean add = true;
List<VersionDiff.AddFile> toRem = new ArrayList<>();
for (VersionDiff.AddFile a : diff.add) {
if (a.dir.equals(f.dir) && a.filename.equals(f.filename)) {
add = false;
toRem.add(a);
}
}
diff.add.removeAll(toRem);
if (add)
diff.remove.add(f);
}
parts[0] = parts[0].replace('.', '/');
rel.url = repos.get(r.file.repository) + parts[0] + "/" + parts[1] + "/" + parts[2] + "/" + parts[1] + "-" + parts[2];
if (parts.length == 4) {
rel.url += "-";
rel.url += parts[3];
}
if (vdiff.add != null)
diff.add.addAll(vdiff.add);
rel.url += ".jar";
}
}
return diff;
relations.add(rel);
}
return relations;
}
public static URL getOverrides() {
if (rcache != null && rcache.overrides != null && !rcache.overrides.isEmpty()) {
try {
return new URL(rcache.overrides);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
return null;
public static List<RelationFile> getToRemove(List<RelationFile> old, List<RelationFile> newrel) {
List<RelationFile> oldRel = new ArrayList<>(old);
oldRel.removeAll(newrel);
return oldRel;
}
public static List<RelationFile> getToAdd(List<RelationFile> old, List<RelationFile> newrel) {
List<RelationFile> newRel = new ArrayList<>(newrel);
newRel.removeAll(old);
return newRel;
}
}

View file

@ -0,0 +1,31 @@
package ley.modding.tcu.model;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ley.modding.tcu.GiteaAPI;
import java.io.Reader;
import java.io.Writer;
public class Config {
private static Gson gson = new GsonBuilder().create();
public static Config fromJSON(Reader reader) {
return gson.fromJson(reader, Config.class);
}
public void toJson(Writer writer) {
gson.toJson(this, writer);
}
public String version;
public String giteaInstance;
public String owner;
public String repository;
public GiteaAPI getAPI() {
return new GiteaAPI(giteaInstance, owner, repository);
}
}

View file

@ -1,24 +0,0 @@
package ley.modding.tcu.model;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.Reader;
import java.io.Writer;
public class LocalPack {
private static Gson gson = new GsonBuilder().create();
public static LocalPack fromJSON(Reader reader) {
return gson.fromJson(reader, LocalPack.class);
}
public void toJson(Writer writer) {
gson.toJson(this, writer);
}
public String version;
public String packURL;
}

View file

@ -0,0 +1,37 @@
package ley.modding.tcu.model;
import ley.modding.tcu.Util;
import java.util.Objects;
public class RelationFile {
public String id;
public String dir;
private String filename = null;
public String url;
public String filename() {
if (filename == null) {
String url = Util.resolve(this.url);
String[] parts = url.split("/");
filename = parts[parts.length - 1];
}
return filename;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RelationFile that = (RelationFile) o;
return Objects.equals(id, that.id) &&
Objects.equals(dir, that.dir) &&
Objects.equals(url, that.url);
}
@Override
public int hashCode() {
return Objects.hash(id, dir, filename, url);
}
}

View file

@ -0,0 +1,22 @@
package ley.modding.tcu.model;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import java.io.Reader;
public class Release {
private static Gson gson = new GsonBuilder().create();
public static Release[] fromJSON(Reader reader) {
return gson.fromJson(reader, Release[].class);
}
@SerializedName("tag_name")
public String tag;
@SerializedName("zipball_url")
public String zipUrl;
}

View file

@ -1,22 +0,0 @@
package ley.modding.tcu.model;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.Reader;
import java.util.List;
import java.util.Map;
public class RemotePack {
private static Gson gson = new GsonBuilder().create();
public static RemotePack fromJSON(Reader reader) {
return gson.fromJson(reader, RemotePack.class);
}
public List<String> versions;
public String overrides;
public Map<String, VersionDiff> diff;
}

View file

@ -0,0 +1,19 @@
package ley.modding.tcu.model;
public class Version {
public String latest;
public String current;
public String overrides;
public Version(String latest, String current, String overrides) {
this.latest = latest;
this.current = current;
this.overrides = overrides;
}
public boolean isLatest() {
return latest.equals(current);
}
}

View file

@ -1,25 +0,0 @@
package ley.modding.tcu.model;
import java.util.List;
public class VersionDiff {
public List<RemoveFile> remove;
public List<AddFile> add;
public static class RemoveFile {
public String filename;
public String dir;
}
public static class AddFile {
public String url;
public String filename;
public String dir;
}
}