[config-compiler-plugin] Keep original bytes for non-config classes
This commit is contained in:
parent
f434e8843a
commit
55bfa434ec
@ -27,3 +27,10 @@ allprojects {
|
|||||||
compileOnly("io.gitlab.jfronny:commons-gson:$rootProject.commons_version")
|
compileOnly("io.gitlab.jfronny:commons-gson:$rootProject.commons_version")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task copyVersionNumber {
|
||||||
|
doLast {
|
||||||
|
java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new java.awt.datatransfer.StringSelection("$version"), null)
|
||||||
|
println("Copied version number: $version")
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,6 @@ dependencies {
|
|||||||
implementation("io.gitlab.jfronny:commons-gson:$rootProject.commons_version")
|
implementation("io.gitlab.jfronny:commons-gson:$rootProject.commons_version")
|
||||||
implementation("org.ow2.asm:asm:9.3")
|
implementation("org.ow2.asm:asm:9.3")
|
||||||
implementation("org.ow2.asm:asm-commons:9.3")
|
implementation("org.ow2.asm:asm-commons:9.3")
|
||||||
implementation("org.ow2.asm:asm-util:9.3")
|
|
||||||
implementation(project(":libjf-config-core-v1")) {
|
implementation(project(":libjf-config-core-v1")) {
|
||||||
transitive(false)
|
transitive(false)
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,17 @@ package io.gitlab.jfronny.libjf.config.plugin;
|
|||||||
import io.gitlab.jfronny.gson.stream.JsonReader;
|
import io.gitlab.jfronny.gson.stream.JsonReader;
|
||||||
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
||||||
import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer;
|
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.fmj.FabricModJsonTransformer;
|
||||||
import io.gitlab.jfronny.libjf.config.plugin.util.*;
|
import io.gitlab.jfronny.libjf.config.plugin.util.*;
|
||||||
import org.apache.tools.zip.*;
|
import org.apache.tools.zip.*;
|
||||||
import org.gradle.api.GradleException;
|
import org.gradle.api.GradleException;
|
||||||
import org.gradle.api.file.FileCopyDetails;
|
import org.gradle.api.file.FileCopyDetails;
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
import org.objectweb.asm.util.CheckClassAdapter;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class StreamAction {
|
public class StreamAction {
|
||||||
@ -39,7 +40,7 @@ public class StreamAction {
|
|||||||
} else {
|
} else {
|
||||||
return visitFile(details);
|
return visitFile(details);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) {
|
||||||
throw new GradleException("Could not add " + details + " to ZIP " + zipFile, e);
|
throw new GradleException("Could not add " + details + " to ZIP " + zipFile, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +104,7 @@ public class StreamAction {
|
|||||||
copyArchiveEntry(archiveFilePath, archive);
|
copyArchiveEntry(archiveFilePath, archive);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} catch (IOException e) {
|
} catch (Throwable e) {
|
||||||
throw new GradleException("Could not read archive entry " + archiveFilePath.getPathString(), e);
|
throw new GradleException("Could not read archive entry " + archiveFilePath.getPathString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,25 +137,29 @@ public class StreamAction {
|
|||||||
private void processClass(RelativeArchivePath file, ZipFile archive) throws IOException {
|
private void processClass(RelativeArchivePath file, ZipFile archive) throws IOException {
|
||||||
ZipEntry zipEntry = new ZipEntry(file.getPathString());
|
ZipEntry zipEntry = new ZipEntry(file.getPathString());
|
||||||
addParentDirectories(new RelativeArchivePath(zipEntry));
|
addParentDirectories(new RelativeArchivePath(zipEntry));
|
||||||
processClass(archive.getInputStream(file.entry), file.getPathString(), file.entry.getTime());
|
processClass(archive.getInputStream(file.entry).readAllBytes(), file.getPathString(), file.entry.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processClass(FileCopyDetails details) throws IOException {
|
private void processClass(FileCopyDetails details) throws IOException {
|
||||||
try (InputStream is = new BufferedInputStream(new FileInputStream(details.getFile()))) {
|
try (InputStream is = new FileInputStream(details.getFile())) {
|
||||||
processClass(is, details.getPath(), details.getLastModified());
|
processClass(is.readAllBytes(), details.getPath(), details.getLastModified());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processClass(InputStream classInputStream, String path, long lastModified) throws IOException {
|
private void processClass(byte[] klazz, String path, long lastModified) throws IOException {
|
||||||
final ClassReader reader = new ClassReader(classInputStream);
|
try {
|
||||||
final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
|
final ClassReader reader = new ClassReader(klazz);
|
||||||
reader.accept(new CheckClassAdapter(
|
final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
|
||||||
new ConfigInjectClassTransformer(modId, writer, knownConfigClasses)
|
final ConfigInjectClassTransformer transformer = new ConfigInjectClassTransformer(modId, writer, knownConfigClasses);
|
||||||
), ClassReader.EXPAND_FRAMES);
|
reader.accept(transformer, ClassReader.EXPAND_FRAMES);
|
||||||
|
klazz = writer.toByteArray();
|
||||||
|
} catch (NotAConfigClassException notAConfigClass) {
|
||||||
|
// Use original bytes
|
||||||
|
}
|
||||||
ZipEntry archiveEntry = new ZipEntry(path);
|
ZipEntry archiveEntry = new ZipEntry(path);
|
||||||
archiveEntry.setTime(getArchiveTimeFor(lastModified));
|
archiveEntry.setTime(getArchiveTimeFor(lastModified));
|
||||||
zipOutStr.putNextEntry(archiveEntry);
|
zipOutStr.putNextEntry(archiveEntry);
|
||||||
zipOutStr.write(writer.toByteArray());
|
zipOutStr.write(klazz);
|
||||||
zipOutStr.closeEntry();
|
zipOutStr.closeEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +170,7 @@ public class StreamAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processFMJ(FileCopyDetails details) throws IOException {
|
private void processFMJ(FileCopyDetails details) throws IOException {
|
||||||
try (InputStream is = new BufferedInputStream(new FileInputStream(details.getFile()))) {
|
try (InputStream is = new FileInputStream(details.getFile())) {
|
||||||
processFMJ(is, details.getPath(), details.getLastModified());
|
processFMJ(is, details.getPath(), details.getLastModified());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,23 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
private final List<String> verifiers = new LinkedList<>();
|
private final List<String> verifiers = new LinkedList<>();
|
||||||
private final List<DiscoveredValue> values = new LinkedList<>();
|
private final List<DiscoveredValue> values = new LinkedList<>();
|
||||||
private boolean initFound = false;
|
private boolean initFound = false;
|
||||||
private TransformerMode mode = TransformerMode.OTHER;
|
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) {
|
public ConfigInjectClassTransformer(String modId, ClassVisitor cw, Set<Type> knownConfigClasses) {
|
||||||
super(ASM9, cw);
|
super(ASM9, cw);
|
||||||
@ -52,29 +68,31 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
||||||
if (descriptor.equals(Type.getDescriptor(Category.class)) && mode == TransformerMode.OTHER) {
|
if (mode == null) throw new IllegalStateException("Attempted to visit annotation before class");
|
||||||
|
if (descriptor.equals(Type.getDescriptor(Category.class)) && isOther()) {
|
||||||
mode = TransformerMode.CONFIG_CATEGORY;
|
mode = TransformerMode.CONFIG_CATEGORY;
|
||||||
return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs);
|
return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs);
|
||||||
}
|
}
|
||||||
if (descriptor.equals(Type.getDescriptor(JfConfig.class)) && mode == TransformerMode.OTHER) {
|
else if (descriptor.equals(Type.getDescriptor(JfConfig.class)) && isOther()) {
|
||||||
mode = TransformerMode.CONFIG_ROOT;
|
mode = TransformerMode.CONFIG_ROOT;
|
||||||
knownConfigClasses.add(current);
|
knownConfigClasses.add(current);
|
||||||
return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs);
|
return new AnnotationMetaGatheringVisitor(super.visitAnnotation(descriptor, visible), referencedConfigs);
|
||||||
|
} else {
|
||||||
|
return super.visitAnnotation(descriptor, visible);
|
||||||
}
|
}
|
||||||
return super.visitAnnotation(descriptor, visible);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitNestMember(String nestMember) {
|
public void visitNestMember(String nestMember) {
|
||||||
if (mode != TransformerMode.OTHER) {
|
ensureCategory();
|
||||||
categories.add(nestMember);
|
categories.add(nestMember);
|
||||||
}
|
|
||||||
super.visitNestMember(nestMember);
|
super.visitNestMember(nestMember);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
if (mode == TransformerMode.CONFIG_ROOT) {
|
ensureCategory();
|
||||||
|
if (isConfig()) {
|
||||||
if ("<clinit>".equals(name)) {
|
if ("<clinit>".equals(name)) {
|
||||||
initFound = true;
|
initFound = true;
|
||||||
return new ClInitInjectVisitor(
|
return new ClInitInjectVisitor(
|
||||||
@ -85,10 +103,8 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mode != TransformerMode.OTHER) {
|
if (name.startsWith(PREFIX)) {
|
||||||
if (name.startsWith(PREFIX)) {
|
throw new GradleException("This class declares methods generated by this plugin manually. Do not transform classes twice!");
|
||||||
throw new GradleException("This class declares methods generated by this plugin manually. Do not transform classes twice!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ((access & ACC_STATIC) == ACC_STATIC) {
|
if ((access & ACC_STATIC) == ACC_STATIC) {
|
||||||
// Possibly add verifier or preset
|
// Possibly add verifier or preset
|
||||||
@ -101,6 +117,7 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||||
|
ensureCategory();
|
||||||
if ((access & ACC_STATIC) == ACC_STATIC) {
|
if ((access & ACC_STATIC) == ACC_STATIC) {
|
||||||
return new FieldMetaGatheringVisitor(super.visitField(access, name, descriptor, signature, value), name, values, Type.getType(descriptor));
|
return new FieldMetaGatheringVisitor(super.visitField(access, name, descriptor, signature, value), name, values, Type.getType(descriptor));
|
||||||
}
|
}
|
||||||
@ -109,7 +126,8 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
if (mode == TransformerMode.CONFIG_ROOT) {
|
ensureCategory();
|
||||||
|
if (isConfig()) {
|
||||||
if (!initFound) {
|
if (!initFound) {
|
||||||
// Generate <clinit> if missing
|
// Generate <clinit> if missing
|
||||||
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, CLINIT, "()V", null, null);
|
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, CLINIT, "()V", null, null);
|
||||||
@ -150,9 +168,8 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
m.endMethod();
|
m.endMethod();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mode != TransformerMode.OTHER) {
|
{
|
||||||
boolean root = mode == TransformerMode.CONFIG_ROOT;
|
Type builderType = isConfig() ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE;
|
||||||
Type builderType = root ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE;
|
|
||||||
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, BUILDER_ROOT, getMethodDescriptor(builderType, builderType), null, null);
|
GeneratorAdapter2 m = method(ACC_PRIVATE | ACC_STATIC, BUILDER_ROOT, getMethodDescriptor(builderType, builderType), null, null);
|
||||||
m.loadArg(0);
|
m.loadArg(0);
|
||||||
for (String name : referencedConfigs) {
|
for (String name : referencedConfigs) {
|
||||||
@ -195,10 +212,9 @@ public class ConfigInjectClassTransformer extends ClassVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dslInvoke(GeneratorAdapter m, String name, Type returnType, Type... arguments) {
|
public void dslInvoke(GeneratorAdapter m, String name, Type returnType, Type... arguments) {
|
||||||
boolean root = mode == TransformerMode.CONFIG_ROOT;
|
Type builderType = isConfig() ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE;
|
||||||
Type builderType = root ? CONFIG_BUILDER_TYPE : CATEGORY_BUILDER_TYPE;
|
|
||||||
m.invokeInterface(builderType, new Method(name, returnType, arguments));
|
m.invokeInterface(builderType, new Method(name, returnType, arguments));
|
||||||
if (root) m.checkCast(CONFIG_BUILDER_TYPE);
|
if (isConfig()) m.checkCast(CONFIG_BUILDER_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String camelCase(String s) {
|
private String camelCase(String s) {
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user