Skip to content

Commit 53203e1

Browse files
authored
Document more about eachFile, filesMatching, and filesNotMatching (#1682)
* Mention `eachFile` and `filesNotMatching` * New steps * Use `ParameterizedTest` for `strategyCanBeOverriddenByEachFile` * Cleanups * Add more examples * Merge duplicate steps * Add the optional step at the last
1 parent 619a512 commit 53203e1

File tree

3 files changed

+158
-33
lines changed

3 files changed

+158
-33
lines changed

docs/configuration/merging/README.md

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,117 @@ Different strategies will lead to different results for `foo/bar` files in the J
7777
```
7878

7979
The [`ResourceTransformer`][ResourceTransformer]s like [`ServiceFileTransformer`][ServiceFileTransformer] will not work
80-
as expected as the duplicate resource files fed for them are excluded beforehand. However, this behavior might be what you expected for duplicate `foo/bar` files, preventing them from being included.
80+
as expected as the duplicate resource files fed for them are excluded beforehand. However, this behavior might be what
81+
you expected for duplicate `foo/bar` files, preventing them from being included.
8182

82-
Want [`ResourceTransformer`][ResourceTransformer]s and `duplicatesStrategy` to work together? There are several steps
83-
to take:
83+
Want [`ResourceTransformer`][ResourceTransformer]s and `duplicatesStrategy` to work together? There are several common
84+
steps to take:
8485

85-
1. Set the strategy to `INCLUDE` or `WARN`.
86+
1. Set the default strategy to `INCLUDE` or `WARN`.
8687
2. Apply your [`ResourceTransformer`][ResourceTransformer]s.
8788
3. Remove duplicate entries by
88-
- overriding the default strategy for specific files using [`filesMatching`][Jar.filesMatching]
89+
- overriding the default strategy for specific files to `EXCLUDE` or `FAIL` using
90+
[`filesMatching`][Jar.filesMatching], [`filesNotMatching`][Jar.filesNotMatching], or [`eachFile`][Jar.eachFile] functions
8991
- or applying [`PreserveFirstFoundResourceTransformer`][PreserveFirstFoundResourceTransformer] for specific files
9092
- or write your own [`ResourceTransformer`][ResourceTransformer] to handle duplicates
9193
- or mechanism similar.
92-
4. Optionally, enable [`ShadowJar.failOnDuplicateEntries`][ShadowJar.failOnDuplicateEntries] to check duplicate entries in the final JAR.
93-
5. Optionally, use [Diffuse](https://github.com/JakeWharton/diffuse) to diff the JARs.
94+
95+
Alternatively, you can follow these steps:
96+
97+
1. Set the default strategy to `EXCLUDE` or `FAIL`.
98+
2. Apply your [`ResourceTransformer`][ResourceTransformer]s.
99+
3. Bypass the duplicate entries which should be handled by the [`ResourceTransformer`][ResourceTransformer]s using
100+
[`filesMatching`][Jar.filesMatching], [`filesNotMatching`][Jar.filesNotMatching], or [`eachFile`][Jar.eachFile] functions
101+
to set their `duplicatesStrategy` to `INCLUDE` or `WARN`.
102+
103+
Optional steps:
104+
105+
- Enable [`ShadowJar.failOnDuplicateEntries`][ShadowJar.failOnDuplicateEntries] to check duplicate entries in the final JAR.
106+
- Use [Diffuse](https://github.com/JakeWharton/diffuse) to diff the JARs.
107+
108+
Here are some examples:
109+
110+
=== "Kotlin"
111+
112+
```kotlin
113+
tasks.shadowJar {
114+
// Step 1.
115+
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
116+
// Step 2.
117+
mergeServiceFiles()
118+
// Step 3. Using `filesNotMatching`:
119+
filesNotMatching("META-INF/services/**") {
120+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
121+
}
122+
// Step 3. Using `PreserveFirstFoundResourceTransformer`:
123+
transform<com.github.jengelman.gradle.plugins.shadow.transformers.PreserveFirstFoundResourceTransformer>() {
124+
resources.add("META-INF/foo/**") // Or something else where the first occurrence should be preserved.
125+
}
126+
}
127+
128+
tasks.shadowJar {
129+
// Step 1.
130+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
131+
// Step 2.
132+
mergeServiceFiles()
133+
// Step 3. Using `filesMatching`:
134+
filesMatching("META-INF/services/**") {
135+
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
136+
}
137+
// Step 3. Using `eachFile`:
138+
eachFile {
139+
if (path.startsWith("META-INF/services/")) {
140+
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
141+
}
142+
}
143+
}
144+
145+
tasks.shadowJar {
146+
// Optional step.
147+
failOnDuplicateEntries = true
148+
}
149+
```
150+
151+
=== "Groovy"
152+
153+
```groovy
154+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
155+
// Step 1.
156+
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
157+
// Step 2.
158+
mergeServiceFiles()
159+
// Step 3. Using `filesNotMatching`:
160+
filesNotMatching('META-INF/services/**') {
161+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
162+
}
163+
// Step 3. Using `PreserveFirstFoundResourceTransformer`:
164+
transform(com.github.jengelman.gradle.plugins.shadow.transformers.PreserveFirstFoundResourceTransformer) {
165+
resources.add('META-INF/foo/**') // Or something else where the first occurrence should be preserved.
166+
}
167+
}
168+
169+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
170+
// Step 1.
171+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Or FAIL.
172+
// Step 2.
173+
mergeServiceFiles()
174+
// Step 3. Using `filesMatching`:
175+
filesMatching('META-INF/services/**') {
176+
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
177+
}
178+
// Step 3. Using `eachFile`:
179+
eachFile {
180+
if (it.path.startsWith('META-INF/services/')) {
181+
it.duplicatesStrategy = DuplicatesStrategy.INCLUDE // Or WARN.
182+
}
183+
}
184+
}
185+
186+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
187+
// Optional step.
188+
failOnDuplicateEntries = true
189+
}
190+
```
94191

95192
## Basic ResourceTransformer Usage
96193

@@ -451,7 +548,9 @@ It must be added using the [`transform`][ShadowJar.transform] methods.
451548

452549

453550
[AbstractCopyTask]: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.AbstractCopyTask.html
551+
[Jar.eachFile]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:eachFile(org.gradle.api.Action)
454552
[Jar.filesMatching]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:filesMatching(java.lang.Iterable,%20org.gradle.api.Action)
553+
[Jar.filesNotMatching]: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:filesNotMatching(java.lang.Iterable,%20org.gradle.api.Action)
455554
[AppendingTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-appending-transformer/index.html
456555
[DuplicatesStrategy]: https://docs.gradle.org/current/javadoc/org/gradle/api/file/DuplicatesStrategy.html
457556
[GroovyExtensionModuleTransformer]: ../../api/shadow/com.github.jengelman.gradle.plugins.shadow.transformers/-groovy-extension-module-transformer/index.html

src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import com.github.jengelman.gradle.plugins.shadow.util.getContent
88
import kotlin.io.path.appendText
99
import kotlin.io.path.writeText
1010
import org.gradle.api.file.DuplicatesStrategy
11+
import org.gradle.api.file.DuplicatesStrategy.EXCLUDE
12+
import org.gradle.api.file.DuplicatesStrategy.FAIL
13+
import org.gradle.api.file.DuplicatesStrategy.INCLUDE
14+
import org.gradle.api.file.DuplicatesStrategy.INHERIT
15+
import org.gradle.api.file.DuplicatesStrategy.WARN
1116
import org.junit.jupiter.api.Test
1217
import org.junit.jupiter.params.ParameterizedTest
1318
import org.junit.jupiter.params.provider.Arguments
@@ -221,8 +226,8 @@ class ServiceFileTransformerTest : BaseTransformerTest() {
221226
}
222227

223228
@Test
224-
fun strategyExcludeCanBeOverriddenByFilesMatching() {
225-
writeDuplicatesStrategy(DuplicatesStrategy.EXCLUDE)
229+
fun strategyCanBeOverriddenByFilesMatching() {
230+
writeDuplicatesStrategy(EXCLUDE)
226231
projectScript.appendText(
227232
"""
228233
$shadowJarTask {
@@ -242,8 +247,8 @@ class ServiceFileTransformerTest : BaseTransformerTest() {
242247
}
243248

244249
@Test
245-
fun strategyIncludeCanBeOverriddenByFilesNotMatching() {
246-
writeDuplicatesStrategy(DuplicatesStrategy.INCLUDE)
250+
fun strategyCanBeOverriddenByFilesNotMatching() {
251+
writeDuplicatesStrategy(INCLUDE)
247252
projectScript.appendText(
248253
"""
249254
$shadowJarTask {
@@ -262,6 +267,34 @@ class ServiceFileTransformerTest : BaseTransformerTest() {
262267
}
263268
}
264269

270+
@ParameterizedTest
271+
@MethodSource("eachFileStrategyProvider")
272+
fun strategyCanBeOverriddenByEachFile(
273+
default: DuplicatesStrategy,
274+
override: DuplicatesStrategy,
275+
matchPath: String,
276+
) {
277+
writeDuplicatesStrategy(default)
278+
projectScript.appendText(
279+
"""
280+
$shadowJarTask {
281+
eachFile {
282+
if (path == '$matchPath') {
283+
duplicatesStrategy = DuplicatesStrategy.$override
284+
}
285+
}
286+
}
287+
""".trimIndent(),
288+
)
289+
290+
run(shadowJarPath)
291+
292+
assertThat(outputShadowedJar).useAll {
293+
getContent(ENTRY_SERVICES_SHADE).isEqualTo(CONTENT_ONE_TWO)
294+
getContent(ENTRY_SERVICES_FOO).isEqualTo("one")
295+
}
296+
}
297+
265298
private fun writeDuplicatesStrategy(strategy: DuplicatesStrategy) {
266299
projectScript.appendText(
267300
"""
@@ -279,21 +312,21 @@ class ServiceFileTransformerTest : BaseTransformerTest() {
279312
private companion object {
280313
@JvmStatic
281314
fun withThrowingProvider() = listOf(
282-
Arguments.of(
283-
DuplicatesStrategy.FAIL,
284-
"Cannot copy zip entry .* to .* because zip entry .* has already been copied there",
285-
),
286-
Arguments.of(
287-
DuplicatesStrategy.INHERIT,
288-
"Entry .* is a duplicate but no duplicate handling strategy has been set",
289-
),
315+
Arguments.of(FAIL, "Cannot copy zip entry .* to .* because zip entry .* has already been copied there"),
316+
Arguments.of(INHERIT, "Entry .* is a duplicate but no duplicate handling strategy has been set"),
290317
)
291318

292319
@JvmStatic
293320
fun withoutThrowingProvider() = listOf(
294-
Arguments.of(DuplicatesStrategy.EXCLUDE, CONTENT_ONE, "one"),
295-
Arguments.of(DuplicatesStrategy.INCLUDE, CONTENT_ONE_TWO, "one\ntwo"),
296-
Arguments.of(DuplicatesStrategy.WARN, CONTENT_ONE_TWO, "one\ntwo"),
321+
Arguments.of(EXCLUDE, CONTENT_ONE, "one"),
322+
Arguments.of(INCLUDE, CONTENT_ONE_TWO, "one\ntwo"),
323+
Arguments.of(WARN, CONTENT_ONE_TWO, "one\ntwo"),
324+
)
325+
326+
@JvmStatic
327+
fun eachFileStrategyProvider() = listOf(
328+
Arguments.of(EXCLUDE, INCLUDE, ENTRY_SERVICES_SHADE),
329+
Arguments.of(INCLUDE, EXCLUDE, ENTRY_SERVICES_FOO),
297330
)
298331
}
299332
}

src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowJar.kt

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,19 +219,12 @@ public abstract class ShadowJar : Jar() {
219219
* **NOTE:** The strategy takes precedence over transforming and relocating.
220220
* Some [ResourceTransformer]s like [ServiceFileTransformer] will not work as expected with setting the strategy to
221221
* [EXCLUDE] (the default), as the duplicate resource files fed for them are excluded beforehand.
222-
* Want [ResourceTransformer]s and the strategy to work together? There are several steps to take:
223-
*
224-
* 1. Set the strategy to [INCLUDE] or [WARN].
225-
* 2. Apply your [ResourceTransformer]s.
226-
* 3. Remove duplicate entries by
227-
* - overriding the default strategy for specific files using [filesMatching]
228-
* - or applying `PreserveFirstFoundResourceTransformer` for specific files
229-
* - or write your own `ResourceTransformer`s to handle duplicates
230-
* - or mechanism similar.
231-
* 4. Optionally, enable [failOnDuplicateEntries] to check duplicate entries in the final JAR.
232-
* 5. Optionally, use [Diffuse](https://github.com/JakeWharton/diffuse) to diff the JARs.
222+
* Want [ResourceTransformer]s and the strategy to work together? See more details in the
223+
* [Handling Duplicates Strategy](https://gradleup.com/shadow/configuration/merging/#handling-duplicates-strategy) section.
233224
*
225+
* @see [eachFile]
234226
* @see [filesMatching]
227+
* @see [filesNotMatching]
235228
* @see [DuplicatesStrategy]
236229
* @see [CopySpec.duplicatesStrategy]
237230
*/

0 commit comments

Comments
 (0)