Skip to content

Commit d59d947

Browse files
authored
Fix the regression of PropertiesFileTransformer in 8.3.7 (#1493)
Defaults `PropertiesFileTransformer.keyTransformer` to a copy of `Closure.IDENTITY`. We can't use `Closure.IDENTITY` instead, as it is not compatible with Groovy 3 and 4.
1 parent 00df3c9 commit d59d947

File tree

9 files changed

+247
-30
lines changed

9 files changed

+247
-30
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ on:
55
branches:
66
- 8.x
77
pull_request:
8+
branches:
9+
- 8.x
810
workflow_dispatch:
911

1012
jobs:

src/docs/changes/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
## [Unreleased]
55

6+
**Fixed**
7+
8+
- Fix the regression of `PropertiesFileTransformer` in `8.3.7`. ([#1493](https://github.com/GradleUp/shadow/pull/1493))
9+
610
**Changed**
711

812
- Expose Ant as `compile` scope. ([#1488](https://github.com/GradleUp/shadow/pull/1488))

src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.github.jengelman.gradle.plugins.shadow.internal
22

3+
import groovy.transform.CompileStatic
4+
5+
@CompileStatic
36
class CleanProperties extends Properties {
47

58
private static class StripCommentsWithTimestampBufferedWriter extends BufferedWriter {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ class PropertiesFileTransformer implements Transformer {
136136
String charset = 'ISO_8859_1'
137137

138138
@Internal
139-
Closure<String> keyTransformer = IDENTITY
139+
Closure<String> keyTransformer = new Closure<String>("") {
140+
String doCall(Object arguments) { arguments } // We can't use Closure#IDENTITY instead, as it is not compatible with Groovy 3 and 4.
141+
}
140142

141143
@Override
142144
boolean canTransformResource(FileTreeElement element) {
@@ -192,6 +194,9 @@ class PropertiesFileTransformer implements Transformer {
192194
}
193195

194196
private Properties transformKeys(Properties properties) {
197+
if (keyTransformer == null) {
198+
throw new IllegalStateException("keyTransformer must not be null.")
199+
}
195200
if (keyTransformer == IDENTITY) {
196201
return properties
197202
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
package com.github.jengelman.gradle.plugins.shadow
2+
3+
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
4+
import com.github.jengelman.gradle.plugins.shadow.util.PluginSpecification
5+
import spock.lang.Issue
6+
import spock.lang.Unroll
7+
8+
class PropertiesFileTransformerSpec extends PluginSpecification {
9+
10+
@Unroll
11+
def 'merge properties with different strategies: #mergeStrategy'() {
12+
given:
13+
File one = buildJar('one.jar')
14+
.insertFile('test.properties',
15+
'key1=one\nkey2=one').write()
16+
17+
File two = buildJar('two.jar')
18+
.insertFile('test.properties',
19+
'key2=two\nkey3=two').write()
20+
21+
buildFile << """
22+
import ${PropertiesFileTransformer.name}
23+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
24+
from('${escapedPath(one)}')
25+
from('${escapedPath(two)}')
26+
}
27+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
28+
transform(PropertiesFileTransformer) {
29+
paths = ['test.properties']
30+
mergeSeparator = ";"
31+
mergeStrategy = '${mergeStrategy}'
32+
}
33+
}
34+
""".stripIndent()
35+
36+
when:
37+
run('shadowJar')
38+
39+
then:
40+
assert output.exists()
41+
42+
and:
43+
String text = getJarFileContents(output, 'test.properties')
44+
def lines = text.replace('#', '').trim().split("\\r?\\n").toList()
45+
assert lines.size() == 3
46+
switch (mergeStrategy) {
47+
case 'first':
48+
assert lines.containsAll(['key1=one', 'key2=one', 'key3=two'])
49+
break
50+
case 'latest':
51+
assert lines.containsAll(['key1=one', 'key2=two', 'key3=two'])
52+
break
53+
case 'append':
54+
assert lines.containsAll(['key1=one', 'key2=one;two', 'key3=two'])
55+
break
56+
default:
57+
assert false: "Unknown mergeStrategy: $mergeStrategy"
58+
}
59+
60+
where:
61+
mergeStrategy << ['first', 'latest', 'append']
62+
}
63+
64+
def 'merge properties with key transformer'() {
65+
given:
66+
File one = buildJar('one.jar')
67+
.insertFile('META-INF/test.properties', 'foo=bar')
68+
.write()
69+
70+
File two = buildJar('two.jar')
71+
.insertFile('META-INF/test.properties', 'FOO=baz')
72+
.write()
73+
74+
buildFile << """
75+
import ${PropertiesFileTransformer.name}
76+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
77+
from('${escapedPath(one)}')
78+
from('${escapedPath(two)}')
79+
}
80+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
81+
transform(PropertiesFileTransformer) {
82+
paths = ['META-INF/test.properties']
83+
mergeStrategy = 'append'
84+
keyTransformer = { key -> key.toUpperCase() }
85+
}
86+
}
87+
""".stripIndent()
88+
89+
when:
90+
run('shadowJar')
91+
92+
then:
93+
output.exists()
94+
String text = getJarFileContents(output, 'META-INF/test.properties')
95+
text.contains('FOO=bar,baz')
96+
}
97+
98+
def 'merge properties with specified charset'() {
99+
given:
100+
File one = buildJar('one.jar')
101+
.insertFile('META-INF/utf8.properties', 'foo=第一')
102+
.write()
103+
104+
File two = buildJar('two.jar')
105+
.insertFile('META-INF/utf8.properties', 'foo=第二')
106+
.write()
107+
108+
buildFile << """
109+
import ${PropertiesFileTransformer.name}
110+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
111+
from('${escapedPath(one)}')
112+
from('${escapedPath(two)}')
113+
}
114+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
115+
transform(PropertiesFileTransformer) {
116+
paths = ['META-INF/utf8.properties']
117+
mergeStrategy = 'append'
118+
charset = 'UTF-8'
119+
}
120+
}
121+
""".stripIndent()
122+
123+
when:
124+
run('shadowJar')
125+
126+
then:
127+
output.exists()
128+
String text = getJarFileContents(output, 'META-INF/utf8.properties')
129+
text.contains('foo=第一,第二')
130+
}
131+
132+
def 'merge properties with mappings'() {
133+
given:
134+
File one = buildJar('one.jar')
135+
.insertFile('META-INF/foo.properties', 'foo=1')
136+
.insertFile('META-INF/bar.properties', 'bar=2')
137+
.write()
138+
139+
File two = buildJar('two.jar')
140+
.insertFile('META-INF/foo.properties', 'foo=3')
141+
.insertFile('META-INF/bar.properties', 'bar=4')
142+
.write()
143+
144+
buildFile << """
145+
import ${PropertiesFileTransformer.name}
146+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
147+
from('${escapedPath(one)}')
148+
from('${escapedPath(two)}')
149+
}
150+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
151+
transform(PropertiesFileTransformer) {
152+
mappings = [
153+
'META-INF/foo.properties': [mergeStrategy: 'append', mergeSeparator: ';'],
154+
'META-INF/bar.properties': [mergeStrategy: 'latest']
155+
]
156+
}
157+
}
158+
""".stripIndent()
159+
160+
when:
161+
run('shadowJar')
162+
163+
then:
164+
output.exists()
165+
166+
and:
167+
String fooText = getJarFileContents(output, 'META-INF/foo.properties')
168+
fooText.contains('foo=1;3')
169+
170+
and:
171+
String barText = getJarFileContents(output, 'META-INF/bar.properties')
172+
barText.contains('bar=4')
173+
}
174+
175+
@Issue(
176+
['https://github.com/GradleUp/shadow/issues/622',
177+
'https://github.com/GradleUp/shadow/issues/856'
178+
]
179+
)
180+
def 'merged properties dont contain date comment'() {
181+
given:
182+
File one = buildJar('one.jar')
183+
.insertFile('META-INF/test.properties', 'foo=one')
184+
.write()
185+
186+
File two = buildJar('two.jar')
187+
.insertFile('META-INF/test.properties', 'foo=two')
188+
.write()
189+
190+
buildFile << """
191+
import ${PropertiesFileTransformer.name}
192+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
193+
from('${escapedPath(one)}')
194+
from('${escapedPath(two)}')
195+
}
196+
tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
197+
transform(PropertiesFileTransformer) {
198+
paths = ['META-INF/test.properties']
199+
mergeStrategy = 'append'
200+
}
201+
}
202+
""".stripIndent()
203+
204+
when:
205+
run('shadowJar')
206+
207+
then:
208+
output.exists()
209+
String text = getJarFileContents(output, 'META-INF/test.properties')
210+
text.replace('#', '').trim() == 'foo=one,two'
211+
}
212+
}

src/test/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowPluginSpec.groovy

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ class ShadowPluginSpec extends PluginSpecification {
387387
package client;
388388
import junit.framework.TestCase;
389389
public class Client extends TestCase {
390-
public static void main(String[] args) {}
390+
public static void main(String[] args) {}
391391
}
392392
""".stripIndent()
393393
@@ -1029,7 +1029,7 @@ class ShadowPluginSpec extends PluginSpecification {
10291029
version = '1.0'
10301030
repositories { maven { url = "${repo.uri}" } }
10311031
dependencies { api project(':api') }
1032-
1032+
10331033
shadowJar.minimize()
10341034
""".stripIndent()
10351035
@@ -1247,8 +1247,4 @@ class ShadowPluginSpec extends PluginSpecification {
12471247
JarFile jar = new JarFile(output)
12481248
assert jar.entries().collect().findAll { it.name.endsWith('.class') }.size() == 1
12491249
}
1250-
1251-
private String escapedPath(File file) {
1252-
file.path.replaceAll('\\\\', '\\\\\\\\')
1253-
}
12541250
}

0 commit comments

Comments
 (0)