From 08a797c53b4d875442e4f5fc05e161529fedd02d Mon Sep 17 00:00:00 2001 From: Juuxel <6596629+Juuxel@users.noreply.github.com> Date: Fri, 23 Jul 2021 23:51:34 +0300 Subject: [PATCH] Use jar processor ids to fix #432 (#444) * Use jar processor ids to fix #432 * Use full hash string of jar processor ids --- .../AccessWidenerJarProcessor.java | 5 ++ .../processors/JarProcessor.java | 12 ++++ .../processors/JarProcessorManager.java | 61 +++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java index 78538f9..679bb94 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java @@ -69,6 +69,11 @@ public class AccessWidenerJarProcessor implements JarProcessor { this.project = project; } + @Override + public String getId() { + return "loom:access_widener"; + } + @Override public void setup() { LoomGradleExtension loomGradleExtension = LoomGradleExtension.get(project); diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessor.java index 33cde23..71f9a6b 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessor.java @@ -27,6 +27,18 @@ package net.fabricmc.loom.configuration.processors; import java.io.File; public interface JarProcessor { + /** + * Returns a unique ID for this jar processor, containing all configuration details. + * + *

If the jar processor implementation class supports creating multiple jar processors with different effects, + * the needed configuration should also be included in this ID. Example: {@code path.to.MyJarProcessor#someOption}. + * + * @return the ID of this jar processor + */ + default String getId() { + return getClass().getName(); + } + void setup(); /** diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessorManager.java b/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessorManager.java index 9ee6864..4c36c40 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessorManager.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/JarProcessorManager.java @@ -25,9 +25,27 @@ package net.fabricmc.loom.configuration.processors; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; + +import com.google.common.hash.Hashing; +import com.google.common.io.CharSource; +import org.zeroturnaround.zip.ZipUtil; +import org.zeroturnaround.zip.transform.StreamZipEntryTransformer; +import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; public class JarProcessorManager { + private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; + private static final String JAR_PROCESSOR_HASH_ATTRIBUTE = "Loom-Jar-Processor-Hash"; private final List jarProcessors; public JarProcessorManager(List jarProcessors) { @@ -47,13 +65,56 @@ public class JarProcessorManager { return true; } + String jarProcessorHash = getJarProcessorHash(); + + try (JarFile jar = new JarFile(file)) { + Attributes attributes = jar.getManifest().getMainAttributes(); + + if (!jarProcessorHash.equals(attributes.getValue(JAR_PROCESSOR_HASH_ATTRIBUTE))) { + return true; + } + } catch (IOException e) { + throw new UncheckedIOException("Could not check jar manifest of " + file, e); + } + return jarProcessors.stream().anyMatch(jarProcessor -> jarProcessor.isInvalid(file)); } + private String getJarProcessorHash() { + String jarProcessorIds = jarProcessors.stream() + .map(JarProcessor::getId) + .sorted() + .collect(Collectors.joining(";")); + + try { + return CharSource.wrap(jarProcessorIds) + .asByteSource(StandardCharsets.UTF_8) + .hash(Hashing.sha256()) + .toString(); + } catch (IOException e) { + throw new UncheckedIOException("Could not hash jar processor IDs", e); + } + } + public void process(File file) { for (JarProcessor jarProcessor : jarProcessors) { jarProcessor.process(file); } + + boolean manifestTransformed = ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[] { + new ZipEntryTransformerEntry(MANIFEST_PATH, new StreamZipEntryTransformer() { + @Override + protected void transform(ZipEntry zipEntry, InputStream in, OutputStream out) throws IOException { + Manifest manifest = new Manifest(in); + manifest.getMainAttributes().putValue(JAR_PROCESSOR_HASH_ATTRIBUTE, getJarProcessorHash()); + manifest.write(out); + } + }) + }); + + if (!manifestTransformed) { + throw new RuntimeException("Could not add data to jar manifest in " + file); + } } public T getByType(Class tClass) {