chore(config-compiler-plugin): Remove deprecated gradle plugin. Use the new javac plugin instead!
This commit is contained in:
parent
e4d510f164
commit
e7bfc67bf5
|
@ -1,49 +0,0 @@
|
|||
import io.gitlab.jfronny.scripts.*
|
||||
import javax.lang.model.element.Modifier.*
|
||||
|
||||
plugins {
|
||||
id("java-gradle-plugin")
|
||||
id("jf.maven-publish")
|
||||
id("jf.codegen")
|
||||
}
|
||||
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://maven.frohnmeyer-wds.de/artifacts")
|
||||
maven("https://maven.fabricmc.net/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(gradleApi())
|
||||
implementation("org.apache.ant:ant:${prop("ant_version")}")
|
||||
implementation("io.gitlab.jfronny:commons-gson:${prop("commons_version")}")
|
||||
implementation("org.ow2.asm:asm:${prop("asm_version")}")
|
||||
implementation("org.ow2.asm:asm-commons:${prop("asm_version")}")
|
||||
implementation(project(":libjf-config-core-v1")) { isTransitive = false }
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create("simplePlugin") {
|
||||
id = "io.gitlab.jfronny.libjf.libjf-config-compiler-plugin"
|
||||
implementationClass = "io.gitlab.jfronny.libjf.config.plugin.ConfigPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.publish.get().dependsOn(tasks.build.get())
|
||||
rootProject.tasks.deployDebug.dependsOn(tasks.publish.get())
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
generate(project) {
|
||||
`class`("io.gitlab.jfronny.libjf.config.plugin", "BuildMetadata") {
|
||||
modifiers(PUBLIC)
|
||||
field("IS_RELEASE", project.hasProperty("release"), PUBLIC, STATIC, FINAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.ZipCompressor;
|
||||
import org.apache.tools.zip.ZipOutputStream;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.internal.file.copy.CopyAction;
|
||||
import org.gradle.api.internal.file.copy.CopyActionProcessingStream;
|
||||
import org.gradle.api.tasks.WorkResult;
|
||||
import org.gradle.api.tasks.WorkResults;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class ConfigInjectCopyAction implements CopyAction {
|
||||
private final File zipFile;
|
||||
private final ZipCompressor compressor;
|
||||
private final String encoding;
|
||||
private final boolean preserveFileTimestamps;
|
||||
private final String modId;
|
||||
private final Set<Type> knownConfigClasses = new HashSet<>();
|
||||
|
||||
public ConfigInjectCopyAction(File zipFile,
|
||||
ZipCompressor compressor,
|
||||
String encoding,
|
||||
boolean preserveFileTimestamps,
|
||||
String modId) {
|
||||
this.zipFile = zipFile;
|
||||
this.compressor = compressor;
|
||||
this.encoding = encoding;
|
||||
this.preserveFileTimestamps = preserveFileTimestamps;
|
||||
this.modId = modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkResult execute(CopyActionProcessingStream stream) {
|
||||
try (ZipOutputStream zipOutStr = compressor.createArchiveOutputStream(zipFile)) {
|
||||
if (encoding != null) {
|
||||
zipOutStr.setEncoding(encoding);
|
||||
}
|
||||
AtomicBoolean fmjFound = new AtomicBoolean(false);
|
||||
stream.process(details -> fmjFound.compareAndSet(false,
|
||||
new StreamAction(zipOutStr, zipFile, preserveFileTimestamps, modId, knownConfigClasses)
|
||||
.processFile(details)
|
||||
));
|
||||
} catch (IOException e) {
|
||||
throw new GradleException("Could not create ZIP " + zipFile, e);
|
||||
}
|
||||
return WorkResults.didWork(true);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.GradleVersionUtil;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.ZipCompressor;
|
||||
import org.gradle.api.file.DuplicatesStrategy;
|
||||
import org.gradle.api.internal.file.copy.CopyAction;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.bundling.Jar;
|
||||
|
||||
public abstract class ConfigInjectTask extends Jar {
|
||||
@Input
|
||||
public abstract Property<String> getModId();
|
||||
private final GradleVersionUtil versionUtil;
|
||||
|
||||
public ConfigInjectTask() {
|
||||
super();
|
||||
setDuplicatesStrategy(DuplicatesStrategy.FAIL);
|
||||
versionUtil = new GradleVersionUtil(getProject().getGradle().getGradleVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CopyAction createCopyAction() {
|
||||
return new ConfigInjectCopyAction(
|
||||
getArchiveFile().get().getAsFile(),
|
||||
getInternalCompressor(),
|
||||
this.getMetadataCharset(),
|
||||
isPreserveFileTimestamps(),
|
||||
getModId().get()
|
||||
);
|
||||
}
|
||||
|
||||
@Internal
|
||||
protected ZipCompressor getInternalCompressor() {
|
||||
return versionUtil.getInternalCompressor(getEntryCompression(), this);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.BasePluginExtension;
|
||||
import org.gradle.api.tasks.bundling.Jar;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ConfigPlugin implements Plugin<Project> {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getTasks().register("injectCompiledConfig", ConfigInjectTask.class, task -> {
|
||||
task.from(project.getTasks().named("jar", Jar.class));
|
||||
task.getModId().set(project.getExtensions().getByType(BasePluginExtension.class).getArchivesName());
|
||||
task.getArchiveClassifier().set("config-inject");
|
||||
task.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs"));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin;
|
||||
|
||||
import io.gitlab.jfronny.gson.stream.JsonReader;
|
||||
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.NotAConfigClassException;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.fmj.FabricModJsonTransformer;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.*;
|
||||
import org.apache.tools.zip.*;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.file.FileCopyDetails;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class StreamAction {
|
||||
private static final long CONSTANT_TIME_FOR_ZIP_ENTRIES = (new GregorianCalendar(1980, 1, 1, 0, 0, 0)).getTimeInMillis();
|
||||
private final ZipOutputStream zipOutStr;
|
||||
private final File zipFile;
|
||||
private final boolean preserveFileTimestamps;
|
||||
private final String modId;
|
||||
private final Set<Type> knownConfigClasses;
|
||||
|
||||
public StreamAction(ZipOutputStream zipOutStr, File zipFile, boolean preserveFileTimestamps, String modId, Set<Type> knownConfigClasses) {
|
||||
this.zipOutStr = zipOutStr;
|
||||
this.zipFile = zipFile;
|
||||
this.preserveFileTimestamps = preserveFileTimestamps;
|
||||
this.modId = modId;
|
||||
this.knownConfigClasses = knownConfigClasses;
|
||||
}
|
||||
|
||||
public boolean processFile(FileCopyDetails details) {
|
||||
try {
|
||||
if (details.isDirectory()) {
|
||||
visitDirectory(details);
|
||||
return false;
|
||||
} else {
|
||||
return visitFile(details);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new GradleException("Could not add " + details + " to ZIP " + zipFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitDirectory(FileCopyDetails details) throws IOException {
|
||||
String path = details.getRelativePath().getPathString() + "/";
|
||||
ZipEntry archiveEntry = new ZipEntry(path);
|
||||
archiveEntry.setTime(getArchiveTimeFor(details.getLastModified()));
|
||||
archiveEntry.setUnixMode(UnixStat.DIR_FLAG | details.getMode());
|
||||
zipOutStr.putNextEntry(archiveEntry);
|
||||
zipOutStr.closeEntry();
|
||||
}
|
||||
|
||||
private boolean visitFile(FileCopyDetails details) throws IOException {
|
||||
if (details.getPath().endsWith(".jar")) {
|
||||
return processArchive(details);
|
||||
} else if (details.getPath().endsWith(".class")) {
|
||||
processClass(details);
|
||||
} else if (details.getPath().equals("fabric.mod.json")) {
|
||||
processFMJ(details);
|
||||
return true;
|
||||
} else {
|
||||
ZipEntry archiveEntry = new ZipEntry(details.getRelativePath().getPathString());
|
||||
archiveEntry.setTime(getArchiveTimeFor(details.getLastModified()));
|
||||
archiveEntry.setUnixMode(UnixStat.FILE_FLAG | details.getMode());
|
||||
zipOutStr.putNextEntry(archiveEntry);
|
||||
details.copyTo(zipOutStr);
|
||||
zipOutStr.closeEntry();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean processArchive(FileCopyDetails details) throws IOException {
|
||||
try (ZipFile archive = new ZipFile(details.getFile())) {
|
||||
AtomicBoolean fmjFound = new AtomicBoolean(false);
|
||||
EnumerationSpliterator.stream(archive.getEntries())
|
||||
.map(RelativeArchivePath::new)
|
||||
.map(ArchiveFileTreeElement::new)
|
||||
.filter(it -> it.getRelativePath().isFile())
|
||||
.forEach(archiveElement -> {
|
||||
fmjFound.compareAndSet(false, visitArchiveFile(archiveElement, archive));
|
||||
});
|
||||
return fmjFound.get();
|
||||
}
|
||||
}
|
||||
|
||||
private void visitArchiveDirectory(RelativeArchivePath archiveDir) throws IOException {
|
||||
zipOutStr.putNextEntry(archiveDir.entry);
|
||||
zipOutStr.closeEntry();
|
||||
}
|
||||
|
||||
private boolean visitArchiveFile(ArchiveFileTreeElement archiveFile, ZipFile archive) {
|
||||
RelativeArchivePath archiveFilePath = archiveFile.getRelativePath();
|
||||
try {
|
||||
if (archiveFile.isClassFile()) {
|
||||
processClass(archiveFilePath, archive);
|
||||
} else if (archiveFilePath.getPathString().equals("fabric.mod.json")) {
|
||||
processFMJ(archiveFilePath, archive);
|
||||
return true;
|
||||
} else {
|
||||
copyArchiveEntry(archiveFilePath, archive);
|
||||
}
|
||||
return false;
|
||||
} catch (Throwable e) {
|
||||
throw new GradleException("Could not read archive entry " + archiveFilePath.getPathString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyArchiveEntry(RelativeArchivePath archiveFile, ZipFile archive) throws IOException {
|
||||
ZipEntry entry = new ZipEntry(archiveFile.entry.getName());
|
||||
entry.setTime(getArchiveTimeFor(archiveFile.entry.getTime()));
|
||||
RelativeArchivePath path = new RelativeArchivePath(entry);
|
||||
addParentDirectories(path);
|
||||
zipOutStr.putNextEntry(path.entry);
|
||||
try (InputStream is = archive.getInputStream(archiveFile.entry)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int n;
|
||||
while (-1 != (n = is.read(buffer))) {
|
||||
zipOutStr.write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
zipOutStr.closeEntry();
|
||||
}
|
||||
|
||||
private void addParentDirectories(RelativeArchivePath file) throws IOException {
|
||||
if (file != null) {
|
||||
addParentDirectories(file.getParent());
|
||||
if (!file.isFile()) {
|
||||
visitArchiveDirectory(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processClass(RelativeArchivePath file, ZipFile archive) throws IOException {
|
||||
ZipEntry zipEntry = new ZipEntry(file.getPathString());
|
||||
addParentDirectories(new RelativeArchivePath(zipEntry));
|
||||
processClass(archive.getInputStream(file.entry).readAllBytes(), file.getPathString(), file.entry.getTime());
|
||||
}
|
||||
|
||||
private void processClass(FileCopyDetails details) throws IOException {
|
||||
try (InputStream is = new FileInputStream(details.getFile())) {
|
||||
processClass(is.readAllBytes(), details.getPath(), details.getLastModified());
|
||||
}
|
||||
}
|
||||
|
||||
private void processClass(byte[] klazz, String path, long lastModified) throws IOException {
|
||||
try {
|
||||
final ClassReader reader = new ClassReader(klazz);
|
||||
final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
|
||||
final ConfigInjectClassTransformer transformer = new ConfigInjectClassTransformer(modId, writer, knownConfigClasses);
|
||||
reader.accept(transformer, ClassReader.EXPAND_FRAMES);
|
||||
klazz = writer.toByteArray();
|
||||
System.out.println("Injected config registration into " + path);
|
||||
} catch (NotAConfigClassException notAConfigClass) {
|
||||
// Use original bytes
|
||||
}
|
||||
ZipEntry archiveEntry = new ZipEntry(path);
|
||||
archiveEntry.setTime(getArchiveTimeFor(lastModified));
|
||||
zipOutStr.putNextEntry(archiveEntry);
|
||||
zipOutStr.write(klazz);
|
||||
zipOutStr.closeEntry();
|
||||
}
|
||||
|
||||
private void processFMJ(RelativeArchivePath file, ZipFile archive) throws IOException {
|
||||
ZipEntry zipEntry = new ZipEntry(file.getPathString());
|
||||
addParentDirectories(new RelativeArchivePath(zipEntry));
|
||||
processFMJ(archive.getInputStream(file.entry), file.getPathString(), file.entry.getTime());
|
||||
}
|
||||
|
||||
private void processFMJ(FileCopyDetails details) throws IOException {
|
||||
try (InputStream is = new FileInputStream(details.getFile())) {
|
||||
processFMJ(is, details.getPath(), details.getLastModified());
|
||||
}
|
||||
}
|
||||
|
||||
private void processFMJ(InputStream fmj, String path, long lastModified) throws IOException {
|
||||
ZipEntry archiveEntry = new ZipEntry(path);
|
||||
archiveEntry.setTime(getArchiveTimeFor(lastModified));
|
||||
zipOutStr.putNextEntry(archiveEntry);
|
||||
// Leave this closeable open, as everything else will break the writer
|
||||
|
||||
try (JsonReader reader = new JsonReader(new InputStreamReader(fmj));
|
||||
JsonWriter writer = new JsonWriter(new OutputStreamWriter(new DelegatingUncloseableOutputStream(zipOutStr)))) {
|
||||
FabricModJsonTransformer.transform(reader, writer, knownConfigClasses);
|
||||
}
|
||||
zipOutStr.closeEntry();
|
||||
}
|
||||
|
||||
private long getArchiveTimeFor(long timestamp) {
|
||||
return preserveFileTimestamps ? timestamp : CONSTANT_TIME_FOR_ZIP_ENTRIES;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class AnnotationMetaGatheringVisitor extends AnnotationVisitor {
|
||||
private final List<String> referencedConfigs;
|
||||
|
||||
public AnnotationMetaGatheringVisitor(AnnotationVisitor annotationVisitor, List<String> referencedConfigs) {
|
||||
super(ASM9, annotationVisitor);
|
||||
this.referencedConfigs = referencedConfigs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
return switch (name) {
|
||||
case "referencedConfigs" -> new ArrayVisitor<>(super.visitArray(name), referencedConfigs);
|
||||
default -> throw new GradleException("Unknown field in category or JfConfig annotation: " + name);
|
||||
};
|
||||
}
|
||||
|
||||
private static class ArrayVisitor<T> extends AnnotationVisitor {
|
||||
private final List<T> target;
|
||||
|
||||
protected ArrayVisitor(AnnotationVisitor annotationVisitor, List<T> target) {
|
||||
super(ASM9, annotationVisitor);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
super.visit(name, value);
|
||||
target.add((T) value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.Category;
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.JfConfig;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.BuildMetadata;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.value.DiscoveredValue;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.ClInitInjectVisitor;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.GeneratorAdapter2;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.GeneratorAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static io.gitlab.jfronny.libjf.config.plugin.asm.value.KnownTypes.*;
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static org.objectweb.asm.Type.*;
|
||||
|
||||
public class ConfigInjectClassTransformer extends ClassVisitor {
|
||||
// Field names
|
||||
public static final String PREFIX = "libjf$config$";
|
||||
public static final String INIT_METHOD = PREFIX + "clinit";
|
||||
public static final String REGISTER_METHOD = PREFIX + "register";
|
||||
public static final String BUILDER_ROOT = PREFIX + "root";
|
||||
public static final String CLINIT = "<clinit>";
|
||||
// Transformation metadata
|
||||
public final String modId;
|
||||
public Type current;
|
||||
private final Set<Type> knownConfigClasses;
|
||||
// Transformer state
|
||||
private final List<String> categories = new LinkedList<>();
|
||||
private final List<String> referencedConfigs = new LinkedList<>();
|
||||
private final List<String> presets = new LinkedList<>();
|
||||
private final List<String> verifiers = new LinkedList<>();
|
||||
private final List<DiscoveredValue> values = new LinkedList<>();
|
||||
private boolean initFound = false;
|
||||
private TransformerMode mode;
|
||||
|
||||
public boolean isCategory() {
|
||||
return mode == TransformerMode.CONFIG_CATEGORY || isConfig();
|
||||
}
|
||||
|
||||
public void ensureCategory() {
|
||||
if (!isCategory()) throw new NotAConfigClassException();
|
||||
}
|
||||
|
||||
public boolean isConfig() {
|
||||
return mode == TransformerMode.CONFIG_ROOT;
|
||||
}
|
||||
|
||||
public boolean isOther() {
|
||||
return mode == TransformerMode.OTHER;
|
||||
}
|
||||
|
||||
public ConfigInjectClassTransformer(String modId, ClassVisitor cw, Set<Type> knownConfigClasses) {
|
||||
super(ASM9, cw);
|
||||
this.modId = modId;
|
||||
this.knownConfigClasses = knownConfigClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
this.current = Type.getType('L' + name + ';');
|
||||
mode = TransformerMode.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
||||
if (mode == null) throw new IllegalStateException("Attempted to visit annotation before class");
|
||||
if (descriptor.equals(Type.getDescriptor(Category.class)) && isOther()) {
|
||||
mode = TransformerMode.CONFIG_CATEGORY;
|
||||
return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs);
|
||||
}
|
||||
else if (descriptor.equals(Type.getDescriptor(JfConfig.class)) && isOther()) {
|
||||
mode = TransformerMode.CONFIG_ROOT;
|
||||
knownConfigClasses.add(current);
|
||||
return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs);
|
||||
} else {
|
||||
return super.visitAnnotation(descriptor, visible);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestMember(String nestMember) {
|
||||
ensureCategory();
|
||||
categories.add(nestMember);
|
||||
super.visitNestMember(nestMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
ensureCategory();
|
||||
if (isConfig()) {
|
||||
if (CLINIT.equals(name)) {
|
||||
initFound = true;
|
||||
return new ClInitInjectVisitor(
|
||||
super.visitMethod(access, name, descriptor, signature, exceptions),
|
||||
current.getInternalName(),
|
||||
INIT_METHOD,
|
||||
"()V"
|
||||
);
|
||||
}
|
||||
}
|
||||
if (name.startsWith(PREFIX)) {
|
||||
throw new GradleException("This class declares methods generated by this plugin manually. Do not transform classes twice!");
|
||||
}
|
||||
if ((access & ACC_STATIC) == ACC_STATIC) {
|
||||
// Possibly add verifier or preset
|
||||
return new MethodMetaGatheringVisitor(
|
||||
super.visitMethod(access, name, descriptor, signature, exceptions),
|
||||
name, presets, verifiers);
|
||||
}
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||
ensureCategory();
|
||||
if ((access & ACC_STATIC) == ACC_STATIC) {
|
||||
return new FieldMetaGatheringVisitor(super.visitField(access, name, descriptor, signature, value), name, values, Type.getType(descriptor));
|
||||
}
|
||||
return super.visitField(access, name, descriptor, signature, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
ensureCategory();
|
||||
if (isConfig()) {
|
||||
if (!initFound) {
|
||||
// Generate <clinit> if missing
|
||||
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, CLINIT, "()V", null, null);
|
||||
m.invokeStatic(current, new Method(INIT_METHOD, "()V"));
|
||||
m.returnValue();
|
||||
m.endMethod();
|
||||
}
|
||||
// Generate main method
|
||||
{
|
||||
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, INIT_METHOD, "()V", null, null);
|
||||
|
||||
m.comment("Migrate files from old paths");
|
||||
m.invokeIStatic(CONFIG_HOLDER_TYPE, new Method("getInstance", CONFIG_HOLDER_TYPE, new Type[0]));
|
||||
m.push(modId);
|
||||
m.invokeInterface(CONFIG_HOLDER_TYPE, new Method("migrateFiles", "(Ljava/lang/String;)V"));
|
||||
|
||||
m.comment("Invoke DSL, continue in " + BUILDER_ROOT);
|
||||
m.push(modId);
|
||||
m.invokeIStatic(DSL_TYPE, new Method("create", DSL_DEFAULTED_TYPE, new Type[]{STRING_TYPE}));
|
||||
m.λ("apply",
|
||||
getMethodDescriptor(CONFIG_BUILDER_FUNCTION_TYPE),
|
||||
getMethodType(CONFIG_BUILDER_TYPE, CONFIG_BUILDER_TYPE),
|
||||
current.getInternalName(),
|
||||
BUILDER_ROOT);
|
||||
|
||||
m.invokeInterface(DSL_DEFAULTED_TYPE, new Method("config", CONFIG_INSTANCE_TYPE, new Type[]{CONFIG_BUILDER_FUNCTION_TYPE}));
|
||||
m.pop();
|
||||
m.returnValue();
|
||||
m.endMethod();
|
||||
}
|
||||
// Generate register method for impl
|
||||
// This method does nothing but is needed to properly implement the interface
|
||||
// This also ensures the static initializer is called
|
||||
{
|
||||
GeneratorAdapter2 m = method(ACC_PUBLIC | ACC_STATIC, REGISTER_METHOD, getMethodDescriptor(VOID_TYPE, DSL_DEFAULTED_TYPE), null, null);
|
||||
m.comment("This placeholder method is referenced in the FMJ to ensure the static initializer is called");
|
||||
m.returnValue();
|
||||
m.endMethod();
|
||||
}
|
||||
}
|
||||
{
|
||||
Type builderType = isConfig() ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE;
|
||||
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, BUILDER_ROOT, getMethodDescriptor(builderType, builderType), null, null);
|
||||
m.loadArg(0);
|
||||
for (String name : referencedConfigs) {
|
||||
m.comment("Reference the config of \"" + name + "\"");
|
||||
m.push(name);
|
||||
dslInvoke(m, "referenceConfig", CATEGORY_BUILDER_TYPE, STRING_TYPE);
|
||||
}
|
||||
for (String name : categories) {
|
||||
m.comment("Register the category defined in " + name);
|
||||
m.push(camelCase(name.substring(current.getInternalName().length())));
|
||||
m.λ("apply",
|
||||
getMethodDescriptor(CATEGORY_BUILDER_FUNCTION_TYPE),
|
||||
getMethodType(CATEGORY_BUILDER_TYPE, CATEGORY_BUILDER_TYPE),
|
||||
name,
|
||||
BUILDER_ROOT);
|
||||
dslInvoke(m, "category", CATEGORY_BUILDER_TYPE, STRING_TYPE, CATEGORY_BUILDER_FUNCTION_TYPE);
|
||||
}
|
||||
for (String verifier : verifiers) {
|
||||
m.comment("Register the verifier \"" + verifier + "\"");
|
||||
m.runnable(current.getInternalName(), verifier);
|
||||
dslInvoke(m, "addVerifier", CATEGORY_BUILDER_TYPE, RUNNABLE_TYPE);
|
||||
}
|
||||
for (String preset : presets) {
|
||||
m.comment("Register the preset \"" + preset + "\"");
|
||||
m.push(preset);
|
||||
m.runnable(current.getInternalName(), preset);
|
||||
dslInvoke(m, "addPreset", CATEGORY_BUILDER_TYPE, STRING_TYPE, RUNNABLE_TYPE);
|
||||
}
|
||||
for (DiscoveredValue value : values) {
|
||||
m.comment("Register the value \"" + value + "\"");
|
||||
value.generateRegistration(m, this);
|
||||
}
|
||||
m.returnValue();
|
||||
m.endMethod();
|
||||
for (DiscoveredValue value : values) {
|
||||
value.generateλ(this);
|
||||
}
|
||||
}
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
public void dslInvoke(GeneratorAdapter m, String name, Type returnType, Type... arguments) {
|
||||
Type builderType = isConfig() ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE;
|
||||
m.invokeInterface(builderType, new Method(name, returnType, arguments));
|
||||
if (isConfig()) m.checkCast(CONFIG_BUILDER_TYPE);
|
||||
}
|
||||
|
||||
private String camelCase(String s) {
|
||||
return Character.toLowerCase(s.charAt(0)) + s.substring(1);
|
||||
}
|
||||
|
||||
public GeneratorAdapter2 method(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
if (BuildMetadata.IS_RELEASE && !name.equals(CLINIT)) access |= ACC_SYNTHETIC;
|
||||
return new GeneratorAdapter2(super.visitMethod(access, name, descriptor, signature, exceptions), access, name, descriptor);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.Entry;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.value.DiscoveredValue;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class FieldMetaGatheringVisitor extends FieldVisitor {
|
||||
private final String name;
|
||||
private final List<DiscoveredValue> values;
|
||||
private final Type type;
|
||||
|
||||
protected FieldMetaGatheringVisitor(FieldVisitor fieldVisitor, String name, List<DiscoveredValue> values, Type type) {
|
||||
super(ASM9, fieldVisitor);
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
||||
if (descriptor.equals(Type.getDescriptor(Entry.class))) {
|
||||
return new MetaGatheringAnnotationVisitor(super.visitAnnotation(descriptor, visible));
|
||||
}
|
||||
return super.visitAnnotation(descriptor, visible);
|
||||
}
|
||||
|
||||
public class MetaGatheringAnnotationVisitor extends AnnotationVisitor {
|
||||
private double min = Double.NEGATIVE_INFINITY;
|
||||
private double max = Double.POSITIVE_INFINITY;
|
||||
protected MetaGatheringAnnotationVisitor(AnnotationVisitor annotationVisitor) {
|
||||
super(ASM9, annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
super.visit(name, value);
|
||||
switch (name) {
|
||||
case "min" -> {
|
||||
min = (Double)value;
|
||||
}
|
||||
case "max" -> {
|
||||
max = (Double)value;
|
||||
}
|
||||
case "width" -> {}
|
||||
default -> throw new IllegalArgumentException("Unexpected name in @Entry annotation: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
values.add(new DiscoveredValue(name, min, max, type));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.Preset;
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.Verifier;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class MethodMetaGatheringVisitor extends MethodVisitor {
|
||||
private final String name;
|
||||
private final List<String> presets;
|
||||
private final List<String> verifiers;
|
||||
protected MethodMetaGatheringVisitor(MethodVisitor methodVisitor, String name, List<String> presets, List<String> verifiers) {
|
||||
super(ASM9, methodVisitor);
|
||||
this.name = name;
|
||||
this.presets = presets;
|
||||
this.verifiers = verifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
||||
if (descriptor.equals(Type.getDescriptor(Preset.class))) {
|
||||
presets.add(name);
|
||||
}
|
||||
if (descriptor.equals(Type.getDescriptor(Verifier.class))) {
|
||||
verifiers.add(name);
|
||||
}
|
||||
return super.visitAnnotation(descriptor, visible);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm;
|
||||
|
||||
public class NotAConfigClassException extends RuntimeException {
|
||||
public NotAConfigClassException() {
|
||||
super("This class is not a config class and should not be modified");
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm;
|
||||
|
||||
public enum TransformerMode {
|
||||
CONFIG_ROOT, CONFIG_CATEGORY, OTHER
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm.value;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.util.GeneratorAdapter2;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import static io.gitlab.jfronny.libjf.config.plugin.asm.value.KnownTypes.*;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static org.objectweb.asm.Type.*;
|
||||
|
||||
public class DiscoveredValue {
|
||||
private static final String PREFIX = ConfigInjectClassTransformer.PREFIX;
|
||||
|
||||
public final String name;
|
||||
public final double min;
|
||||
public final double max;
|
||||
public final Type aType;
|
||||
public final KnownType type;
|
||||
|
||||
public DiscoveredValue(String name, double min, double max, Type type) {
|
||||
this.name = name;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.aType = type;
|
||||
this.type = KnownType.of(type);
|
||||
}
|
||||
|
||||
public void generateRegistration(GeneratorAdapter2 m, ConfigInjectClassTransformer t) {
|
||||
if (type != KnownType.OBJECT) {
|
||||
m.push(name);
|
||||
m.getStatic(t.current, name, aType);
|
||||
if (!aType.equals(type.unboxed)) {
|
||||
m.comment("Unboxing value " + name + " from " + aType + " to " + type.unboxed);
|
||||
m.unbox(type.unboxed); // Unbox (as parameter is unboxed) or leave as is (if target is unboxed)
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case INT, LONG, FLOAT, DOUBLE -> {
|
||||
m.comment("Numeric type");
|
||||
m.push(min);
|
||||
m.push(max);
|
||||
m.supplier(t.current.getInternalName(), gName(), gDesc());
|
||||
m.consumer(t.current.getInternalName(), sName(), sDesc());
|
||||
t.dslInvoke(m, "value", CATEGORY_BUILDER_TYPE, STRING_TYPE, type.unboxed, DOUBLE_TYPE, DOUBLE_TYPE, SUPPLIER_TYPE, CONSUMER_TYPE);
|
||||
}
|
||||
case BOOLEAN, STRING -> {
|
||||
m.comment("Simple one-value type");
|
||||
m.supplier(t.current.getInternalName(), gName(), gDesc());
|
||||
m.consumer(t.current.getInternalName(), sName(), sDesc());
|
||||
t.dslInvoke(m, "value", CATEGORY_BUILDER_TYPE, STRING_TYPE, type.unboxed, SUPPLIER_TYPE, CONSUMER_TYPE);
|
||||
}
|
||||
case OBJECT -> {
|
||||
System.err.println("WARNING: Attempted to use unsupported type in config. The entry \"" + name + "\" will fall back to reflective runtime access!");
|
||||
m.comment("Reflective access due to missing compatibility for the type \"" + aType + "\"");
|
||||
m.push(t.current);
|
||||
m.push(name);
|
||||
m.invokeIStatic(ENTRY_INFO_TYPE, new Method("ofField", ENTRY_INFO_TYPE, new Type[]{CLASS_TYPE, STRING_TYPE}));
|
||||
m.invokeInterface(CATEGORY_BUILDER_TYPE, new Method("value", CATEGORY_BUILDER_TYPE, new Type[]{ENTRY_INFO_TYPE}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateλ(ConfigInjectClassTransformer t) {
|
||||
GeneratorAdapter2 m = t.method(ACC_PRIVATE | ACC_STATIC, gName(), gDesc().getInternalName(), null, null);
|
||||
m.getStatic(t.current, name, aType);
|
||||
m.comment("Boxing from " + aType + " (" + aType.getSort() + ")");
|
||||
m.box(aType); // Box if target field uses unboxed value
|
||||
m.returnValue();
|
||||
m.endMethod();
|
||||
|
||||
m = t.method(ACC_PRIVATE | ACC_STATIC, sName(), sDesc().getInternalName(), null, null);
|
||||
m.loadArg(0);
|
||||
m.unbox(aType); // Unbox to the target fields type
|
||||
m.putStatic(t.current, name, aType);
|
||||
m.returnValue();
|
||||
m.endMethod();
|
||||
}
|
||||
|
||||
private String gName() {
|
||||
return PREFIX + "get$" + name;
|
||||
}
|
||||
|
||||
private Type gDesc() {
|
||||
return getMethodType(type.boxed);
|
||||
}
|
||||
|
||||
private String sName() {
|
||||
return PREFIX + "set$" + name;
|
||||
}
|
||||
|
||||
private Type sDesc() {
|
||||
return getMethodType(VOID_TYPE, type.boxed);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm.value;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.gitlab.jfronny.libjf.config.plugin.asm.value.KnownTypes.*;
|
||||
import static org.objectweb.asm.Type.*;
|
||||
|
||||
public enum KnownType {
|
||||
INT(INT_BOX_TYPE, INT_TYPE),
|
||||
LONG(LONG_BOX_TYPE, LONG_TYPE),
|
||||
FLOAT(FLOAT_BOX_TYPE, FLOAT_TYPE),
|
||||
DOUBLE(DOUBLE_BOX_TYPE, DOUBLE_TYPE),
|
||||
STRING(STRING_TYPE, STRING_TYPE),
|
||||
BOOLEAN(BOOLEAN_BOX_TYPE, BOOLEAN_TYPE),
|
||||
OBJECT(OBJECT_TYPE, OBJECT_TYPE);
|
||||
|
||||
public final Type boxed;
|
||||
public final Type unboxed;
|
||||
private static final Map<Type, KnownType> t2t = new HashMap<>();
|
||||
|
||||
KnownType(Type boxed, Type unboxed) {
|
||||
this.boxed = boxed;
|
||||
this.unboxed = unboxed;
|
||||
}
|
||||
|
||||
static {
|
||||
for (KnownType value : values()) {
|
||||
if (value != OBJECT) {
|
||||
t2t.put(value.boxed, value);
|
||||
t2t.put(value.unboxed, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static KnownType of(Type type) {
|
||||
return t2t.getOrDefault(type, OBJECT);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.asm.value;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.*;
|
||||
import io.gitlab.jfronny.libjf.config.api.v1.dsl.*;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class KnownTypes {
|
||||
// DSL types
|
||||
public static final Type CONFIG_BUILDER_TYPE = Type.getType(ConfigBuilder.class);
|
||||
public static final Type CONFIG_BUILDER_FUNCTION_TYPE = Type.getType(ConfigBuilder.ConfigBuilderFunction.class);
|
||||
public static final Type CATEGORY_BUILDER_TYPE = Type.getType(CategoryBuilder.class);
|
||||
public static final Type CATEGORY_BUILDER_FUNCTION_TYPE = Type.getType(CategoryBuilder.CategoryBuilderFunction.class);
|
||||
public static final Type DSL_TYPE = Type.getType(DSL.class);
|
||||
public static final Type DSL_DEFAULTED_TYPE = Type.getType(DSL.Defaulted.class);
|
||||
public static final Type CONFIG_HOLDER_TYPE = Type.getType(ConfigHolder.class);
|
||||
public static final Type CONFIG_INSTANCE_TYPE = Type.getType(ConfigInstance.class);
|
||||
public static final Type ENTRY_INFO_TYPE = Type.getType(EntryInfo.class);
|
||||
// Boxes
|
||||
public static final Type INT_BOX_TYPE = Type.getType(Integer.class);
|
||||
public static final Type LONG_BOX_TYPE = Type.getType(Long.class);
|
||||
public static final Type FLOAT_BOX_TYPE = Type.getType(Float.class);
|
||||
public static final Type DOUBLE_BOX_TYPE = Type.getType(Double.class);
|
||||
public static final Type BOOLEAN_BOX_TYPE = Type.getType(Boolean.class);
|
||||
public static final Type CHARACTER_BOX_TYPE = Type.getType(Character.class);
|
||||
public static final Type SHORT_BOX_TYPE = Type.getType(Short.class);
|
||||
public static final Type BYTE_BOX_TYPE = Type.getType(Byte.class);
|
||||
// Additional
|
||||
public static final Type STRING_TYPE = Type.getType(String.class);
|
||||
public static final Type OBJECT_TYPE = Type.getType(Object.class);
|
||||
public static final Type RUNNABLE_TYPE = Type.getType(Runnable.class);
|
||||
public static final Type SUPPLIER_TYPE = Type.getType(Supplier.class);
|
||||
public static final Type CONSUMER_TYPE = Type.getType(Consumer.class);
|
||||
public static final Type NUMBER_TYPE = Type.getType(Number.class);
|
||||
public static final Type CLASS_TYPE = Type.getType(Class.class);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.fmj;
|
||||
|
||||
import io.gitlab.jfronny.gson.*;
|
||||
import io.gitlab.jfronny.gson.stream.JsonReader;
|
||||
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
||||
import io.gitlab.jfronny.libjf.config.impl.ConfigCore;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class FabricModJsonTransformer {
|
||||
private static final Gson INPUT_GSON = new GsonBuilder().setLenient().create();
|
||||
private static final Gson OUTPUT_GSON = new GsonBuilder().create();
|
||||
private static final String ENTRYPOINTS = "entrypoints";
|
||||
private static final String LIBJF_CONFIG = ConfigCore.MODULE_ID;
|
||||
public static void transform(JsonReader reader, JsonWriter writer, Set<Type> configClasses) {
|
||||
JsonObject fmj = INPUT_GSON.<JsonElement>fromJson(reader, JsonElement.class).getAsJsonObject();
|
||||
if (!fmj.has(ENTRYPOINTS)) fmj.add(ENTRYPOINTS, new JsonObject());
|
||||
JsonObject entrypoints = fmj.get(ENTRYPOINTS).getAsJsonObject();
|
||||
if (!entrypoints.has(LIBJF_CONFIG)) entrypoints.add(LIBJF_CONFIG, new JsonArray());
|
||||
JsonArray libjfConfig = entrypoints.getAsJsonArray(LIBJF_CONFIG).getAsJsonArray();
|
||||
for (Type klazz : configClasses) {
|
||||
// Remove references to class
|
||||
Iterator<JsonElement> each = libjfConfig.iterator();
|
||||
while(each.hasNext()) {
|
||||
JsonElement element = each.next();
|
||||
if (element.isJsonPrimitive() && element.getAsString().equals(klazz.getClassName())) {
|
||||
each.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Add reference to init method
|
||||
libjfConfig.add(klazz.getClassName() + "::" + ConfigInjectClassTransformer.REGISTER_METHOD);
|
||||
}
|
||||
OUTPUT_GSON.toJson(fmj, writer);
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import org.gradle.api.file.FileTreeElement;
|
||||
import org.gradle.api.file.RelativePath;
|
||||
import org.gradle.api.internal.file.DefaultFileTreeElement;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ArchiveFileTreeElement implements FileTreeElement {
|
||||
private final RelativeArchivePath archivePath;
|
||||
|
||||
public ArchiveFileTreeElement(RelativeArchivePath archivePath) {
|
||||
this.archivePath = archivePath;
|
||||
}
|
||||
|
||||
public boolean isClassFile() {
|
||||
return archivePath.isClassFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return archivePath.entry.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified() {
|
||||
return archivePath.entry.getLastModifiedDate().getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return archivePath.entry.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream open() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(OutputStream outputStream) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyTo(File file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return archivePath.getPathString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return archivePath.getLastName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelativeArchivePath getRelativePath() {
|
||||
return archivePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMode() {
|
||||
return archivePath.entry.getUnixMode();
|
||||
}
|
||||
|
||||
public FileTreeElement asFileTreeElement() {
|
||||
return new DefaultFileTreeElement(null, new RelativePath(!isDirectory(), archivePath.getSegments()), null, null);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class ClInitInjectVisitor extends MethodVisitor {
|
||||
private final String owner;
|
||||
private final String name;
|
||||
private final String descriptor;
|
||||
|
||||
public ClInitInjectVisitor(MethodVisitor mw, String owner, String name, String descriptor) {
|
||||
super(ASM9, mw);
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
if (opcode == RETURN) {
|
||||
super.visitMethodInsn(INVOKESTATIC, owner, name, descriptor, false);
|
||||
}
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import org.apache.tools.zip.Zip64Mode;
|
||||
import org.apache.tools.zip.ZipOutputStream;
|
||||
import org.gradle.api.UncheckedIOException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class DefaultZipCompressor implements ZipCompressor {
|
||||
private final int entryCompressionMethod;
|
||||
private final Zip64Mode zip64Mode;
|
||||
|
||||
public DefaultZipCompressor(boolean allowZip64Mode, int entryCompressionMethod) {
|
||||
this.entryCompressionMethod = entryCompressionMethod;
|
||||
this.zip64Mode = allowZip64Mode ? Zip64Mode.AsNeeded : Zip64Mode.Never;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipOutputStream createArchiveOutputStream(File destination) {
|
||||
try {
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(destination);
|
||||
zipOutputStream.setUseZip64(zip64Mode);
|
||||
zipOutputStream.setMethod(entryCompressionMethod);
|
||||
return zipOutputStream;
|
||||
} catch (Exception e) {
|
||||
String message = String.format("Unable to create ZIP output stream for file %s.", destination);
|
||||
throw new UncheckedIOException(message, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class DelegatingUncloseableOutputStream extends OutputStream {
|
||||
private final OutputStream delegate;
|
||||
|
||||
public DelegatingUncloseableOutputStream(OutputStream delegate) {
|
||||
super();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int i) throws IOException {
|
||||
delegate.write(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
delegate.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
delegate.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class EnumerationSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
|
||||
private final Enumeration<T> enumeration;
|
||||
|
||||
public EnumerationSpliterator(long est, int additionalCharacteristics, Enumeration<T> enumeration) {
|
||||
super(est, additionalCharacteristics);
|
||||
this.enumeration = enumeration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super T> action) {
|
||||
if (enumeration.hasMoreElements()) {
|
||||
action.accept(enumeration.nextElement());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(Consumer<? super T> action) {
|
||||
while (enumeration.hasMoreElements())
|
||||
action.accept(enumeration.nextElement());
|
||||
}
|
||||
|
||||
public static <T> Stream<T> stream(Enumeration<T> enumeration) {
|
||||
EnumerationSpliterator<T> spliterator = new EnumerationSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED, enumeration);
|
||||
return StreamSupport.stream(spliterator, false);
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import io.gitlab.jfronny.libjf.config.plugin.BuildMetadata;
|
||||
import io.gitlab.jfronny.libjf.config.plugin.asm.value.KnownTypes;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.GeneratorAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ASM9;
|
||||
import static org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||
|
||||
public class GeneratorAdapter2 extends GeneratorAdapter {
|
||||
private static final Handle metafactory = new Handle(
|
||||
H_INVOKESTATIC,
|
||||
Type.getInternalName(LambdaMetafactory.class),
|
||||
"metafactory",
|
||||
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
|
||||
false
|
||||
);
|
||||
|
||||
public GeneratorAdapter2(MethodVisitor methodVisitor, int access, String name, String descriptor) {
|
||||
super(ASM9, methodVisitor, access, name, descriptor);
|
||||
}
|
||||
|
||||
public void λ(String lambdaMethodName, String lambdaType, Type lambdaDescriptor, Type implDescriptor, String implOwner, String implName) {
|
||||
invokeDynamic(lambdaMethodName,
|
||||
lambdaType,
|
||||
metafactory,
|
||||
lambdaDescriptor,
|
||||
new Handle(H_INVOKESTATIC, implOwner, implName, implDescriptor.getInternalName(), false),
|
||||
implDescriptor);
|
||||
}
|
||||
|
||||
public void λ(String lambdaMethodName, String lambdaType, Type descriptor, String implOwner, String implName) {
|
||||
λ(lambdaMethodName, lambdaType, descriptor, descriptor, implOwner, implName);
|
||||
}
|
||||
|
||||
public void runnable(String implOwner, String implName) {
|
||||
λ("run",
|
||||
"()Ljava/lang/Runnable;",
|
||||
Type.getType("()V"),
|
||||
implOwner,
|
||||
implName);
|
||||
}
|
||||
|
||||
public void supplier(String implOwner, String implName, Type implDescriptor) {
|
||||
λ("get",
|
||||
"()Ljava/util/function/Supplier;",
|
||||
Type.getType("()Ljava/lang/Object;"),
|
||||
implDescriptor,
|
||||
implOwner,
|
||||
implName);
|
||||
}
|
||||
|
||||
public void consumer(String implOwner, String implName, Type implDescriptor) {
|
||||
λ("accept",
|
||||
"()Ljava/util/function/Consumer;",
|
||||
Type.getType("(Ljava/lang/Object;)V"),
|
||||
implDescriptor,
|
||||
implOwner,
|
||||
implName);
|
||||
}
|
||||
|
||||
public void box(Type type) {
|
||||
Type boxedType;
|
||||
switch (type.getSort()) {
|
||||
case Type.VOID:
|
||||
return;
|
||||
case Type.CHAR:
|
||||
boxedType = KnownTypes.CHARACTER_BOX_TYPE;
|
||||
break;
|
||||
case Type.BOOLEAN:
|
||||
boxedType = KnownTypes.BOOLEAN_BOX_TYPE;
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
boxedType = KnownTypes.DOUBLE_BOX_TYPE;
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
boxedType = KnownTypes.FLOAT_BOX_TYPE;
|
||||
break;
|
||||
case Type.LONG:
|
||||
boxedType = KnownTypes.LONG_BOX_TYPE;
|
||||
break;
|
||||
case Type.INT:
|
||||
boxedType = KnownTypes.INT_BOX_TYPE;
|
||||
break;
|
||||
case Type.SHORT:
|
||||
boxedType = KnownTypes.SHORT_BOX_TYPE;
|
||||
break;
|
||||
case Type.BYTE:
|
||||
boxedType = KnownTypes.BYTE_BOX_TYPE;
|
||||
break;
|
||||
default:
|
||||
boxedType = null;
|
||||
break;
|
||||
}
|
||||
if (boxedType == null) {
|
||||
comment("Unkown boxed type, simply casting");
|
||||
checkCast(type);
|
||||
} else {
|
||||
comment("Boxing " + type + " to " + boxedType);
|
||||
invokeStatic(boxedType, new Method("valueOf", boxedType, new Type[]{type}));
|
||||
}
|
||||
}
|
||||
|
||||
public void invokeIStatic(Type owner, Method method) {
|
||||
invokeInsn(Opcodes.INVOKESTATIC, owner, method, true);
|
||||
}
|
||||
|
||||
public void comment(String comment) {
|
||||
if (BuildMetadata.IS_RELEASE) return;
|
||||
push("[Comment/Generator] " + comment);
|
||||
pop();
|
||||
}
|
||||
|
||||
// Taken from GeneratorAdapter
|
||||
private void invokeInsn(final int opcode, final Type type, final Method method, final boolean isInterface) {
|
||||
String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName();
|
||||
mv.visitMethodInsn(opcode, owner, method.getName(), method.getDescriptor(), isInterface);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import org.apache.tools.zip.ZipOutputStream;
|
||||
import org.gradle.api.tasks.bundling.Jar;
|
||||
import org.gradle.api.tasks.bundling.ZipEntryCompression;
|
||||
import org.gradle.util.GradleVersion;
|
||||
|
||||
public class GradleVersionUtil {
|
||||
private final GradleVersion version;
|
||||
|
||||
public GradleVersionUtil(String version) {
|
||||
this.version = GradleVersion.version(version);
|
||||
}
|
||||
|
||||
public ZipCompressor getInternalCompressor(ZipEntryCompression entryCompression, Jar jar) {
|
||||
return switch (entryCompression) {
|
||||
case DEFLATED -> new DefaultZipCompressor(jar.isZip64(), ZipOutputStream.DEFLATED);
|
||||
case STORED -> new DefaultZipCompressor(jar.isZip64(), ZipOutputStream.STORED);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
import org.apache.tools.zip.ZipEntry;
|
||||
import org.gradle.api.file.RelativePath;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class RelativeArchivePath extends RelativePath {
|
||||
public ZipEntry entry;
|
||||
|
||||
public RelativeArchivePath(ZipEntry entry) {
|
||||
super(!entry.isDirectory(), entry.getName().split("/"));
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public boolean isClassFile() {
|
||||
return getLastName().endsWith(".class");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelativeArchivePath getParent() {
|
||||
List<String> segments = Arrays.asList(getSegments());
|
||||
if (segments.size() == 1) {
|
||||
return null;
|
||||
} else {
|
||||
//Parent is always a directory so add / to the end of the path
|
||||
String path = String.join("/", segments.subList(0, segments.size() - 1)) + "/";
|
||||
return new RelativeArchivePath(new ZipEntry(path));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package io.gitlab.jfronny.libjf.config.plugin.util;
|
||||
|
||||
|
||||
import org.apache.tools.zip.ZipOutputStream;
|
||||
import org.gradle.api.internal.file.archive.compression.ArchiveOutputStreamFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface ZipCompressor extends ArchiveOutputStreamFactory {
|
||||
ZipOutputStream createArchiveOutputStream(File destination);
|
||||
}
|
|
@ -21,5 +21,4 @@ include("libjf-translate-v1")
|
|||
include("libjf-unsafe-v0")
|
||||
include("libjf-web-v0")
|
||||
|
||||
include("libjf-config-compiler-plugin")
|
||||
include("libjf-config-compiler-plugin-v2")
|
||||
|
|
Loading…
Reference in New Issue