diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocationContext.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocationContext.kt index f7ada4233..3777e3259 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocationContext.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocationContext.kt @@ -12,6 +12,30 @@ public fun Relocator.relocatePath(path: String): String { return relocatePath(RelocatePathContext(path)) } +/** + * Relocates all matching class and package names in the given [text]. + * + * Unlike [relocateClass], which operates on a single class name (subject to prefix/format checks in + * [Relocator.canRelocateClass] and single-occurrence replacement), this function performs global + * replacement across arbitrary text content (e.g. `MANIFEST.MF` attributes or ProGuard/R8 rules). + * + * For [SimpleRelocator], it directly replaces all occurrences of [SimpleRelocator.pattern] with + * [SimpleRelocator.shadedPattern]. For generic [Relocator]s, it delegates to [relocateClass] if + * applicable. + */ +internal fun Relocator.relocateText(text: String): String { + if (this is SimpleRelocator) { + return when { + pattern.isEmpty() -> text + else -> text.replace(pattern, shadedPattern) + } + } + return when { + canRelocateClass(text) -> relocateClass(text) + else -> text + } +} + public fun Iterable.relocateClass(className: String): String { forEach { relocator -> if (relocator.canRelocateClass(className)) { @@ -29,3 +53,14 @@ public fun Iterable.relocatePath(path: String): String { } return path } + +/** + * Sequentially relocates all matching class and package names in the given [text] across all + * relocators in this collection. + * + * Unlike [Iterable.relocateClass] which stops at the first matching relocator, this function passes + * the text through every relocator in a chain-of-responsibility pipeline so that all patterns + * present in the text are relocated. + */ +internal fun Iterable.relocateText(text: String): String = + fold(text) { acc, relocator -> relocator.relocateText(acc) } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ProGuardFilesResourceTransformer.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ProGuardFilesResourceTransformer.kt index f5034fb06..9efcea339 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ProGuardFilesResourceTransformer.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ProGuardFilesResourceTransformer.kt @@ -3,8 +3,8 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import com.github.jengelman.gradle.plugins.shadow.internal.checkDupStrategy import com.github.jengelman.gradle.plugins.shadow.internal.writeEntry import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator -import com.github.jengelman.gradle.plugins.shadow.relocation.relocateClass import com.github.jengelman.gradle.plugins.shadow.relocation.relocatePath +import com.github.jengelman.gradle.plugins.shadow.relocation.relocateText import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement import org.gradle.api.tasks.Internal @@ -50,20 +50,10 @@ constructor(patternSet: PatternSet = PatternSet().include("META-INF/proguard/**" } internal companion object { - /** - * Matches Java class names, fully qualified class names, package wildcards (e.g. `com.foo.**`), - * and inner classes (`com.foo.Bar$Inner`). - */ - private val CLASS_PATTERN = - """(?.relocateRuleLine(line: String): String { return when { line.isBlank() || line.trimStart().startsWith("#") -> line - else -> - CLASS_PATTERN.replace(line) { matchResult -> - relocateClass(matchResult.value) - } + else -> relocateText(line) } } } diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt index 55f8c48b7..a2af78c71 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt @@ -40,6 +40,27 @@ class RelocatorsTest { .isEqualTo("shadow.org.package.Bar") } + @Test + fun relocateTextChained() { + val relocators = + listOf( + SimpleRelocator("org.foo", "shaded.foo"), + SimpleRelocator("org.bar", "shaded.bar"), + ) + assertThat(relocators.relocateText("org.foo.Foo, org.bar.Bar and other.Baz")) + .isEqualTo("shaded.foo.Foo, shaded.bar.Bar and other.Baz") + } + + @Test + fun relocateTextOrder() { + val relocators = + listOf( + SimpleRelocator("org.foo", "org.bar"), + SimpleRelocator("org.bar", "org.baz"), + ) + assertThat(relocators.relocateText("org.foo.Foo")).isEqualTo("org.baz.Foo") + } + private companion object { val primitiveTypes = setOf('B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z') diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt index 4a88226aa..26ab52707 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt @@ -219,6 +219,29 @@ class SimpleRelocatorTest { assertThat(relocator.relocateClass("org.foo.bar.Class")).isEqualTo("private.stuff.bar.Class") } + @Test + fun relocateText() { + var relocator = SimpleRelocator("org.foo") + assertThat( + relocator.relocateText("org.foo.bar.Class, hidden.org.foo.bar.Class and org.foo.bar.Class") + ) + .isEqualTo( + "hidden.org.foo.bar.Class, hidden.hidden.org.foo.bar.Class and hidden.org.foo.bar.Class" + ) + + relocator = SimpleRelocator("org.foo", "private.stuff") + assertThat( + relocator.relocateText("org.foo.bar.Class, private.stuff.bar.Class and org.foo.bar.Class") + ) + .isEqualTo("private.stuff.bar.Class, private.stuff.bar.Class and private.stuff.bar.Class") + + relocator = SimpleRelocator() + assertThat(relocator.relocateText("org.foo.bar.Class")).isEqualTo("org.foo.bar.Class") + + relocator = SimpleRelocator("org.foo", "shaded.foo", rawString = true) + assertThat(relocator.relocateText("org.foo.bar.Class")).isEqualTo("org.foo.bar.Class") + } + @Test fun relocateRawString() { var relocator = SimpleRelocator("Lorg/foo", "Lhidden/org/foo", rawString = true)