Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: GradleUp/shadow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9.0.0-beta5
Choose a base ref
...
head repository: GradleUp/shadow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9.0.0-beta6
Choose a head ref
  • 7 commits
  • 13 files changed
  • 4 contributors

Commits on Jan 21, 2025

  1. Prepare next development version

    Goooler committed Jan 21, 2025
    Copy the full SHA
    8ad88ed View commit details

Commits on Jan 23, 2025

  1. Fix and polish Log4j2PluginsCacheFileTransformer (#1175)

    * 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
    
    * Convert Log4j2PluginCacheFileTransformer to Kotlin
    
    * Merge Log4j2PluginCacheFileTransformer into Log4j2PluginsCacheFileTransformer
    
    * Cleanups
    
    * 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
    
    * Convert Log4j2PluginCacheFileTransformerTest to Kotlin
    
    * Check element.relativePath.pathString in canTransformResource
    
    * Fix Log4j2PluginCacheFileTransformerTest
    
    * Merge Log4j2PluginCacheFileTransformerTest into Log4j2PluginsCacheFileTransformerTest
    
    * Remove redundant shouldTransform and shouldTransformForSingleFile
    
    * Cleanups
    
    * Revert changes on relocatePlugins
    
    * Add a functional test
    
    * Note this change
    Goooler authored Jan 23, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    897895c View commit details
  2. Exclude module-info.class in Multi-Release folders by default (#1177)

    Goooler authored Jan 23, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    91fba91 View commit details
  3. Tidy up @issue (#1179)

    Goooler authored Jan 23, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    3f59363 View commit details
  4. Note using Log4j2PluginsCacheFileTransformer in doc (#1178)

    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    Co-authored-by: Piotr P. Karwasz <piotr@github.copernik.eu>
    3 people authored Jan 23, 2025

    Partially verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    1f543ed View commit details
  5. Update plugin com.gradle.develocity to v3.19.1 (#1180)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
    renovate[bot] authored Jan 23, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    fe2931f View commit details
  6. Prepare version 9.0.0-beta6

    Goooler committed Jan 23, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    Goooler Zongle Wang
    Copy the full SHA
    a7bffad View commit details
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -110,6 +110,7 @@ testing.suites {
implementation(libs.apache.maven.modelBuilder)
implementation(libs.moshi)
implementation(libs.moshi.kotlin)
implementation(libs.apache.log4j)
}
}

2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ org.gradle.parallel=true

GROUP=com.gradleup.shadow
POM_ARTIFACT_ID=shadow-gradle-plugin
VERSION_NAME=9.0.0-beta5
VERSION_NAME=9.0.0-beta6

SONATYPE_AUTOMATIC_RELEASE=true
SONATYPE_HOST=DEFAULT
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ pluginManagement {
}

plugins {
id("com.gradle.develocity") version "3.19"
id("com.gradle.develocity") version "3.19.1"
}

develocity {
14 changes: 13 additions & 1 deletion src/docs/changes/README.md
Original file line number Diff line number Diff line change
@@ -4,6 +4,17 @@
## [Unreleased]


## [v9.0.0-beta6] (2025-01-23)

**Added**

- Exclude `module-info.class` in Multi-Release folders by default. ([#1177](https://github.com/GradleUp/shadow/pull/1177))

**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)

**Added**
@@ -478,7 +489,8 @@ Instead, use the `enableRelocation = true` and `relocationPrefix = "<new package



[Unreleased]: https://github.com/GradleUp/shadow/compare/9.0.0-beta5...HEAD
[Unreleased]: https://github.com/GradleUp/shadow/compare/9.0.0-beta6...HEAD
[v9.0.0-beta6]: https://github.com/GradleUp/shadow/releases/tag/9.0.0-beta6
[v9.0.0-beta5]: https://github.com/GradleUp/shadow/releases/tag/9.0.0-beta5
[v9.0.0-beta4]: https://github.com/GradleUp/shadow/releases/tag/9.0.0-beta4
[v9.0.0-beta3]: https://github.com/GradleUp/shadow/releases/tag/9.0.0-beta3
12 changes: 12 additions & 0 deletions src/docs/configuration/merging/README.md
Original file line number Diff line number Diff line change
@@ -176,6 +176,18 @@ tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.Shadow
}
```

## Merging Log4j2 Plugin Cache Files (`Log4j2Plugins.dat`)

`Log4j2PluginsCacheFileTransformer` is a `Transformer` that merges `META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat` plugin caches from all the jars
containing Log4j 2.x Core components. It's a Gradle equivalent of [Log4j Plugin Descriptor Transformer](https://logging.apache.org/log4j/transform/log4j-transform-maven-shade-plugin-extensions.html#log4j-plugin-cache-transformer).

```groovy
// Merging Log4j2 Plugin Cache Files
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer.class)
}
```

## Appending Text Files

Generic text files can be appended together using the
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -197,6 +197,10 @@ class JavaPluginTest : BasePluginTest() {
}
}

@Issue(
"https://github.com/GradleUp/shadow/issues/352",
"https://github.com/GradleUp/shadow/issues/729",
)
@Test
fun excludeSomeMetaInfFilesByDefault() {
localRepo.module("shadow", "a", "1.0") {
@@ -207,6 +211,8 @@ class JavaPluginTest : BasePluginTest() {
insert("META-INF/a.DSA", "DSA Signature Block")
insert("META-INF/a.RSA", "RSA Signature Block")
insert("META-INF/a.properties", "key=value")
insert("META-INF/versions/9/module-info.class", "module myModuleName {}")
insert("META-INF/versions/16/module-info.class", "module myModuleName {}")
insert("module-info.class", "module myModuleName {}")
}
}.publish()
@@ -238,6 +244,8 @@ class JavaPluginTest : BasePluginTest() {
"META-INF/a.SF",
"META-INF/a.DSA",
"META-INF/a.RSA",
"META-INF/versions/9/module-info.class",
"META-INF/versions/16/module-info.class",
"module-info.class",
)
}
Original file line number Diff line number Diff line change
@@ -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
@@ -48,7 +53,9 @@ class TransformersTest : BaseTransformerTest() {
commonAssertions()
}

@Issue("https://github.com/GradleUp/shadow/issues/82")
@Issue(
"https://github.com/GradleUp/shadow/issues/82",
)
@Test
fun shadowManifestLeaksToJarManifest() {
writeMainClass()
@@ -65,6 +72,37 @@ 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()
val one = buildJarOne {
insert(PLUGIN_CACHE_FILE, content)
}
val two = buildJarOne {
insert(PLUGIN_CACHE_FILE, content)
}
projectScriptPath.appendText(
transform<Log4j2PluginsCacheFileTransformer>(
shadowJarBlock = fromJar(one, two),
),
)

run(shadowJarTask)

val actualFileBytes = outputShadowJar.use { jar ->
@Suppress("Since15")
jar.getStream(PLUGIN_CACHE_FILE).use { it.readAllBytes() }
}
assertThat(actualFileBytes.contentHashCode()).all {
// Hash of the original plugin cache file.
isNotEqualTo(-2114104185)
isEqualTo(1911442937)
}
}

@Test
fun canUseCustomTransformer() {
writeMainClass()
@@ -137,7 +175,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,
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -96,6 +96,8 @@ public abstract class ShadowJavaPlugin @Inject constructor(
"META-INF/*.SF",
"META-INF/*.DSA",
"META-INF/*.RSA",
// module-info.class in Multi-Release folders.
"META-INF/versions/**/module-info.class",
"module-info.class",
)
}
Original file line number Diff line number Diff line change
@@ -4,85 +4,105 @@ 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.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

/**
* 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
* @author John Engelman
*/
@CacheableTransformer
public open class Log4j2PluginsCacheFileTransformer : Transformer {
private val temporaryFiles = mutableListOf<File>()
private val relocators = mutableListOf<Relocator>()
/**
* Log4j config files to share across the transformation stages.
*/
private val tempFiles = mutableListOf<Path>()

/**
* [Relocator] instances to share across the transformation stages.
*/
private val tempRelocators = mutableListOf<Relocator>()
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) {
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)
relocatePlugins(aggregator)
val entry = ZipEntry(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()
}
}

private fun relocatePlugins(pluginCache: PluginCache) {
internal 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 ->
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)
}
}
}
}

private fun deleteTempFiles() {
val pathIterator = tempFiles.listIterator()
while (pathIterator.hasNext()) {
val path = pathIterator.next()
path.deleteIfExists()
pathIterator.remove()
}
}

private val urlEnumeration: Enumeration<URL>
get() {
val urls = temporaryFiles.map { it.toURI().toURL() }
val urls = tempFiles.map { it.toUri().toURL() }
return Collections.enumeration(urls)
}
}
Loading