From 46136cc7b0eabb809f93afdcb8d6e25113a67427 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Jan 2025 16:28:12 +0800 Subject: [PATCH 01/15] Copy Log4j2PluginCacheFileTransformer.java from logging-log4j-transform Updated to https://github.com/apache/logging-log4j-transform/blob/a190ba8dfd8a58f1ce95c3d06bcd6a924a416db5/log4j-transform-maven-shade-plugin-extensions/src/main/java/org/apache/logging/log4j/maven/plugins/shade/transformer/Log4j2PluginCacheFileTransformer.java --- .../Log4j2PluginCacheFileTransformer.java | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/main/java/Log4j2PluginCacheFileTransformer.java diff --git a/src/main/java/Log4j2PluginCacheFileTransformer.java b/src/main/java/Log4j2PluginCacheFileTransformer.java new file mode 100644 index 000000000..21fec615c --- /dev/null +++ b/src/main/java/Log4j2PluginCacheFileTransformer.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.logging.log4j.core.config.plugins.processor.PluginCache; +import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry; +import org.apache.maven.plugins.shade.relocation.Relocator; +import org.apache.maven.plugins.shade.resource.ReproducibleResourceTransformer; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.util.*; +import java.util.Map.Entry; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE; + +/** + * 'log4j-maven-shade-plugin' transformer implementation. + */ +public class Log4j2PluginCacheFileTransformer implements ReproducibleResourceTransformer { + + /** + * Log4j config files to share across the transformation stages. + */ + private final List tempFiles; + /** + * {@link Relocator} instances to share across the transformation stages. + */ + private final List tempRelocators; + /** + * Store youngest (i.e. largest millisecond) so that we can produce reproducible jar file + */ + private long youngestTime = 0; + + /** + * Default constructor, initializing internal state. + */ + public Log4j2PluginCacheFileTransformer() { + tempRelocators = new ArrayList<>(); + tempFiles = new ArrayList<>(); + } + + /** + * @param resource resource to check + * @return true when resource is recognized as log4j-plugin-cache file + */ + @Override + public boolean canTransformResource(final String resource) { + return PLUGIN_CACHE_FILE.equals(resource); + } + + @Override + @Deprecated + public void processResource(String resource, InputStream is, List relocators) { + // stub + } + + /** + * @param resource ignored parameter + * @param resourceInput resource input stream to save in temp file + * for next stage + * @param relocators relocators to keep for next stage + * @throws IOException thrown by file writing errors + */ + @Override + public void processResource( + final String resource, final InputStream resourceInput, final List relocators, final long time) + throws IOException { + final Path tempFile = Files.createTempFile("Log4j2Plugins", "dat"); + Files.copy(resourceInput, tempFile, REPLACE_EXISTING); + tempFiles.add(tempFile); + youngestTime = Math.max(youngestTime, time); + + if (relocators != null) { + this.tempRelocators.addAll(relocators); + } + } + + /** + * @return true if any dat file collected + */ + @Override + public boolean hasTransformedResource() { + return tempFiles.size() > 0; + } + + /** + * Stores all previously collected log4j-cache-files to the target jar. + * + * @param jos jar output + * @throws IOException When the IO blows up + */ + @Override + public void modifyOutputStream(final JarOutputStream jos) throws IOException { + try { + final PluginCache aggregator = new PluginCache(); + aggregator.loadCacheFiles(getUrls()); + relocatePlugin(tempRelocators, aggregator.getAllCategories()); + putJarEntry(jos); + // prevent the aggregator to close the jar output + final CloseShieldOutputStream outputStream = new CloseShieldOutputStream(jos); + aggregator.writeCache(outputStream); + } finally { + deleteTempFiles(); + } + } + + private Enumeration getUrls() throws MalformedURLException { + final List urls = new ArrayList<>(); + for (final Path tempFile : tempFiles) { + final URL url = tempFile.toUri().toURL(); + urls.add(url); + } + return Collections.enumeration(urls); + } + + /** + * Applies the given {@code relocators} to the {@code aggregator}. + * + * @param relocators relocators. + * @param aggregatorCategories all categories of the aggregator + */ + /* default */ void relocatePlugin( + final List relocators, Map> aggregatorCategories) { + for (final Entry> categoryEntry : aggregatorCategories.entrySet()) { + for (final Entry pluginMapEntry : + categoryEntry.getValue().entrySet()) { + final PluginEntry pluginEntry = pluginMapEntry.getValue(); + final String originalClassName = pluginEntry.getClassName(); + + final Relocator matchingRelocator = findFirstMatchingRelocator(originalClassName, relocators); + + if (matchingRelocator != null) { + final String newClassName = matchingRelocator.relocateClass(originalClassName); + pluginEntry.setClassName(newClassName); + } + } + } + } + + private Relocator findFirstMatchingRelocator(final String originalClassName, final List relocators) { + Relocator result = null; + for (final Relocator relocator : relocators) { + if (relocator.canRelocateClass(originalClassName)) { + result = relocator; + break; + } + } + return result; + } + + private void putJarEntry(JarOutputStream jos) throws IOException { + final JarEntry jarEntry = new JarEntry(PLUGIN_CACHE_FILE); + + // Set time to youngest timestamp, to ensure reproducible output. + final FileTime fileTime = FileTime.fromMillis(youngestTime); + jarEntry.setLastModifiedTime(fileTime); + + jos.putNextEntry(jarEntry); + } + + private void deleteTempFiles() throws IOException { + final ListIterator pathIterator = tempFiles.listIterator(); + while (pathIterator.hasNext()) { + final Path path = pathIterator.next(); + Files.deleteIfExists(path); + pathIterator.remove(); + } + } +} From 22dc994bc24a775450866065437f6bc281ff39b6 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Jan 2025 16:29:40 +0800 Subject: [PATCH 02/15] Convert Log4j2PluginCacheFileTransformer to Kotlin --- .../Log4j2PluginCacheFileTransformer.java | 191 ------------------ .../java/Log4j2PluginCacheFileTransformer.kt | 173 ++++++++++++++++ 2 files changed, 173 insertions(+), 191 deletions(-) delete mode 100644 src/main/java/Log4j2PluginCacheFileTransformer.java create mode 100644 src/main/java/Log4j2PluginCacheFileTransformer.kt diff --git a/src/main/java/Log4j2PluginCacheFileTransformer.java b/src/main/java/Log4j2PluginCacheFileTransformer.java deleted file mode 100644 index 21fec615c..000000000 --- a/src/main/java/Log4j2PluginCacheFileTransformer.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache; -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry; -import org.apache.maven.plugins.shade.relocation.Relocator; -import org.apache.maven.plugins.shade.resource.ReproducibleResourceTransformer; - -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.FileTime; -import java.util.*; -import java.util.Map.Entry; -import java.util.jar.JarEntry; -import java.util.jar.JarOutputStream; - -import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; -import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE; - -/** - * 'log4j-maven-shade-plugin' transformer implementation. - */ -public class Log4j2PluginCacheFileTransformer implements ReproducibleResourceTransformer { - - /** - * Log4j config files to share across the transformation stages. - */ - private final List tempFiles; - /** - * {@link Relocator} instances to share across the transformation stages. - */ - private final List tempRelocators; - /** - * Store youngest (i.e. largest millisecond) so that we can produce reproducible jar file - */ - private long youngestTime = 0; - - /** - * Default constructor, initializing internal state. - */ - public Log4j2PluginCacheFileTransformer() { - tempRelocators = new ArrayList<>(); - tempFiles = new ArrayList<>(); - } - - /** - * @param resource resource to check - * @return true when resource is recognized as log4j-plugin-cache file - */ - @Override - public boolean canTransformResource(final String resource) { - return PLUGIN_CACHE_FILE.equals(resource); - } - - @Override - @Deprecated - public void processResource(String resource, InputStream is, List relocators) { - // stub - } - - /** - * @param resource ignored parameter - * @param resourceInput resource input stream to save in temp file - * for next stage - * @param relocators relocators to keep for next stage - * @throws IOException thrown by file writing errors - */ - @Override - public void processResource( - final String resource, final InputStream resourceInput, final List relocators, final long time) - throws IOException { - final Path tempFile = Files.createTempFile("Log4j2Plugins", "dat"); - Files.copy(resourceInput, tempFile, REPLACE_EXISTING); - tempFiles.add(tempFile); - youngestTime = Math.max(youngestTime, time); - - if (relocators != null) { - this.tempRelocators.addAll(relocators); - } - } - - /** - * @return true if any dat file collected - */ - @Override - public boolean hasTransformedResource() { - return tempFiles.size() > 0; - } - - /** - * Stores all previously collected log4j-cache-files to the target jar. - * - * @param jos jar output - * @throws IOException When the IO blows up - */ - @Override - public void modifyOutputStream(final JarOutputStream jos) throws IOException { - try { - final PluginCache aggregator = new PluginCache(); - aggregator.loadCacheFiles(getUrls()); - relocatePlugin(tempRelocators, aggregator.getAllCategories()); - putJarEntry(jos); - // prevent the aggregator to close the jar output - final CloseShieldOutputStream outputStream = new CloseShieldOutputStream(jos); - aggregator.writeCache(outputStream); - } finally { - deleteTempFiles(); - } - } - - private Enumeration getUrls() throws MalformedURLException { - final List urls = new ArrayList<>(); - for (final Path tempFile : tempFiles) { - final URL url = tempFile.toUri().toURL(); - urls.add(url); - } - return Collections.enumeration(urls); - } - - /** - * Applies the given {@code relocators} to the {@code aggregator}. - * - * @param relocators relocators. - * @param aggregatorCategories all categories of the aggregator - */ - /* default */ void relocatePlugin( - final List relocators, Map> aggregatorCategories) { - for (final Entry> categoryEntry : aggregatorCategories.entrySet()) { - for (final Entry pluginMapEntry : - categoryEntry.getValue().entrySet()) { - final PluginEntry pluginEntry = pluginMapEntry.getValue(); - final String originalClassName = pluginEntry.getClassName(); - - final Relocator matchingRelocator = findFirstMatchingRelocator(originalClassName, relocators); - - if (matchingRelocator != null) { - final String newClassName = matchingRelocator.relocateClass(originalClassName); - pluginEntry.setClassName(newClassName); - } - } - } - } - - private Relocator findFirstMatchingRelocator(final String originalClassName, final List relocators) { - Relocator result = null; - for (final Relocator relocator : relocators) { - if (relocator.canRelocateClass(originalClassName)) { - result = relocator; - break; - } - } - return result; - } - - private void putJarEntry(JarOutputStream jos) throws IOException { - final JarEntry jarEntry = new JarEntry(PLUGIN_CACHE_FILE); - - // Set time to youngest timestamp, to ensure reproducible output. - final FileTime fileTime = FileTime.fromMillis(youngestTime); - jarEntry.setLastModifiedTime(fileTime); - - jos.putNextEntry(jarEntry); - } - - private void deleteTempFiles() throws IOException { - final ListIterator pathIterator = tempFiles.listIterator(); - while (pathIterator.hasNext()) { - final Path path = pathIterator.next(); - Files.deleteIfExists(path); - pathIterator.remove(); - } - } -} diff --git a/src/main/java/Log4j2PluginCacheFileTransformer.kt b/src/main/java/Log4j2PluginCacheFileTransformer.kt new file mode 100644 index 000000000..2cc1e2bc8 --- /dev/null +++ b/src/main/java/Log4j2PluginCacheFileTransformer.kt @@ -0,0 +1,173 @@ +import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry +import org.apache.maven.plugins.shade.relocation.Relocator +import java.io.IOException +import java.io.InputStream +import java.net.MalformedURLException +import java.net.URL +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardCopyOption +import java.nio.file.attribute.FileTime +import java.util.Collections +import java.util.jar.JarEntry +import java.util.jar.JarOutputStream +import kotlin.math.max + +/** + * 'log4j-maven-shade-plugin' transformer implementation. + */ +public class Log4j2PluginCacheFileTransformer public constructor() : ReproducibleResourceTransformer { + /** + * Log4j config files to share across the transformation stages. + */ + private val tempFiles: MutableList + + /** + * [Relocator] instances to share across the transformation stages. + */ + private val tempRelocators: MutableList + + /** + * Store youngest (i.e. largest millisecond) so that we can produce reproducible jar file + */ + private var youngestTime: Long = 0 + + /** + * Default constructor, initializing internal state. + */ + init { + tempRelocators = ArrayList() + tempFiles = ArrayList() + } + + /** + * @param resource resource to check + * @return true when resource is recognized as log4j-plugin-cache file + */ + public override fun canTransformResource(resource: String?): Boolean { + return PluginProcessor.PLUGIN_CACHE_FILE == resource + } + + @Deprecated("") + public override fun processResource(resource: String?, `is`: InputStream?, relocators: MutableList?) { + // stub + } + + /** + * @param resource ignored parameter + * @param resourceInput resource input stream to save in temp file + * for next stage + * @param relocators relocators to keep for next stage + * @throws IOException thrown by file writing errors + */ + @Throws(IOException::class) + public override fun processResource( + resource: String?, resourceInput: InputStream, relocators: MutableList?, time: Long + ) { + val tempFile = Files.createTempFile("Log4j2Plugins", "dat") + Files.copy(resourceInput, tempFile, StandardCopyOption.REPLACE_EXISTING) + tempFiles.add(tempFile) + youngestTime = max(youngestTime.toDouble(), time.toDouble()).toLong() + + if (relocators != null) { + this.tempRelocators.addAll(relocators) + } + } + + /** + * @return true if any dat file collected + */ + public override fun hasTransformedResource(): Boolean { + return tempFiles.size > 0 + } + + /** + * Stores all previously collected log4j-cache-files to the target jar. + * + * @param jos jar output + * @throws IOException When the IO blows up + */ + @Throws(IOException::class) + public override fun modifyOutputStream(jos: JarOutputStream) { + try { + val aggregator: PluginCache = PluginCache() + aggregator.loadCacheFiles(this.urls) + relocatePlugin(tempRelocators, aggregator.getAllCategories()) + putJarEntry(jos) + // prevent the aggregator to close the jar output + val outputStream: CloseShieldOutputStream = CloseShieldOutputStream(jos) + aggregator.writeCache(outputStream) + } finally { + deleteTempFiles() + } + } + + @get:Throws(MalformedURLException::class) + private val urls: Enumeration + get() { + val urls: MutableList = ArrayList() + for (tempFile in tempFiles) { + val url = tempFile.toUri().toURL() + urls.add(url) + } + return Collections.enumeration(urls) + } + + /** + * Applies the given `relocators` to the `aggregator`. + * + * @param relocators relocators. + * @param aggregatorCategories all categories of the aggregator + */ + /* default */ + public fun relocatePlugin( + relocators: MutableList, + aggregatorCategories: MutableMap?> + ) { + for (categoryEntry in aggregatorCategories.entries) { + for (pluginMapEntry in categoryEntry.value!!.entries) { + val pluginEntry: PluginEntry = pluginMapEntry.value!! + val originalClassName = pluginEntry.getClassName() + + val matchingRelocator: Relocator? = findFirstMatchingRelocator(originalClassName, relocators) + + if (matchingRelocator != null) { + val newClassName: String? = matchingRelocator.relocateClass(originalClassName) + pluginEntry.setClassName(newClassName) + } + } + } + } + + private fun findFirstMatchingRelocator(originalClassName: String?, relocators: MutableList): Relocator? { + var result: Relocator? = null + for (relocator in relocators) { + if (relocator.canRelocateClass(originalClassName)) { + result = relocator + break + } + } + return result + } + + @Throws(IOException::class) + private fun putJarEntry(jos: JarOutputStream) { + val jarEntry: JarEntry = JarEntry(PluginProcessor.PLUGIN_CACHE_FILE) + + // Set time to youngest timestamp, to ensure reproducible output. + val fileTime = FileTime.fromMillis(youngestTime) + jarEntry.setLastModifiedTime(fileTime) + + jos.putNextEntry(jarEntry) + } + + @Throws(IOException::class) + private fun deleteTempFiles() { + val pathIterator = tempFiles.listIterator() + while (pathIterator.hasNext()) { + val path = pathIterator.next() + Files.deleteIfExists(path) + pathIterator.remove() + } + } +} From d6e09fee618cd227130c17e33b0d34a3dc755a5e Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Jan 2025 16:51:10 +0800 Subject: [PATCH 03/15] Merge Log4j2PluginCacheFileTransformer into Log4j2PluginsCacheFileTransformer --- .../java/Log4j2PluginCacheFileTransformer.kt | 173 ------------------ .../Log4j2PluginsCacheFileTransformer.kt | 97 +++++++--- 2 files changed, 69 insertions(+), 201 deletions(-) delete mode 100644 src/main/java/Log4j2PluginCacheFileTransformer.kt diff --git a/src/main/java/Log4j2PluginCacheFileTransformer.kt b/src/main/java/Log4j2PluginCacheFileTransformer.kt deleted file mode 100644 index 2cc1e2bc8..000000000 --- a/src/main/java/Log4j2PluginCacheFileTransformer.kt +++ /dev/null @@ -1,173 +0,0 @@ -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry -import org.apache.maven.plugins.shade.relocation.Relocator -import java.io.IOException -import java.io.InputStream -import java.net.MalformedURLException -import java.net.URL -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardCopyOption -import java.nio.file.attribute.FileTime -import java.util.Collections -import java.util.jar.JarEntry -import java.util.jar.JarOutputStream -import kotlin.math.max - -/** - * 'log4j-maven-shade-plugin' transformer implementation. - */ -public class Log4j2PluginCacheFileTransformer public constructor() : ReproducibleResourceTransformer { - /** - * Log4j config files to share across the transformation stages. - */ - private val tempFiles: MutableList - - /** - * [Relocator] instances to share across the transformation stages. - */ - private val tempRelocators: MutableList - - /** - * Store youngest (i.e. largest millisecond) so that we can produce reproducible jar file - */ - private var youngestTime: Long = 0 - - /** - * Default constructor, initializing internal state. - */ - init { - tempRelocators = ArrayList() - tempFiles = ArrayList() - } - - /** - * @param resource resource to check - * @return true when resource is recognized as log4j-plugin-cache file - */ - public override fun canTransformResource(resource: String?): Boolean { - return PluginProcessor.PLUGIN_CACHE_FILE == resource - } - - @Deprecated("") - public override fun processResource(resource: String?, `is`: InputStream?, relocators: MutableList?) { - // stub - } - - /** - * @param resource ignored parameter - * @param resourceInput resource input stream to save in temp file - * for next stage - * @param relocators relocators to keep for next stage - * @throws IOException thrown by file writing errors - */ - @Throws(IOException::class) - public override fun processResource( - resource: String?, resourceInput: InputStream, relocators: MutableList?, time: Long - ) { - val tempFile = Files.createTempFile("Log4j2Plugins", "dat") - Files.copy(resourceInput, tempFile, StandardCopyOption.REPLACE_EXISTING) - tempFiles.add(tempFile) - youngestTime = max(youngestTime.toDouble(), time.toDouble()).toLong() - - if (relocators != null) { - this.tempRelocators.addAll(relocators) - } - } - - /** - * @return true if any dat file collected - */ - public override fun hasTransformedResource(): Boolean { - return tempFiles.size > 0 - } - - /** - * Stores all previously collected log4j-cache-files to the target jar. - * - * @param jos jar output - * @throws IOException When the IO blows up - */ - @Throws(IOException::class) - public override fun modifyOutputStream(jos: JarOutputStream) { - try { - val aggregator: PluginCache = PluginCache() - aggregator.loadCacheFiles(this.urls) - relocatePlugin(tempRelocators, aggregator.getAllCategories()) - putJarEntry(jos) - // prevent the aggregator to close the jar output - val outputStream: CloseShieldOutputStream = CloseShieldOutputStream(jos) - aggregator.writeCache(outputStream) - } finally { - deleteTempFiles() - } - } - - @get:Throws(MalformedURLException::class) - private val urls: Enumeration - get() { - val urls: MutableList = ArrayList() - for (tempFile in tempFiles) { - val url = tempFile.toUri().toURL() - urls.add(url) - } - return Collections.enumeration(urls) - } - - /** - * Applies the given `relocators` to the `aggregator`. - * - * @param relocators relocators. - * @param aggregatorCategories all categories of the aggregator - */ - /* default */ - public fun relocatePlugin( - relocators: MutableList, - aggregatorCategories: MutableMap?> - ) { - for (categoryEntry in aggregatorCategories.entries) { - for (pluginMapEntry in categoryEntry.value!!.entries) { - val pluginEntry: PluginEntry = pluginMapEntry.value!! - val originalClassName = pluginEntry.getClassName() - - val matchingRelocator: Relocator? = findFirstMatchingRelocator(originalClassName, relocators) - - if (matchingRelocator != null) { - val newClassName: String? = matchingRelocator.relocateClass(originalClassName) - pluginEntry.setClassName(newClassName) - } - } - } - } - - private fun findFirstMatchingRelocator(originalClassName: String?, relocators: MutableList): Relocator? { - var result: Relocator? = null - for (relocator in relocators) { - if (relocator.canRelocateClass(originalClassName)) { - result = relocator - break - } - } - return result - } - - @Throws(IOException::class) - private fun putJarEntry(jos: JarOutputStream) { - val jarEntry: JarEntry = JarEntry(PluginProcessor.PLUGIN_CACHE_FILE) - - // Set time to youngest timestamp, to ensure reproducible output. - val fileTime = FileTime.fromMillis(youngestTime) - jarEntry.setLastModifiedTime(fileTime) - - jos.putNextEntry(jarEntry) - } - - @Throws(IOException::class) - private fun deleteTempFiles() { - val pathIterator = tempFiles.listIterator() - while (pathIterator.hasNext()) { - val path = pathIterator.next() - Files.deleteIfExists(path) - pathIterator.remove() - } - } -} diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt index ad1769630..25f92e21c 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt @@ -4,12 +4,16 @@ import com.github.jengelman.gradle.plugins.shadow.ShadowStats import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext.Companion.getEntryTimestamp -import java.io.File import java.net.URL +import java.nio.file.Path import java.util.Collections import java.util.Enumeration +import kotlin.io.path.createTempFile +import kotlin.io.path.deleteIfExists +import kotlin.io.path.outputStream import org.apache.commons.io.output.CloseShieldOutputStream import org.apache.logging.log4j.core.config.plugins.processor.PluginCache +import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor import org.apache.tools.zip.ZipEntry import org.apache.tools.zip.ZipOutputStream @@ -25,8 +29,15 @@ import org.gradle.api.file.FileTreeElement */ @CacheableTransformer public open class Log4j2PluginsCacheFileTransformer : Transformer { - private val temporaryFiles = mutableListOf() - private val relocators = mutableListOf() + /** + * Log4j config files to share across the transformation stages. + */ + private val tempFiles = mutableListOf() + + /** + * [Relocator] instances to share across the transformation stages. + */ + private val tempRelocators = mutableListOf() private var stats: ShadowStats? = null override fun canTransformResource(element: FileTreeElement): Boolean { @@ -34,55 +45,85 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { } override fun transform(context: TransformerContext) { - val temporaryFile = File.createTempFile("Log4j2Plugins", ".dat") - temporaryFile.deleteOnExit() - temporaryFiles.add(temporaryFile) + val temporaryFile = createTempFile("Log4j2Plugins", ".dat") + tempFiles.add(temporaryFile) val fos = temporaryFile.outputStream() context.inputStream.use { it.copyTo(fos) } - relocators.addAll(context.relocators) + tempRelocators.addAll(context.relocators) if (stats == null) { stats = context.stats } } + /** + * @return true if any dat file collected + */ override fun hasTransformedResource(): Boolean { - // This functionality matches the original plugin, however, I'm not clear what - // the exact logic is. From what I can tell temporaryFiles should be never be empty - // if anything has been performed. - return temporaryFiles.isNotEmpty() || relocators.isNotEmpty() + return tempFiles.isNotEmpty() } override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) { - val pluginCache = PluginCache() - pluginCache.loadCacheFiles(urlEnumeration) - relocatePlugins(pluginCache) - val entry = ZipEntry(PluginProcessor.PLUGIN_CACHE_FILE) - entry.time = getEntryTimestamp(preserveFileTimestamps, entry.time) - os.putNextEntry(entry) - pluginCache.writeCache(CloseShieldOutputStream.wrap(os)) - temporaryFiles.clear() + try { + val aggregator = PluginCache() + aggregator.loadCacheFiles(urlEnumeration) + relocatePlugin(tempRelocators, aggregator.allCategories) + val entry = ZipEntry(PluginProcessor.PLUGIN_CACHE_FILE) + entry.time = getEntryTimestamp(preserveFileTimestamps, entry.time) + os.putNextEntry(entry) + aggregator.writeCache(CloseShieldOutputStream.wrap(os)) + } finally { + deleteTempFiles() + } } - private fun relocatePlugins(pluginCache: PluginCache) { - pluginCache.allCategories.values.forEach { currentMap -> - currentMap.values.forEach { currentPluginEntry -> - val className = currentPluginEntry.className - val relocateClassContext = RelocateClassContext(className, requireNotNull(stats)) - relocators.firstOrNull { it.canRelocateClass(className) }?.let { relocator -> - // Then we perform that relocation and update the plugin entry to reflect the new value. - currentPluginEntry.className = relocator.relocateClass(relocateClassContext) + /** + * Applies the given `relocators` to the `aggregator`. + * + * @param relocators relocators. + * @param aggregatorCategories all categories of the aggregator + */ + private fun relocatePlugin( + relocators: List, + aggregatorCategories: Map>, + ) { + for (categoryEntry in aggregatorCategories.entries) { + for (pluginMapEntry in categoryEntry.value.entries) { + val pluginEntry = pluginMapEntry.value + val originalClassName = pluginEntry.className + val relocateClassContext = RelocateClassContext(originalClassName, requireNotNull(stats)) + + findFirstMatchingRelocator(originalClassName, relocators)?.let { + pluginEntry.className = it.relocateClass(relocateClassContext) } } } } + private fun findFirstMatchingRelocator(originalClassName: String, relocators: List): Relocator? { + for (relocator in relocators) { + if (relocator.canRelocateClass(originalClassName)) { + return relocator + } + } + return null + } + + private fun deleteTempFiles() { + val pathIterator = tempFiles.listIterator() + while (pathIterator.hasNext()) { + val path = pathIterator.next() + path.deleteIfExists() + pathIterator.remove() + } + } + private val urlEnumeration: Enumeration get() { - val urls = temporaryFiles.map { it.toURI().toURL() } + val urls = tempFiles.map { it.toUri().toURL() } return Collections.enumeration(urls) } } From bb07bfef12ae934f900e6ddbd50c09458a26e254 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Jan 2025 17:07:50 +0800 Subject: [PATCH 04/15] Cleanups --- .../Log4j2PluginsCacheFileTransformer.kt | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt index 25f92e21c..56cd2f189 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt @@ -60,7 +60,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { } /** - * @return true if any dat file collected + * @return `true` if any dat file collected. */ override fun hasTransformedResource(): Boolean { return tempFiles.isNotEmpty() @@ -74,6 +74,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { val entry = ZipEntry(PluginProcessor.PLUGIN_CACHE_FILE) entry.time = getEntryTimestamp(preserveFileTimestamps, entry.time) os.putNextEntry(entry) + // prevent the aggregator to close the jar output. aggregator.writeCache(CloseShieldOutputStream.wrap(os)) } finally { deleteTempFiles() @@ -84,7 +85,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { * Applies the given `relocators` to the `aggregator`. * * @param relocators relocators. - * @param aggregatorCategories all categories of the aggregator + * @param aggregatorCategories all categories of the aggregator. */ private fun relocatePlugin( relocators: List, @@ -96,22 +97,13 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { val originalClassName = pluginEntry.className val relocateClassContext = RelocateClassContext(originalClassName, requireNotNull(stats)) - findFirstMatchingRelocator(originalClassName, relocators)?.let { + relocators.firstOrNull { it.canRelocateClass(originalClassName) }?.let { pluginEntry.className = it.relocateClass(relocateClassContext) } } } } - private fun findFirstMatchingRelocator(originalClassName: String, relocators: List): Relocator? { - for (relocator in relocators) { - if (relocator.canRelocateClass(originalClassName)) { - return relocator - } - } - return null - } - private fun deleteTempFiles() { val pathIterator = tempFiles.listIterator() while (pathIterator.hasNext()) { From e51d79cad0030007b8c14bce15c16089f1fc5402 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Jan 2025 17:19:46 +0800 Subject: [PATCH 05/15] Copy Log4j2PluginCacheFileTransformerTest.java Updated to https://github.com/apache/logging-log4j-transform/blob/8d6538acc50ed819d21987e69fe94b485ee0d368/log4j-transform-maven-shade-plugin-extensions/src/test/java/org/apache/logging/log4j/maven/plugins/shade/transformer/Log4j2PluginCacheFileTransformerTest.java --- .../Log4j2PluginCacheFileTransformerTest.java | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java new file mode 100644 index 000000000..6e232a622 --- /dev/null +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.jengelman.gradle.plugins.shadow.transformers; + +import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.core.config.plugins.processor.PluginCache; +import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry; +import org.apache.maven.plugins.shade.relocation.Relocator; +import org.apache.maven.plugins.shade.relocation.SimpleRelocator; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Arrays; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; + +import static java.util.Collections.enumeration; +import static java.util.Collections.singletonList; +import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE; +import static org.junit.jupiter.api.Assertions.*; + +final class Log4j2PluginCacheFileTransformerTest { + + private static URL pluginUrl; + + @BeforeAll + public static void setUp() { + pluginUrl = Log4j2PluginCacheFileTransformerTest.class.getClassLoader().getResource(PLUGIN_CACHE_FILE); + } + + @Test + public void testCanTransformResource() { + final Log4j2PluginCacheFileTransformer transformer = new Log4j2PluginCacheFileTransformer(); + assertFalse(transformer.canTransformResource(null)); + assertFalse(transformer.canTransformResource("")); + assertFalse(transformer.canTransformResource(".")); + assertFalse(transformer.canTransformResource("tmp.dat")); + assertFalse(transformer.canTransformResource(PLUGIN_CACHE_FILE + ".tmp")); + assertFalse(transformer.canTransformResource("tmp/" + PLUGIN_CACHE_FILE)); + assertTrue(transformer.canTransformResource(PLUGIN_CACHE_FILE)); + } + + @Test + public void test() throws Exception { + final Log4j2PluginCacheFileTransformer transformer = new Log4j2PluginCacheFileTransformer(); + assertFalse(transformer.hasTransformedResource()); + + long expectedYoungestResourceTime = 1605922127000L; // Sat Nov 21 2020 01:28:47 + try (InputStream log4jCacheFileInputStream = + getClass().getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE)) { + transformer.processResource( + PLUGIN_CACHE_FILE, log4jCacheFileInputStream, null, expectedYoungestResourceTime); + } + assertTrue(transformer.hasTransformedResource()); + + try (InputStream log4jCacheFileInputStream = + getClass().getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE)) { + transformer.processResource(PLUGIN_CACHE_FILE, log4jCacheFileInputStream, null, 2000L); + } + assertTrue(transformer.hasTransformedResource()); + + assertTransformedCacheFile(transformer, expectedYoungestResourceTime, 1911442937); + } + + private void assertTransformedCacheFile( + @SuppressWarnings("SameParameterValue") Log4j2PluginCacheFileTransformer transformer, + @SuppressWarnings("SameParameterValue") long expectedTime, + @SuppressWarnings("SameParameterValue") long expectedHash) + throws IOException { + final ByteArrayOutputStream jarBuff = new ByteArrayOutputStream(); + try (final JarOutputStream out = new JarOutputStream(jarBuff)) { + transformer.modifyOutputStream(out); + } + + try (JarInputStream in = new JarInputStream(new ByteArrayInputStream(jarBuff.toByteArray()))) { + for (; ; ) { + final JarEntry jarEntry = in.getNextJarEntry(); + if (jarEntry == null) { + fail("No expected resource in the output jar"); + } else if (jarEntry.getName().equals(PLUGIN_CACHE_FILE)) { + assertEquals(expectedTime, jarEntry.getTime()); + assertEquals(expectedHash, Arrays.hashCode(IOUtils.toByteArray(in))); + break; + } + } + } + } + + @Test + public void testRelocation() throws IOException { + // test with matching relocator + testRelocation("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging"); + + // test without matching relocator + testRelocation("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging"); + } + + private void testRelocation(final String src, final String pattern, final String target) throws IOException { + final Log4j2PluginCacheFileTransformer transformer = new Log4j2PluginCacheFileTransformer(); + final Relocator log4jRelocator = new SimpleRelocator(src, pattern, null, null); + final PluginCache aggregator = new PluginCache(); + aggregator.loadCacheFiles(enumeration(singletonList(pluginUrl))); + + transformer.relocatePlugin(singletonList(log4jRelocator), aggregator.getAllCategories()); + + for (final Map pluginEntryMap : + aggregator.getAllCategories().values()) { + for (final PluginEntry entry : pluginEntryMap.values()) { + assertTrue(entry.getClassName().startsWith(target)); + } + } + } + + @AfterAll + public static void tearDown() { + pluginUrl = null; + } +} From a621360a5efff8d99d82d1e0d0f2f062f058887c Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Jan 2025 17:40:01 +0800 Subject: [PATCH 06/15] Convert Log4j2PluginCacheFileTransformerTest to Kotlin --- .../Log4j2PluginsCacheFileTransformer.kt | 4 +- .../Log4j2PluginCacheFileTransformerTest.java | 140 ------------------ .../Log4j2PluginCacheFileTransformerTest.kt | 122 +++++++++++++++ .../Log4j2PluginsCacheFileTransformerTest.kt | 19 ++- .../core/config/plugins/Log4j2Plugins.dat | Bin 0 -> 17923 bytes 5 files changed, 138 insertions(+), 147 deletions(-) delete mode 100644 src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java create mode 100644 src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt create mode 100644 src/test/resources/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt index 56cd2f189..1f33673cf 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt @@ -20,8 +20,6 @@ import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement /** - * Modified from the maven equivalent to work with gradle - * * Modified from [org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformer.java](https://github.com/apache/logging-log4j-transform/blob/main/log4j-transform-maven-shade-plugin-extensions/src/main/java/org/apache/logging/log4j/maven/plugins/shade/transformer/Log4j2PluginCacheFileTransformer.java). * * @author Paul Nelson Baker @@ -87,7 +85,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { * @param relocators relocators. * @param aggregatorCategories all categories of the aggregator. */ - private fun relocatePlugin( + internal fun relocatePlugin( relocators: List, aggregatorCategories: Map>, ) { diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java deleted file mode 100644 index 6e232a622..000000000 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.github.jengelman.gradle.plugins.shadow.transformers; - -import org.apache.commons.io.IOUtils; -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache; -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry; -import org.apache.maven.plugins.shade.relocation.Relocator; -import org.apache.maven.plugins.shade.relocation.SimpleRelocator; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Arrays; -import java.util.Map; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; -import java.util.jar.JarOutputStream; - -import static java.util.Collections.enumeration; -import static java.util.Collections.singletonList; -import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE; -import static org.junit.jupiter.api.Assertions.*; - -final class Log4j2PluginCacheFileTransformerTest { - - private static URL pluginUrl; - - @BeforeAll - public static void setUp() { - pluginUrl = Log4j2PluginCacheFileTransformerTest.class.getClassLoader().getResource(PLUGIN_CACHE_FILE); - } - - @Test - public void testCanTransformResource() { - final Log4j2PluginCacheFileTransformer transformer = new Log4j2PluginCacheFileTransformer(); - assertFalse(transformer.canTransformResource(null)); - assertFalse(transformer.canTransformResource("")); - assertFalse(transformer.canTransformResource(".")); - assertFalse(transformer.canTransformResource("tmp.dat")); - assertFalse(transformer.canTransformResource(PLUGIN_CACHE_FILE + ".tmp")); - assertFalse(transformer.canTransformResource("tmp/" + PLUGIN_CACHE_FILE)); - assertTrue(transformer.canTransformResource(PLUGIN_CACHE_FILE)); - } - - @Test - public void test() throws Exception { - final Log4j2PluginCacheFileTransformer transformer = new Log4j2PluginCacheFileTransformer(); - assertFalse(transformer.hasTransformedResource()); - - long expectedYoungestResourceTime = 1605922127000L; // Sat Nov 21 2020 01:28:47 - try (InputStream log4jCacheFileInputStream = - getClass().getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE)) { - transformer.processResource( - PLUGIN_CACHE_FILE, log4jCacheFileInputStream, null, expectedYoungestResourceTime); - } - assertTrue(transformer.hasTransformedResource()); - - try (InputStream log4jCacheFileInputStream = - getClass().getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE)) { - transformer.processResource(PLUGIN_CACHE_FILE, log4jCacheFileInputStream, null, 2000L); - } - assertTrue(transformer.hasTransformedResource()); - - assertTransformedCacheFile(transformer, expectedYoungestResourceTime, 1911442937); - } - - private void assertTransformedCacheFile( - @SuppressWarnings("SameParameterValue") Log4j2PluginCacheFileTransformer transformer, - @SuppressWarnings("SameParameterValue") long expectedTime, - @SuppressWarnings("SameParameterValue") long expectedHash) - throws IOException { - final ByteArrayOutputStream jarBuff = new ByteArrayOutputStream(); - try (final JarOutputStream out = new JarOutputStream(jarBuff)) { - transformer.modifyOutputStream(out); - } - - try (JarInputStream in = new JarInputStream(new ByteArrayInputStream(jarBuff.toByteArray()))) { - for (; ; ) { - final JarEntry jarEntry = in.getNextJarEntry(); - if (jarEntry == null) { - fail("No expected resource in the output jar"); - } else if (jarEntry.getName().equals(PLUGIN_CACHE_FILE)) { - assertEquals(expectedTime, jarEntry.getTime()); - assertEquals(expectedHash, Arrays.hashCode(IOUtils.toByteArray(in))); - break; - } - } - } - } - - @Test - public void testRelocation() throws IOException { - // test with matching relocator - testRelocation("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging"); - - // test without matching relocator - testRelocation("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging"); - } - - private void testRelocation(final String src, final String pattern, final String target) throws IOException { - final Log4j2PluginCacheFileTransformer transformer = new Log4j2PluginCacheFileTransformer(); - final Relocator log4jRelocator = new SimpleRelocator(src, pattern, null, null); - final PluginCache aggregator = new PluginCache(); - aggregator.loadCacheFiles(enumeration(singletonList(pluginUrl))); - - transformer.relocatePlugin(singletonList(log4jRelocator), aggregator.getAllCategories()); - - for (final Map pluginEntryMap : - aggregator.getAllCategories().values()) { - for (final PluginEntry entry : pluginEntryMap.values()) { - assertTrue(entry.getClassName().startsWith(target)); - } - } - } - - @AfterAll - public static void tearDown() { - pluginUrl = null; - } -} diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt new file mode 100644 index 000000000..ef9780ab6 --- /dev/null +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt @@ -0,0 +1,122 @@ +package com.github.jengelman.gradle.plugins.shadow.transformers + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import assertk.assertions.isTrue +import assertk.fail +import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator +import com.github.jengelman.gradle.plugins.shadow.util.SimpleRelocator +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.net.URL +import java.util.Collections +import java.util.jar.JarInputStream +import org.apache.commons.io.IOUtils +import org.apache.logging.log4j.core.config.plugins.processor.PluginCache +import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE +import org.apache.tools.zip.ZipOutputStream +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class Log4j2PluginCacheFileTransformerTest { + + private var pluginUrl: URL? = null + + @BeforeAll + fun setUp() { + pluginUrl = Log4j2PluginCacheFileTransformerTest::class.java.getClassLoader() + .getResource(PLUGIN_CACHE_FILE) + } + + @AfterAll + fun tearDown() { + pluginUrl = null + } + + @Test + @Throws(Exception::class) + fun test() { + val transformer = Log4j2PluginsCacheFileTransformer() + assertThat(transformer.hasTransformedResource()).isFalse() + + val expectedYoungestResourceTime = 1605922127000L // Sat Nov 21 2020 01:28:47 + javaClass.getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE) + .use { log4jCacheFileInputStream -> + transformer.transform( + TransformerContext.builder() + .path(PLUGIN_CACHE_FILE) + .inputStream(requireNotNull(log4jCacheFileInputStream)) + .build(), + ) + } + assertThat(transformer.hasTransformedResource()).isTrue() + + javaClass.getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE) + .use { log4jCacheFileInputStream -> + transformer.transform( + TransformerContext.builder() + .path(PLUGIN_CACHE_FILE) + .inputStream(requireNotNull(log4jCacheFileInputStream)) + .build(), + ) + } + assertThat(transformer.hasTransformedResource()).isTrue() + + assertTransformedCacheFile(transformer, expectedYoungestResourceTime, 1911442937) + } + + @Throws(IOException::class) + private fun assertTransformedCacheFile( + transformer: Log4j2PluginsCacheFileTransformer, + expectedTime: Long, + expectedHash: Long, + ) { + val jarBuff = ByteArrayOutputStream() + ZipOutputStream(jarBuff).use { out -> + transformer.modifyOutputStream(requireNotNull(out), false) + } + JarInputStream(ByteArrayInputStream(jarBuff.toByteArray())).use { inputStream -> + while (true) { + val jarEntry = inputStream.nextJarEntry + if (jarEntry == null) { + fail("No expected resource in the output jar") + } else if (jarEntry.getName() == PLUGIN_CACHE_FILE) { + assertThat(expectedTime).isEqualTo(jarEntry.getTime()) + assertThat(expectedHash).isEqualTo(IOUtils.toByteArray(inputStream).contentHashCode().toLong()) + break + } + } + } + } + + @Test + @Throws(IOException::class) + fun testRelocation() { + // test with matching relocator + testRelocation("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging") + + // test without matching relocator + testRelocation("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging") + } + + @Throws(IOException::class) + private fun testRelocation(src: String?, pattern: String?, target: String) { + val transformer = Log4j2PluginsCacheFileTransformer() + val log4jRelocator: Relocator = SimpleRelocator(src, pattern) + val aggregator = PluginCache() + aggregator.loadCacheFiles(Collections.enumeration(mutableListOf(pluginUrl))) + + transformer.relocatePlugin(listOf(log4jRelocator), aggregator.allCategories) + + for (pluginEntryMap in aggregator.allCategories.values) { + for (entry in pluginEntryMap.values) { + assertThat(entry.className.startsWith(target)).isTrue() + } + } + } +} diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt index 3a24dec71..7c3381ada 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt @@ -2,6 +2,7 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import assertk.assertThat import assertk.assertions.isEqualTo +import assertk.assertions.isFalse import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsStream import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator @@ -10,10 +11,24 @@ import java.io.File import java.net.URI import java.util.Collections import org.apache.logging.log4j.core.config.plugins.processor.PluginCache +import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE import org.apache.tools.zip.ZipOutputStream import org.junit.jupiter.api.Test +/** + * Modified from [org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformerTest.java](https://github.com/apache/logging-log4j-transform/blob/main/log4j-transform-maven-shade-plugin-extensions/src/test/java/org/apache/logging/log4j/maven/plugins/shade/transformer/Log4j2PluginCacheFileTransformerTest.java). + */ class Log4j2PluginsCacheFileTransformerTest : BaseTransformerTest() { + @Test + fun canTransformResource() { + assertThat(transformer.canTransformResource("")).isFalse() + assertThat(transformer.canTransformResource(".")).isFalse() + assertThat(transformer.canTransformResource("tmp.dat")).isFalse() + assertThat(transformer.canTransformResource("$PLUGIN_CACHE_FILE.tmp")).isFalse() + assertThat(transformer.canTransformResource("tmp/$PLUGIN_CACHE_FILE")).isFalse() + assertThat(transformer.canTransformResource(PLUGIN_CACHE_FILE)).isTrue() + } + @Test fun shouldTransform() { transformer.transform(context(SimpleRelocator())) @@ -51,8 +66,4 @@ class Log4j2PluginsCacheFileTransformerTest : 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 YS_b!C_m3ocyexEz Date: Tue, 21 Jan 2025 18:06:11 +0800 Subject: [PATCH 07/15] Check element.relativePath.pathString in canTransformResource --- .../transformers/Log4j2PluginsCacheFileTransformer.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt index 1f33673cf..9e2e5f4d3 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt @@ -14,7 +14,7 @@ import kotlin.io.path.outputStream import org.apache.commons.io.output.CloseShieldOutputStream import org.apache.logging.log4j.core.config.plugins.processor.PluginCache import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry -import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor +import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE import org.apache.tools.zip.ZipEntry import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement @@ -39,7 +39,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { private var stats: ShadowStats? = null override fun canTransformResource(element: FileTreeElement): Boolean { - return PluginProcessor.PLUGIN_CACHE_FILE == element.name + return PLUGIN_CACHE_FILE == element.relativePath.pathString } override fun transform(context: TransformerContext) { @@ -69,7 +69,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { val aggregator = PluginCache() aggregator.loadCacheFiles(urlEnumeration) relocatePlugin(tempRelocators, aggregator.allCategories) - val entry = ZipEntry(PluginProcessor.PLUGIN_CACHE_FILE) + val entry = ZipEntry(PLUGIN_CACHE_FILE) entry.time = getEntryTimestamp(preserveFileTimestamps, entry.time) os.putNextEntry(entry) // prevent the aggregator to close the jar output. From fc60777212cbb99aa500852385f4885211bcb036 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 23 Jan 2025 10:31:53 +0800 Subject: [PATCH 08/15] Fix Log4j2PluginCacheFileTransformerTest --- .../Log4j2PluginCacheFileTransformerTest.kt | 120 ++++++------------ 1 file changed, 41 insertions(+), 79 deletions(-) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt index ef9780ab6..79f089189 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt @@ -5,112 +5,58 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue import assertk.fail -import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator +import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsStream +import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator import com.github.jengelman.gradle.plugins.shadow.util.SimpleRelocator -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream -import java.io.IOException import java.net.URL import java.util.Collections import java.util.jar.JarInputStream -import org.apache.commons.io.IOUtils import org.apache.logging.log4j.core.config.plugins.processor.PluginCache import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE import org.apache.tools.zip.ZipOutputStream -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class Log4j2PluginCacheFileTransformerTest { - - private var pluginUrl: URL? = null - - @BeforeAll - fun setUp() { - pluginUrl = Log4j2PluginCacheFileTransformerTest::class.java.getClassLoader() - .getResource(PLUGIN_CACHE_FILE) - } - - @AfterAll - fun tearDown() { - pluginUrl = null - } +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +class Log4j2PluginCacheFileTransformerTest : BaseTransformerTest() { @Test - @Throws(Exception::class) - fun test() { - val transformer = Log4j2PluginsCacheFileTransformer() + fun transformAndModifyOutputStream() { assertThat(transformer.hasTransformedResource()).isFalse() - val expectedYoungestResourceTime = 1605922127000L // Sat Nov 21 2020 01:28:47 - javaClass.getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE) - .use { log4jCacheFileInputStream -> - transformer.transform( - TransformerContext.builder() - .path(PLUGIN_CACHE_FILE) - .inputStream(requireNotNull(log4jCacheFileInputStream)) - .build(), - ) - } + transformer.transform(context()) assertThat(transformer.hasTransformedResource()).isTrue() - - javaClass.getClassLoader().getResourceAsStream(PLUGIN_CACHE_FILE) - .use { log4jCacheFileInputStream -> - transformer.transform( - TransformerContext.builder() - .path(PLUGIN_CACHE_FILE) - .inputStream(requireNotNull(log4jCacheFileInputStream)) - .build(), - ) - } + transformer.transform(context()) assertThat(transformer.hasTransformedResource()).isTrue() - assertTransformedCacheFile(transformer, expectedYoungestResourceTime, 1911442937) - } - - @Throws(IOException::class) - private fun assertTransformedCacheFile( - transformer: Log4j2PluginsCacheFileTransformer, - expectedTime: Long, - expectedHash: Long, - ) { val jarBuff = ByteArrayOutputStream() - ZipOutputStream(jarBuff).use { out -> - transformer.modifyOutputStream(requireNotNull(out), false) + ZipOutputStream(jarBuff).use { + transformer.modifyOutputStream(it, false) } - JarInputStream(ByteArrayInputStream(jarBuff.toByteArray())).use { inputStream -> + JarInputStream(jarBuff.toByteArray().inputStream()).use { inputStream -> while (true) { val jarEntry = inputStream.nextJarEntry if (jarEntry == null) { - fail("No expected resource in the output jar") - } else if (jarEntry.getName() == PLUGIN_CACHE_FILE) { - assertThat(expectedTime).isEqualTo(jarEntry.getTime()) - assertThat(expectedHash).isEqualTo(IOUtils.toByteArray(inputStream).contentHashCode().toLong()) + fail("No expected resource in the output jar.") + } else if (jarEntry.name == PLUGIN_CACHE_FILE) { + @Suppress("Since15") + assertThat(1911442937L).isEqualTo(inputStream.readAllBytes().contentHashCode().toLong()) break } } } } - @Test - @Throws(IOException::class) - fun testRelocation() { - // test with matching relocator - testRelocation("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging") - - // test without matching relocator - testRelocation("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging") - } - - @Throws(IOException::class) - private fun testRelocation(src: String?, pattern: String?, target: String) { - val transformer = Log4j2PluginsCacheFileTransformer() - val log4jRelocator: Relocator = SimpleRelocator(src, pattern) - val aggregator = PluginCache() - aggregator.loadCacheFiles(Collections.enumeration(mutableListOf(pluginUrl))) - + @ParameterizedTest + @MethodSource("relocationParameters") + fun relocations(pattern: String, shadedPattern: String, target: String) { + val log4jRelocator = SimpleRelocator(pattern, shadedPattern) + val aggregator = PluginCache().apply { + loadCacheFiles(Collections.enumeration(listOf(pluginCacheUrl))) + } + // Init stats to avoid NPE. + transformer.transform(context()) transformer.relocatePlugin(listOf(log4jRelocator), aggregator.allCategories) for (pluginEntryMap in aggregator.allCategories.values) { @@ -119,4 +65,20 @@ class Log4j2PluginCacheFileTransformerTest { } } } + + private fun context(vararg relocator: SimpleRelocator): TransformerContext { + return TransformerContext(PLUGIN_CACHE_FILE, requireResourceAsStream(PLUGIN_CACHE_FILE), relocator.toSet()) + } + + private companion object { + val pluginCacheUrl: URL = requireNotNull(this::class.java.getClassLoader().getResource(PLUGIN_CACHE_FILE)) + + @JvmStatic + fun relocationParameters() = listOf( + // test with matching relocator + Arguments.of("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging"), + // test without matching relocator + Arguments.of("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging"), + ) + } } From 6b1b491d5ab1ff2a0674b13fb9f7bbb6d098567c Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 23 Jan 2025 11:16:07 +0800 Subject: [PATCH 09/15] Merge Log4j2PluginCacheFileTransformerTest into Log4j2PluginsCacheFileTransformerTest --- .../Log4j2PluginCacheFileTransformerTest.kt | 84 ------------------- .../Log4j2PluginsCacheFileTransformerTest.kt | 64 ++++++++++++++ 2 files changed, 64 insertions(+), 84 deletions(-) delete mode 100644 src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt deleted file mode 100644 index 79f089189..000000000 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginCacheFileTransformerTest.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.transformers - -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.fail -import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsStream -import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator -import com.github.jengelman.gradle.plugins.shadow.util.SimpleRelocator -import java.io.ByteArrayOutputStream -import java.net.URL -import java.util.Collections -import java.util.jar.JarInputStream -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache -import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE -import org.apache.tools.zip.ZipOutputStream -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource - -class Log4j2PluginCacheFileTransformerTest : BaseTransformerTest() { - @Test - fun transformAndModifyOutputStream() { - assertThat(transformer.hasTransformedResource()).isFalse() - - transformer.transform(context()) - assertThat(transformer.hasTransformedResource()).isTrue() - transformer.transform(context()) - assertThat(transformer.hasTransformedResource()).isTrue() - - val jarBuff = ByteArrayOutputStream() - ZipOutputStream(jarBuff).use { - transformer.modifyOutputStream(it, false) - } - JarInputStream(jarBuff.toByteArray().inputStream()).use { inputStream -> - while (true) { - val jarEntry = inputStream.nextJarEntry - if (jarEntry == null) { - fail("No expected resource in the output jar.") - } else if (jarEntry.name == PLUGIN_CACHE_FILE) { - @Suppress("Since15") - assertThat(1911442937L).isEqualTo(inputStream.readAllBytes().contentHashCode().toLong()) - break - } - } - } - } - - @ParameterizedTest - @MethodSource("relocationParameters") - fun relocations(pattern: String, shadedPattern: String, target: String) { - val log4jRelocator = SimpleRelocator(pattern, shadedPattern) - val aggregator = PluginCache().apply { - loadCacheFiles(Collections.enumeration(listOf(pluginCacheUrl))) - } - // Init stats to avoid NPE. - transformer.transform(context()) - transformer.relocatePlugin(listOf(log4jRelocator), aggregator.allCategories) - - for (pluginEntryMap in aggregator.allCategories.values) { - for (entry in pluginEntryMap.values) { - assertThat(entry.className.startsWith(target)).isTrue() - } - } - } - - private fun context(vararg relocator: SimpleRelocator): TransformerContext { - return TransformerContext(PLUGIN_CACHE_FILE, requireResourceAsStream(PLUGIN_CACHE_FILE), relocator.toSet()) - } - - private companion object { - val pluginCacheUrl: URL = requireNotNull(this::class.java.getClassLoader().getResource(PLUGIN_CACHE_FILE)) - - @JvmStatic - fun relocationParameters() = listOf( - // test with matching relocator - Arguments.of("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging"), - // test without matching relocator - Arguments.of("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging"), - ) - } -} diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt index 7c3381ada..6af1ffaa1 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt @@ -4,16 +4,23 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue +import assertk.fail import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsStream import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator import com.github.jengelman.gradle.plugins.shadow.util.SimpleRelocator +import java.io.ByteArrayOutputStream import java.io.File import java.net.URI +import java.net.URL import java.util.Collections +import java.util.jar.JarInputStream import org.apache.logging.log4j.core.config.plugins.processor.PluginCache import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE import org.apache.tools.zip.ZipOutputStream import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource /** * Modified from [org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformerTest.java](https://github.com/apache/logging-log4j-transform/blob/main/log4j-transform-maven-shade-plugin-extensions/src/test/java/org/apache/logging/log4j/maven/plugins/shade/transformer/Log4j2PluginCacheFileTransformerTest.java). @@ -63,7 +70,64 @@ class Log4j2PluginsCacheFileTransformerTest : BaseTransformerTest + while (true) { + val jarEntry = inputStream.nextJarEntry + if (jarEntry == null) { + fail("No expected resource in the output jar.") + } else if (jarEntry.name == PLUGIN_CACHE_FILE) { + @Suppress("Since15") + assertThat(1911442937L).isEqualTo(inputStream.readAllBytes().contentHashCode().toLong()) + break + } + } + } + } + + @ParameterizedTest + @MethodSource("relocationParameters") + fun relocations(pattern: String, shadedPattern: String, target: String) { + val log4jRelocator = SimpleRelocator(pattern, shadedPattern) + val aggregator = PluginCache().apply { + loadCacheFiles(Collections.enumeration(listOf(pluginCacheUrl))) + } + // Init stats to avoid NPE. + transformer.transform(context()) + transformer.relocatePlugin(listOf(log4jRelocator), aggregator.allCategories) + + for (pluginEntryMap in aggregator.allCategories.values) { + for (entry in pluginEntryMap.values) { + assertThat(entry.className.startsWith(target)).isTrue() + } + } + } + private fun context(vararg relocator: SimpleRelocator): TransformerContext { return TransformerContext(PLUGIN_CACHE_FILE, requireResourceAsStream(PLUGIN_CACHE_FILE), relocator.toSet()) } + + private companion object { + val pluginCacheUrl: URL = requireNotNull(this::class.java.classLoader.getResource(PLUGIN_CACHE_FILE)) + + @JvmStatic + fun relocationParameters() = listOf( + // test with matching relocator + Arguments.of("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging"), + // test without matching relocator + Arguments.of("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging"), + ) + } } From f397f2a8d1ff20c12e74301527d294aedfce9d6e Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 23 Jan 2025 11:19:33 +0800 Subject: [PATCH 10/15] Remove redundant shouldTransform and shouldTransformForSingleFile --- .../Log4j2PluginsCacheFileTransformerTest.kt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt index 6af1ffaa1..19fadb68a 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt @@ -36,18 +36,6 @@ class Log4j2PluginsCacheFileTransformerTest : BaseTransformerTest Date: Thu, 23 Jan 2025 11:21:15 +0800 Subject: [PATCH 11/15] Cleanups --- .../transformers/Log4j2PluginsCacheFileTransformerTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt index 19fadb68a..d6616a8c3 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt @@ -90,7 +90,8 @@ class Log4j2PluginsCacheFileTransformerTest : BaseTransformerTest(listOf(pluginCacheUrl))) + val resources = Collections.enumeration(listOf(pluginCacheUrl)) + loadCacheFiles(resources) } // Init stats to avoid NPE. transformer.transform(context()) From 6118e82eb0222a1e7dc4b3d42390c6b9329b86c7 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 23 Jan 2025 11:27:15 +0800 Subject: [PATCH 12/15] Revert changes on relocatePlugins --- .../Log4j2PluginsCacheFileTransformer.kt | 29 ++++++------------- .../Log4j2PluginsCacheFileTransformerTest.kt | 6 ++-- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt index 9e2e5f4d3..b99559a68 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformer.kt @@ -13,7 +13,6 @@ import kotlin.io.path.deleteIfExists import kotlin.io.path.outputStream import org.apache.commons.io.output.CloseShieldOutputStream import org.apache.logging.log4j.core.config.plugins.processor.PluginCache -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE import org.apache.tools.zip.ZipEntry import org.apache.tools.zip.ZipOutputStream @@ -68,7 +67,7 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { try { val aggregator = PluginCache() aggregator.loadCacheFiles(urlEnumeration) - relocatePlugin(tempRelocators, aggregator.allCategories) + relocatePlugins(aggregator) val entry = ZipEntry(PLUGIN_CACHE_FILE) entry.time = getEntryTimestamp(preserveFileTimestamps, entry.time) os.putNextEntry(entry) @@ -79,24 +78,14 @@ public open class Log4j2PluginsCacheFileTransformer : Transformer { } } - /** - * Applies the given `relocators` to the `aggregator`. - * - * @param relocators relocators. - * @param aggregatorCategories all categories of the aggregator. - */ - internal fun relocatePlugin( - relocators: List, - aggregatorCategories: Map>, - ) { - for (categoryEntry in aggregatorCategories.entries) { - for (pluginMapEntry in categoryEntry.value.entries) { - val pluginEntry = pluginMapEntry.value - val originalClassName = pluginEntry.className - val relocateClassContext = RelocateClassContext(originalClassName, requireNotNull(stats)) - - relocators.firstOrNull { it.canRelocateClass(originalClassName) }?.let { - pluginEntry.className = it.relocateClass(relocateClassContext) + internal fun relocatePlugins(pluginCache: PluginCache) { + pluginCache.allCategories.values.forEach { currentMap -> + currentMap.values.forEach { currentPluginEntry -> + val className = currentPluginEntry.className + val relocateClassContext = RelocateClassContext(className, requireNotNull(stats)) + tempRelocators.firstOrNull { it.canRelocateClass(className) }?.let { relocator -> + // Then we perform that relocation and update the plugin entry to reflect the new value. + currentPluginEntry.className = relocator.relocateClass(relocateClassContext) } } } diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt index d6616a8c3..ddc69512e 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt @@ -88,14 +88,12 @@ class Log4j2PluginsCacheFileTransformerTest : BaseTransformerTest Date: Thu, 23 Jan 2025 13:42:03 +0800 Subject: [PATCH 13/15] Add a functional test --- build.gradle.kts | 1 + .../gradle/plugins/shadow/BasePluginTest.kt | 2 +- .../shadow/transformers/TransformersTest.kt | 34 +++++++++++++++++- .../core/config/plugins/Log4j2Plugins.dat | Bin 0 -> 17923 bytes 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/functionalTest/resources/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat diff --git a/build.gradle.kts b/build.gradle.kts index 20f9bdff9..76b3a3099 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -110,6 +110,7 @@ testing.suites { implementation(libs.apache.maven.modelBuilder) implementation(libs.moshi) implementation(libs.moshi.kotlin) + implementation(libs.apache.log4j) } } diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt index 088095ef0..6784c94f4 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt @@ -334,7 +334,7 @@ abstract class BasePluginTest { return transform { it.task(taskPath)?.outcome }.isNotNull().isEqualTo(expectedOutcome) } - private fun requireResourceAsPath(name: String): Path { + fun requireResourceAsPath(name: String): Path { val resource = this::class.java.classLoader.getResource(name) ?: throw NoSuchFileException("Resource $name not found.") return resource.toURI().toPath() diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt index f16e4265d..a337e8018 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt @@ -1,15 +1,20 @@ package com.github.jengelman.gradle.plugins.shadow.transformers +import assertk.all import assertk.assertThat import assertk.assertions.isEqualTo +import assertk.assertions.isNotEqualTo import assertk.assertions.isNotNull import assertk.assertions.isNull import com.github.jengelman.gradle.plugins.shadow.util.Issue +import com.github.jengelman.gradle.plugins.shadow.util.getStream import com.github.jengelman.gradle.plugins.shadow.util.isRegular import java.util.jar.Attributes import kotlin.io.path.appendText +import kotlin.io.path.readText import kotlin.io.path.writeText import kotlin.reflect.KClass +import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource @@ -65,6 +70,34 @@ class TransformersTest : BaseTransformerTest() { assertThat(mf.mainAttributes.getValue("New-Entry")).isNull() } + @Test + fun canMergeLog4j2PluginCacheFiles() { + val content = requireResourceAsPath(PLUGIN_CACHE_FILE).readText() + val one = buildJarOne { + insert(PLUGIN_CACHE_FILE, content) + } + val two = buildJarOne { + insert(PLUGIN_CACHE_FILE, content) + } + projectScriptPath.appendText( + transform( + shadowJarBlock = fromJar(one, two), + ), + ) + + run(shadowJarTask) + + val actualFileBytes = outputShadowJar.use { jar -> + @Suppress("Since15") + jar.getStream(PLUGIN_CACHE_FILE).use { it.readAllBytes() } + } + val singleContentBytes = content.toByteArray() + assertThat(actualFileBytes.contentHashCode()).all { + isNotEqualTo(singleContentBytes.contentHashCode()) + isEqualTo(1911442937) + } + } + @Test fun canUseCustomTransformer() { writeMainClass() @@ -137,7 +170,6 @@ class TransformersTest : BaseTransformerTest() { "" to ComponentsXmlResourceTransformer::class, "" to DontIncludeResourceTransformer::class, "{ resource.set(\"test.file\"); file.fileValue(file(\"test/some.file\")) }" to IncludeResourceTransformer::class, - "" to Log4j2PluginsCacheFileTransformer::class, "" to ManifestAppenderTransformer::class, "" to ManifestResourceTransformer::class, "{ keyTransformer = { it.toLowerCase() } }" to PropertiesFileTransformer::class, diff --git a/src/functionalTest/resources/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat b/src/functionalTest/resources/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat new file mode 100644 index 0000000000000000000000000000000000000000..fbe6359f109cd7ee81b48c87d619391f3af4b478 GIT binary patch literal 17923 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 YS_b!C_m3ocyexEz Date: Thu, 23 Jan 2025 13:50:31 +0800 Subject: [PATCH 14/15] Cleanups --- .../plugins/shadow/transformers/TransformersTest.kt | 7 +++++-- .../transformers/Log4j2PluginsCacheFileTransformerTest.kt | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt index a337e8018..5cf04f940 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt @@ -70,6 +70,9 @@ class TransformersTest : BaseTransformerTest() { assertThat(mf.mainAttributes.getValue("New-Entry")).isNull() } + @Issue( + "https://github.com/GradleUp/shadow/issues/427", + ) @Test fun canMergeLog4j2PluginCacheFiles() { val content = requireResourceAsPath(PLUGIN_CACHE_FILE).readText() @@ -91,9 +94,9 @@ class TransformersTest : BaseTransformerTest() { @Suppress("Since15") jar.getStream(PLUGIN_CACHE_FILE).use { it.readAllBytes() } } - val singleContentBytes = content.toByteArray() assertThat(actualFileBytes.contentHashCode()).all { - isNotEqualTo(singleContentBytes.contentHashCode()) + // Hash of the original plugin cache file. + isNotEqualTo(-2114104185) isEqualTo(1911442937) } } diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt index ddc69512e..19c082d4c 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/Log4j2PluginsCacheFileTransformerTest.kt @@ -1,8 +1,10 @@ package com.github.jengelman.gradle.plugins.shadow.transformers +import assertk.all import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFalse +import assertk.assertions.isNotEqualTo import assertk.assertions.isTrue import assertk.fail import com.github.jengelman.gradle.plugins.shadow.internal.requireResourceAsStream @@ -78,7 +80,11 @@ class Log4j2PluginsCacheFileTransformerTest : BaseTransformerTest Date: Thu, 23 Jan 2025 14:03:54 +0800 Subject: [PATCH 15/15] Note this change --- src/docs/changes/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index 05b84067d..435fbf8ff 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,10 @@ ## [Unreleased] +**Fixed** + +- Fix `Log4j2PluginsCacheFileTransformer` not working for merging `Log4j2Plugins.dat` files. ([#1175](https://github.com/GradleUp/shadow/pull/1175)) + ## [v9.0.0-beta5] (2025-01-21)