Skip to content

Commit 12d9197

Browse files
committed
Support relocating rules
1 parent c6dd36b commit 12d9197

File tree

5 files changed

+131
-20
lines changed

5 files changed

+131
-20
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.github.jengelman.gradle.plugins.shadow.transformers
2+
3+
import assertk.assertThat
4+
import assertk.assertions.isEqualTo
5+
import com.github.jengelman.gradle.plugins.shadow.testkit.getContent
6+
import kotlin.io.path.appendText
7+
import org.junit.jupiter.api.Test
8+
9+
class ProGuardTransformerTest : BaseTransformerTest() {
10+
@Test
11+
fun mergeProGuardFiles() {
12+
val proGuardEntry = "META-INF/proguard/app.pro"
13+
val content1 = "-keep class com.foo.Bar { *; }"
14+
val content2 = "-keep class com.foo.Baz { *; }"
15+
val one = buildJarOne { insert(proGuardEntry, content1) }
16+
val two = buildJarTwo { insert(proGuardEntry, content2) }
17+
val config = transform<ProGuardTransformer>(dependenciesBlock = implementationFiles(one, two))
18+
projectScript.appendText(config)
19+
20+
runWithSuccess(shadowJarPath)
21+
22+
val content = outputShadowedJar.use { it.getContent(proGuardEntry) }
23+
assertThat(content).isEqualTo("$content1\n$content2")
24+
}
25+
26+
@Test
27+
fun relocateProGuardFiles() {
28+
val proGuardEntry = "META-INF/proguard/app.pro"
29+
val content = "-keep class org.foo.Service { *; }\n-keep class org.foo.exclude.OtherService"
30+
val one = buildJarOne { insert(proGuardEntry, content) }
31+
val config =
32+
"""
33+
dependencies {
34+
${implementationFiles(one)}
35+
}
36+
$shadowJarTask {
37+
relocate('org.foo', 'borg.foo') {
38+
exclude 'org.foo.exclude.*'
39+
}
40+
transform(com.github.jengelman.gradle.plugins.shadow.transformers.ProGuardTransformer)
41+
}
42+
"""
43+
.trimIndent()
44+
projectScript.appendText(config)
45+
46+
runWithSuccess(shadowJarPath)
47+
48+
val transformedContent = outputShadowedJar.use { it.getContent(proGuardEntry) }
49+
assertThat(transformedContent)
50+
.isEqualTo("-keep class borg.foo.Service { *; }\n-keep class org.foo.exclude.OtherService")
51+
}
52+
}

src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,31 +68,40 @@ constructor(
6868
this.excludes.addAll(excludes)
6969
}
7070

71-
if (!rawString) {
72-
// Create exclude pattern sets for sources.
73-
for (exclude in this.excludes) {
74-
// Excludes should be subpackages of the global pattern.
75-
if (exclude.startsWith(this.pattern)) {
76-
sourcePackageExcludes.add(
77-
exclude.substring(this.pattern.length).replaceFirst("[.][*]$".toRegex(), "")
78-
)
79-
}
80-
// Excludes should be subpackages of the global pattern.
81-
if (exclude.startsWith(pathPattern)) {
82-
sourcePathExcludes.add(
83-
exclude.substring(pathPattern.length).replaceFirst("/[*]$".toRegex(), "")
84-
)
85-
}
71+
updateSourceExcludes()
72+
}
73+
74+
private fun updateSourceExcludes() {
75+
if (rawString) return
76+
sourcePackageExcludes.clear()
77+
sourcePathExcludes.clear()
78+
// Create exclude pattern sets for sources.
79+
for (exclude in this.excludes) {
80+
// Excludes should be subpackages of the global pattern.
81+
if (exclude.startsWith(this.pattern)) {
82+
sourcePackageExcludes.add(
83+
exclude.substring(this.pattern.length).replaceFirst("[.][*]$".toRegex(), "")
84+
)
85+
}
86+
// Excludes should be subpackages of the global pattern.
87+
if (exclude.startsWith(pathPattern)) {
88+
sourcePathExcludes.add(
89+
exclude.substring(pathPattern.length).replaceFirst("/[*]$".toRegex(), "")
90+
)
8691
}
8792
}
8893
}
8994

9095
public open fun include(pattern: String) {
9196
includes.addAll(normalizePatterns(listOf(pattern)))
97+
includes.add(pattern)
98+
updateSourceExcludes()
9299
}
93100

94101
public open fun exclude(pattern: String) {
95102
excludes.addAll(normalizePatterns(listOf(pattern)))
103+
excludes.add(pattern)
104+
updateSourceExcludes()
96105
}
97106

98107
override fun canRelocatePath(path: String): Boolean {
@@ -206,7 +215,7 @@ constructor(
206215
*/
207216
val RX_ENDS_WITH_JAVA_KEYWORD: Pattern =
208217
Pattern.compile(
209-
"\\b(import|package|public|protected|private|static|final|synchronized|abstract|volatile|extends|implements|throws) $" +
218+
"\\b(import|package|class|interface|enum|public|protected|private|static|final|synchronized|abstract|volatile|extends|implements|throws|-keep) $" +
210219
"|" +
211220
"\\{@link( \\*)* $" +
212221
"|" +
@@ -255,9 +264,7 @@ constructor(
255264
// Make sure that search pattern starts at word boundary and that we look for literal ".", not
256265
// regex jokers.
257266
val snippets =
258-
sourceContent
259-
.split(("\\b" + patternFrom.replace(".", "[.]") + "\\b").toRegex())
260-
.filter(CharSequence::isNotEmpty)
267+
sourceContent.split(("\\b" + patternFrom.replace(".", "[.]") + "\\b").toRegex())
261268
snippets.forEachIndexed { i, snippet ->
262269
val isFirstSnippet = i == 0
263270
val previousSnippet = if (isFirstSnippet) "" else snippets[i - 1]

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,16 @@ constructor(patternSet: PatternSet = PatternSet().include(PROGUARD_PATTERN)) :
2121

2222
override fun transform(context: TransformerContext) {
2323
val lines = proGuardEntries.getOrPut(context.path) { mutableListOf() }
24-
context.inputStream.bufferedReader().use { it.readLines() }.forEach { line -> lines.add(line) }
24+
context.inputStream
25+
.bufferedReader()
26+
.use { it.readLines() }
27+
.forEach { line ->
28+
var relocatedLine = line
29+
context.relocators.forEach { relocator ->
30+
relocatedLine = relocator.applyToSourceContent(relocatedLine)
31+
}
32+
lines.add(relocatedLine)
33+
}
2534
}
2635

2736
override fun hasTransformedResource(): Boolean = proGuardEntries.isNotEmpty()

src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,12 @@ class SimpleRelocatorTest {
344344
assertThat(relocator.canRelocatePath("org/foo/Class.class")).isFalse()
345345
}
346346

347+
@Test
348+
fun relocateSourceAtStart() {
349+
val relocator = SimpleRelocator("org.foo", "borg.foo")
350+
assertThat(relocator.applyToSourceContent("org.foo.Bar")).isEqualTo("borg.foo.Bar")
351+
}
352+
347353
@Test
348354
fun relocateSourceWithExcludesRaw() {
349355
val relocator =

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.github.jengelman.gradle.plugins.shadow.transformers
33
import assertk.assertThat
44
import assertk.assertions.isEqualTo
55
import assertk.assertions.isTrue
6+
import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator
67
import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath
78
import com.github.jengelman.gradle.plugins.shadow.testkit.getContent
89
import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream
@@ -75,6 +76,42 @@ class ProGuardTransformerTest : BaseTransformerTest<ProGuardTransformer>() {
7576
assertThat(transformer.canTransformResource("META-INF/custom/rules.pro")).isTrue()
7677
}
7778

79+
@Test
80+
fun relocatedClasses() {
81+
val relocator = SimpleRelocator("org.foo", "borg.foo", excludes = listOf("org.foo.exclude.*"))
82+
val content = "-keep class org.foo.Service { *; }\n-keep class org.foo.exclude.OtherService"
83+
val path = "META-INF/proguard/app.pro"
84+
85+
transformer.transform(textContext(path, content, relocator))
86+
87+
tempJar.outputStream().zipOutputStream().use { zos ->
88+
transformer.modifyOutputStream(zos, false)
89+
}
90+
91+
val transformedContent = JarPath(tempJar).use { it.getContent(path) }
92+
assertThat(transformedContent)
93+
.isEqualTo("-keep class borg.foo.Service { *; }\n-keep class org.foo.exclude.OtherService")
94+
}
95+
96+
@Test
97+
fun mergeRelocatedFiles() {
98+
val relocator = SimpleRelocator("org.foo", "borg.foo", excludes = listOf("org.foo.exclude.*"))
99+
val content1 = "-keep class org.foo.Service { *; }"
100+
val content2 = "-keep class org.foo.exclude.OtherService"
101+
val path = "META-INF/proguard/app.pro"
102+
103+
transformer.transform(textContext(path, content1, relocator))
104+
transformer.transform(textContext(path, content2, relocator))
105+
106+
tempJar.outputStream().zipOutputStream().use { zos ->
107+
transformer.modifyOutputStream(zos, false)
108+
}
109+
110+
val transformedContent = JarPath(tempJar).use { it.getContent(path) }
111+
assertThat(transformedContent)
112+
.isEqualTo("-keep class borg.foo.Service { *; }\n-keep class org.foo.exclude.OtherService")
113+
}
114+
78115
private companion object {
79116
@JvmStatic
80117
fun resourceProvider() =

0 commit comments

Comments
 (0)