Skip to content

Commit

Permalink
new processing api + refactor fabric resources
Browse files Browse the repository at this point in the history
  • Loading branch information
CoolMineman committed Nov 3, 2021
1 parent fa90e73 commit e0bfc7e
Show file tree
Hide file tree
Showing 13 changed files with 395 additions and 79 deletions.
2 changes: 1 addition & 1 deletion brachyura/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>io.github.coolcrabs</groupId>
<artifactId>brachyura</artifactId>
<version>0.15</version>
<version>0.16</version>

<properties>
<java.version>1.8</java.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileVisitResult;
Expand All @@ -17,8 +18,10 @@
import java.security.MessageDigest;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -58,12 +61,20 @@
import io.github.coolcrabs.brachyura.maven.MavenId;
import io.github.coolcrabs.brachyura.minecraft.Minecraft;
import io.github.coolcrabs.brachyura.minecraft.VersionMeta;
import io.github.coolcrabs.brachyura.processing.ProcessingEntry;
import io.github.coolcrabs.brachyura.processing.ProcessingId;
import io.github.coolcrabs.brachyura.processing.ProcessingSink;
import io.github.coolcrabs.brachyura.processing.Processor;
import io.github.coolcrabs.brachyura.processing.ProcessorChain;
import io.github.coolcrabs.brachyura.processing.sinks.DirectoryProcessingSink;
import io.github.coolcrabs.brachyura.processing.sources.DirectoryProcessingSource;
import io.github.coolcrabs.brachyura.project.Task;
import io.github.coolcrabs.brachyura.project.java.BaseJavaProject;
import io.github.coolcrabs.brachyura.util.ArrayUtil;
import io.github.coolcrabs.brachyura.util.AtomicDirectory;
import io.github.coolcrabs.brachyura.util.AtomicFile;
import io.github.coolcrabs.brachyura.util.FileSystemUtil;
import io.github.coolcrabs.brachyura.util.GsonUtil;
import io.github.coolcrabs.brachyura.util.JvmUtil;
import io.github.coolcrabs.brachyura.util.Lazy;
import io.github.coolcrabs.brachyura.util.MessageDigestUtil;
Expand Down Expand Up @@ -306,90 +317,126 @@ public boolean build() {
}
}

//TODO better process resources api
@Override
public boolean processResources(Path source, Path target) throws IOException {
// If you think this is bad look at what loom does
Gson gson = new GsonBuilder().setPrettyPrinting().setLenient().create();
Path fmj = source.resolve("fabric.mod.json");
List<String> mixinjs = new ArrayList<>();
List<Path> mixinFiles = new ArrayList<>();
if (Files.isRegularFile(fmj)) {
JsonObject fabricModJson;
try (BufferedReader reader = PathUtil.newBufferedReader(fmj)) {
fabricModJson = gson.fromJson(reader, JsonObject.class);
public enum FMJRefmapApplier implements Processor {
INSTANCE;

@Override
public void process(Collection<ProcessingEntry> inputs, ProcessingSink sink) throws IOException {
HashMap<String, ProcessingEntry> entries = new HashMap<>();
for (ProcessingEntry e : inputs) {
entries.put(e.id.path, e);
}
fabricModJson.addProperty("version", getVersion());
JsonElement m = fabricModJson.get("mixins");
if (m instanceof JsonArray) {
JsonArray mixins = m.getAsJsonArray();
for (JsonElement a : mixins) {
if (a.isJsonPrimitive()) {
mixinjs.add(a.getAsString());
} else if (a.isJsonObject()) {
mixinjs.add(a.getAsJsonObject().get("config").getAsString());
} else {
throw new UnknownJsonException(a.toString());
}
ProcessingEntry fmj = entries.get("fabric.mod.json");
if (fmj != null) {
Gson gson = new GsonBuilder().setPrettyPrinting().setLenient().create();
List<String> mixinjs = new ArrayList<>();
JsonObject fabricModJson;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(fmj.in.get(), StandardCharsets.UTF_8))) {
fabricModJson = gson.fromJson(reader, JsonObject.class);
}
}
List<Path> jij = new ArrayList<>();
for (ModDependency modDependency : modDependencies.get()) {
if (modDependency.flags.contains(ModDependencyFlag.JIJ)) {
jij.add(modDependency.jarDependency.jar);
JsonElement m = fabricModJson.get("mixins");
if (m instanceof JsonArray) {
JsonArray mixins = m.getAsJsonArray();
for (JsonElement a : mixins) {
if (a.isJsonPrimitive()) {
mixinjs.add(a.getAsString());
} else if (a.isJsonObject()) {
mixinjs.add(a.getAsJsonObject().get("config").getAsString());
} else {
throw new UnknownJsonException(a.toString());
}
}
}
}
if (!jij.isEmpty()) {
JsonArray jars = new JsonArray();
fabricModJson.add("jars", jars);
List<String> used = new ArrayList<>();
for (Path jar : jij) {
String path = "META-INF/jars/" + jar.getFileName();
int a = 0;
while (used.contains(path)) {
path = "META-INF/jars/" + a + jar.getFileName();
for (String mixin : mixinjs) {
ProcessingEntry entry = entries.get(mixin);
entries.remove(mixin);
JsonObject mixinjson;
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entry.in.get(), StandardCharsets.UTF_8))) {
mixinjson = gson.fromJson(bufferedReader, JsonObject.class);
}
if (mixinjson.get("refmap") == null) {
mixinjson.addProperty("refmap", fabricModJson.get("id").getAsString() + "-refmap.json");
}
JsonObject o = new JsonObject();
o.addProperty("file", path);
jars.add(o);
used.add(path);
Path t = PathUtil.resolveAndCreateDir(target, path);
Files.copy(jar, t, StandardCopyOption.REPLACE_EXISTING);
sink.sink(() -> GsonUtil.toIs(mixinjson, gson), entry.id);
}
}
try (BufferedWriter jsonWriter = PathUtil.newBufferedWriter(target.resolve("fabric.mod.json"))) {
gson.toJson(fabricModJson, jsonWriter);
}
entries.forEach((k, v) -> sink.sink(v.in, v.id));
}
for (String mixin : mixinjs) {
Path mixinsource = source.resolve(mixin);
mixinFiles.add(mixinsource);
Path mixintarget = target.resolve(mixin);
JsonObject mixinjson;
try (BufferedReader bufferedReader = Files.newBufferedReader(mixinsource)) {
mixinjson = gson.fromJson(bufferedReader, JsonObject.class);
}
if (mixinjson.get("refmap") == null) {
mixinjson.addProperty("refmap", getModId() + "-refmap.json");
}
try (BufferedWriter jsonWriter = PathUtil.newBufferedWriter(mixintarget)) {
gson.toJson(mixinjson, jsonWriter);
}

public static class FmjJijApplier implements Processor {
final List<Path> jij;

public FmjJijApplier(List<Path> jij) {
this.jij = jij;
}

@Override
public void process(Collection<ProcessingEntry> inputs, ProcessingSink sink) throws IOException {
for (ProcessingEntry e : inputs) {
if (!jij.isEmpty() && "fabric.mod.json".equals(e.id.path)) {
Gson gson = new GsonBuilder().setPrettyPrinting().setLenient().create();
JsonObject fabricModJson;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(e.in.get(), StandardCharsets.UTF_8))) {
fabricModJson = gson.fromJson(reader, JsonObject.class);
}
JsonArray jars = new JsonArray();
fabricModJson.add("jars", jars);
List<String> used = new ArrayList<>();
for (Path jar : jij) {
String path = "META-INF/jars/" + jar.getFileName();
int a = 0;
while (used.contains(path)) {
path = "META-INF/jars/" + a + jar.getFileName();
a++;
}
JsonObject o = new JsonObject();
o.addProperty("file", path);
jars.add(o);
used.add(path);
sink.sink(() -> PathUtil.inputStream(jar), new ProcessingId(path, e.id.source));
}
sink.sink(() -> GsonUtil.toIs(fabricModJson, gson), e.id);
} else {
sink.sink(e.in, e.id);
}
}
}
boolean[] result = new boolean[] {true};
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
// Skip fmj and mixin files (already copied)
if (file.equals(fmj) || mixinFiles.contains(file) || processResource(source.relativize(file), file, target)) {
return FileVisitResult.CONTINUE;
}

public class FmjMiscProcessor implements Processor {
@Override
public void process(Collection<ProcessingEntry> inputs, ProcessingSink sink) throws IOException {
for (ProcessingEntry e : inputs) {
if ("fabric.mod.json".equals(e.id.path)) {
Gson gson = new GsonBuilder().setPrettyPrinting().setLenient().create();
JsonObject fabricModJson;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(e.in.get(), StandardCharsets.UTF_8))) {
fabricModJson = gson.fromJson(reader, JsonObject.class);
}
fabricModJson.addProperty("version", getVersion());
if (!getModId().equals(fabricModJson.get("id").getAsString())) {
throw new IllegalArgumentException("Modid in fabric.mod.json not the same as buildscript");
}
sink.sink(() -> GsonUtil.toIs(fabricModJson, gson), e.id);
} else {
result[0] = false;
return FileVisitResult.TERMINATE;
sink.sink(e.in, e.id);
}
}
});
return result[0];
}
}

@Override
public boolean processResources(Path source, Path target) throws IOException {
List<Path> jij = new ArrayList<>();
for (ModDependency modDependency : modDependencies.get()) {
if (modDependency.flags.contains(ModDependencyFlag.JIJ)) {
jij.add(modDependency.jarDependency.jar);
}
}
ProcessorChain c = new ProcessorChain(new FmjMiscProcessor(), FMJRefmapApplier.INSTANCE, new FmjJijApplier(jij));
c.apply(new DirectoryProcessingSink(target), new DirectoryProcessingSource(source));
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.coolcrabs.brachyura.processing;

import java.io.InputStream;
import java.util.function.Supplier;

public class ProcessingEntry {
public final Supplier<InputStream> in;
public final ProcessingId id;

public ProcessingEntry(Supplier<InputStream> in, ProcessingId id) {
this.in = in;
this.id = id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.coolcrabs.brachyura.processing;

public final class ProcessingId {
public final String path;
public final ProcessingSource source;

public ProcessingId(String path, ProcessingSource source) {
this.path = path;
this.source = source;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.coolcrabs.brachyura.processing;

import java.io.InputStream;
import java.util.function.Supplier;

public interface ProcessingSink {
public void sink(Supplier<InputStream> in, ProcessingId id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.coolcrabs.brachyura.processing;

public abstract class ProcessingSource {
public abstract void getInputs(ProcessingSink sink);

@Override
public final boolean equals(Object obj) {
return super.equals(obj);
}

@Override
public final int hashCode() {
return super.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.coolcrabs.brachyura.processing;

import java.io.IOException;
import java.util.Collection;

public interface Processor {
void process(Collection<ProcessingEntry> inputs, ProcessingSink sink) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.github.coolcrabs.brachyura.processing;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Supplier;

import io.github.coolcrabs.brachyura.util.Util;

public class ProcessorChain {
final Processor[] processors;

public ProcessorChain(Processor...processors) {
this.processors = processors;
}

public void apply(ProcessingSink out, ProcessingSource... in) {
try {
Collector c = new Collector();
for (ProcessingSource s : in) {
s.getInputs(c);
}
for (Processor p : processors) {
Collector c2 = new Collector();
p.process(c.e, c2);
c = c2;
}
for (ProcessingEntry pe : c.e) {
out.sink(pe.in, pe.id);
}
} catch (IOException e) {
Util.sneak(e);
}
}

static class Collector implements ProcessingSink {
ConcurrentLinkedQueue<ProcessingEntry> e = new ConcurrentLinkedQueue<>();

@Override
public void sink(Supplier<InputStream> in, ProcessingId id) {
e.add(new ProcessingEntry(in, id));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.github.coolcrabs.brachyura.processing.sinks;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Supplier;

import io.github.coolcrabs.brachyura.processing.ProcessingId;
import io.github.coolcrabs.brachyura.processing.ProcessingSink;
import io.github.coolcrabs.brachyura.util.Util;

public class DirectoryProcessingSink implements ProcessingSink {
final Path path;

public DirectoryProcessingSink(Path path) {
this.path = path;
}

@Override
public void sink(Supplier<InputStream> in, ProcessingId id) {
try {
Path target = path.resolve(id.path);
Path parent = target.getParent();
if (parent != null) {
Files.createDirectories(parent);
}
try (InputStream i = in.get()) {
Files.copy(i, target);
}
} catch (IOException e) {
throw Util.sneak(e);
}
}
}
Loading

0 comments on commit e0bfc7e

Please sign in to comment.