Skip to content

Commit aa386eb

Browse files
snazyGoooler
andauthored
Add new merge strategy Fail to PropertiesFileTransformer (#1856)
Co-authored-by: Zongle Wang <[email protected]>
1 parent b332ac6 commit aa386eb

File tree

5 files changed

+59
-7
lines changed

5 files changed

+59
-7
lines changed

api/shadow.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ public class com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesF
434434
public final class com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy : java/lang/Enum {
435435
public static final field Append Lcom/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy;
436436
public static final field Companion Lcom/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy$Companion;
437+
public static final field Fail Lcom/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy;
437438
public static final field First Lcom/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy;
438439
public static final field Latest Lcom/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy;
439440
public static final fun from (Ljava/lang/String;)Lcom/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer$MergeStrategy;

docs/changes/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Expose `patternSet` of `ApacheNoticeResourceTransformer` as `public`. ([#1850](https://github.com/GradleUp/shadow/pull/1850))
1212
- Expose `patternSet` of `PreserveFirstFoundResourceTransformer` as `public`. ([#1855](https://github.com/GradleUp/shadow/pull/1855))
1313
- Support overriding output path of `ApacheNoticeResourceTransformer`. ([#1851](https://github.com/GradleUp/shadow/pull/1851))
14+
- Add new merge strategy `Fail` to `PropertiesFileTransformer`. ([#1856](https://github.com/GradleUp/shadow/pull/1856))
1415

1516
### Changed
1617

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

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.getContent
77
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer.MergeStrategy
88
import com.github.jengelman.gradle.plugins.shadow.util.Issue
99
import kotlin.io.path.appendText
10+
import org.gradle.testkit.runner.TaskOutcome.FAILED
11+
import org.junit.jupiter.api.Assertions.fail
1012
import org.junit.jupiter.api.Test
1113
import org.junit.jupiter.params.ParameterizedTest
1214
import org.junit.jupiter.params.provider.EnumSource
@@ -33,15 +35,29 @@ class PropertiesFileTransformerTest : BaseTransformerTest() {
3335
),
3436
)
3537

36-
runWithSuccess(shadowJarPath)
38+
if (strategy == MergeStrategy.Fail) {
39+
val result = runWithFailure(shadowJarPath)
3740

38-
val expected = when (strategy) {
39-
MergeStrategy.First -> arrayOf("key1=one", "key2=one", "key3=two")
40-
MergeStrategy.Latest -> arrayOf("key1=one", "key2=two", "key3=two")
41-
MergeStrategy.Append -> arrayOf("key1=one", "key2=one;two", "key3=two")
41+
assertThat(result).taskOutcomeEquals(shadowJarPath, FAILED)
42+
assertThat(result.output.replace(lineSeparator, "\n")).contains(
43+
"""
44+
Caused by: java.lang.IllegalStateException: The following properties files have conflicting property values and cannot be merged:
45+
* META-INF/test.properties
46+
* Property key2 is duplicated 2 times with different values
47+
""".trimIndent(),
48+
)
49+
} else {
50+
runWithSuccess(shadowJarPath)
51+
52+
val expected = when (strategy) {
53+
MergeStrategy.First -> arrayOf("key1=one", "key2=one", "key3=two")
54+
MergeStrategy.Latest -> arrayOf("key1=one", "key2=two", "key3=two")
55+
MergeStrategy.Append -> arrayOf("key1=one", "key2=one;two", "key3=two")
56+
else -> fail("Unexpected strategy: $strategy")
57+
}
58+
val content = outputShadowedJar.use { it.getContent("META-INF/test.properties") }
59+
assertThat(content).contains(*expected)
4260
}
43-
val content = outputShadowedJar.use { it.getContent("META-INF/test.properties") }
44-
assertThat(content).contains(*expected)
4561
}
4662

4763
@Test

src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ import org.gradle.api.tasks.Internal
6262
* - key2 = value2;balue2
6363
* - key3 = value3
6464
*
65+
* With `mergeStrategy = MergeStrategy.Fail` the transformation will fail if there are conflicting values.
66+
*
6567
* There are three additional properties that can be set: [paths], [mappings],
6668
* and [keyTransformer].
6769
* The first contains a list of strings or regexes that will be used to determine if
@@ -103,6 +105,9 @@ public open class PropertiesFileTransformer @Inject constructor(
103105
) : ResourceTransformer {
104106
private inline val charset get() = Charset.forName(charsetName.get())
105107

108+
@get:Internal
109+
internal val conflicts: MutableMap<String, MutableMap<String, Int>> = mutableMapOf()
110+
106111
@get:Internal
107112
internal val propertiesEntries = mutableMapOf<String, CleanProperties>()
108113

@@ -156,6 +161,10 @@ public open class PropertiesFileTransformer @Inject constructor(
156161
props[key] = props.getProperty(key as String) + mergeSeparatorFor(context.path) + value
157162
}
158163
MergeStrategy.First -> Unit
164+
MergeStrategy.Fail -> {
165+
val conflictsForPath = conflicts.computeIfAbsent(context.path) { mutableMapOf() }
166+
conflictsForPath.compute(key as String) { _, count -> (count ?: 1) + 1 }
167+
}
159168
}
160169
} else {
161170
props[key] = value
@@ -215,6 +224,15 @@ public open class PropertiesFileTransformer @Inject constructor(
215224
override fun hasTransformedResource(): Boolean = propertiesEntries.isNotEmpty()
216225

217226
override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
227+
if (conflicts.isNotEmpty()) {
228+
val message = "The following properties files have conflicting property values and cannot be merged:" +
229+
conflicts.map { (path, props) ->
230+
path + props.map { "Property ${it.key} is duplicated ${it.value} times with different values" }
231+
.joinToString(separator = "\n * ", prefix = "\n * ")
232+
}.joinToString(separator = "\n * ", prefix = "\n * ")
233+
error(message)
234+
}
235+
218236
// Cannot close the writer as the OutputStream needs to remain open.
219237
val zipWriter = os.writer(charset)
220238
propertiesEntries.forEach { (path, props) ->
@@ -231,6 +249,7 @@ public open class PropertiesFileTransformer @Inject constructor(
231249
First,
232250
Latest,
233251
Append,
252+
Fail,
234253
;
235254

236255
public companion object {

src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class PropertiesFileTransformerTest : BaseTransformerTest<PropertiesFileTransfor
6464
input1: Map<String, String>,
6565
input2: Map<String, String>,
6666
expectedOutput: Map<String, String>,
67+
expectedConflicts: Map<String, Map<String, Int>>,
6768
) {
6869
transformer.mergeStrategy.set(MergeStrategy.from(mergeStrategy))
6970
transformer.mergeSeparator.set(mergeSeparator)
@@ -74,6 +75,7 @@ class PropertiesFileTransformerTest : BaseTransformerTest<PropertiesFileTransfor
7475
}
7576

7677
assertThat(transformer.propertiesEntries[path].orEmpty()).isEqualTo(expectedOutput)
78+
assertThat(transformer.conflicts).isEqualTo(expectedConflicts)
7779
}
7880

7981
@ParameterizedTest
@@ -263,6 +265,7 @@ class PropertiesFileTransformerTest : BaseTransformerTest<PropertiesFileTransfor
263265
mapOf("foo" to "foo"),
264266
mapOf("foo" to "bar"),
265267
mapOf("foo" to "foo"),
268+
mapOf<String, Map<String, Int>>(),
266269
),
267270
Arguments.of(
268271
"f.properties",
@@ -271,6 +274,7 @@ class PropertiesFileTransformerTest : BaseTransformerTest<PropertiesFileTransfor
271274
mapOf("foo" to "foo"),
272275
mapOf("foo" to "bar"),
273276
mapOf("foo" to "bar"),
277+
mapOf<String, Map<String, Int>>(),
274278
),
275279
Arguments.of(
276280
"f.properties",
@@ -279,6 +283,7 @@ class PropertiesFileTransformerTest : BaseTransformerTest<PropertiesFileTransfor
279283
mapOf("foo" to "foo"),
280284
mapOf("foo" to "bar"),
281285
mapOf("foo" to "foo,bar"),
286+
mapOf<String, Map<String, Int>>(),
282287
),
283288
Arguments.of(
284289
"f.properties",
@@ -287,6 +292,16 @@ class PropertiesFileTransformerTest : BaseTransformerTest<PropertiesFileTransfor
287292
mapOf("foo" to "foo"),
288293
mapOf("foo" to "bar"),
289294
mapOf("foo" to "foo;bar"),
295+
mapOf<String, Map<String, Int>>(),
296+
),
297+
Arguments.of(
298+
"f.properties",
299+
"fail",
300+
";",
301+
mapOf("foo" to "foo"),
302+
mapOf("foo" to "bar"),
303+
mapOf("foo" to "foo"),
304+
mapOf("f.properties" to mapOf("foo" to 2)),
290305
),
291306
)
292307

0 commit comments

Comments
 (0)