From 8b9b19172f3a642b5b4dc734b9c672c009cc7f62 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 21 Aug 2025 16:36:48 +0800 Subject: [PATCH 1/3] Reuse `RelocationClassWriter` --- .../shadow/internal/RelocationClassWriter.kt | 73 +++++++++++++++++++ .../plugins/shadow/tasks/ShadowCopyAction.kt | 8 +- .../com/xpdustry/ksr/KotlinRelocation.kt | 6 +- .../com/xpdustry/ksr/RelocatingClassWriter.kt | 69 ------------------ 4 files changed, 80 insertions(+), 76 deletions(-) create mode 100644 src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt delete mode 100644 src/main/kotlin/com/xpdustry/ksr/RelocatingClassWriter.kt diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt new file mode 100644 index 000000000..384eeda1c --- /dev/null +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt @@ -0,0 +1,73 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext +import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext +import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator +import java.lang.reflect.Field +import org.objectweb.asm.AnnotationVisitor +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.Opcodes + +internal class RelocationClassWriter( + classReader: ClassReader, + relocators: Set, + flags: Int = 0, +) : ClassWriter(classReader, flags) { + internal var isRelocated = false + + init { + // If the class is a Kotlin class, we need to apply relocations to the symbol table. + if (classReader.isKotlinClass()) { + val symbolTable = symbolTableField.get(this) + + @Suppress("UNCHECKED_CAST") + val entries = entriesField.get(symbolTable) as Array + entries.forEach { entryObj -> + if (entryObj != null) { + (symbolValueField.get(entryObj) as? String)?.let { value -> + val newValue = relocators.applyClassRelocation(value) + if (value != newValue) { + symbolValueField.set(entryObj, newValue) + isRelocated = true + } + } + } + } + } + } + + private fun ClassReader.isKotlinClass(): Boolean { + var flag = false + accept( + object : ClassVisitor(Opcodes.ASM9) { + override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? { + if (desc == "Lkotlin/Metadata;") { + flag = true + } + return super.visitAnnotation(desc, visible) + } + }, + ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES, + ) + return flag + } + + companion object Companion { + private val classWriterClass = ClassWriter::class.java + private val symbolTableClass: Class<*> = Class.forName("org.objectweb.asm.SymbolTable") // Package private. + private val symbolClass: Class<*> = Class.forName("org.objectweb.asm.Symbol") // Package private. + + private val symbolTableField: Field = classWriterClass.getDeclaredField("symbolTable") + .apply { isAccessible = true } + private val entriesField: Field = symbolTableClass.getDeclaredField("entries") + .apply { isAccessible = true } + private val symbolValueField: Field = symbolClass.getDeclaredField("value") + .apply { isAccessible = true } + + fun Iterable.applyClassRelocation(value: String): String = fold(value) { string, relocator -> + relocator.relocateClass(RelocateClassContext(string)) + } + } +} diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt index 1a77b032d..533b79c00 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt @@ -1,5 +1,6 @@ package com.github.jengelman.gradle.plugins.shadow.tasks +import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter import com.github.jengelman.gradle.plugins.shadow.internal.RelocatorRemapper import com.github.jengelman.gradle.plugins.shadow.internal.cast import com.github.jengelman.gradle.plugins.shadow.internal.zipEntry @@ -23,7 +24,6 @@ import org.gradle.api.logging.Logging import org.gradle.api.tasks.WorkResult import org.gradle.api.tasks.WorkResults import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.ClassRemapper /** @@ -162,7 +162,7 @@ public open class ShadowCopyAction( fileDetails.writeToZip(path) return } - fileDetails.remapClass() + fileDetails.remapClass(relocators) } else { val mapped = RelocatorRemapper(relocators).map(path) if (transform(fileDetails, mapped)) return @@ -183,7 +183,7 @@ public open class ShadowCopyAction( * Applies remapping to the given class with the specified relocation path. The remapped class is then written * to the zip file. */ - private fun FileCopyDetails.remapClass() = file.readBytes().let { bytes -> + private fun FileCopyDetails.remapClass(relocators: Set) = file.readBytes().let { bytes -> var modified = false val remapper = RelocatorRemapper(relocators) { modified = true } @@ -192,8 +192,8 @@ public open class ShadowCopyAction( // to the original class names. This is not a problem at runtime (because these entries in the // constant pool are never used), but confuses some tools such as Felix's maven-bundle-plugin // that use the constant pool to determine the dependencies of a class. - val cw = ClassWriter(0) val cr = ClassReader(bytes) + val cw = RelocationClassWriter(classReader = cr, relocators = relocators) val cv = ClassRemapper(cw, remapper) try { diff --git a/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt b/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt index 5ab4967b6..84c0ece80 100644 --- a/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt +++ b/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt @@ -25,6 +25,8 @@ */ package com.xpdustry.ksr +import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter +import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter.Companion.applyClassRelocation import com.github.jengelman.gradle.plugins.shadow.relocation.CacheableRelocator import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext @@ -75,8 +77,6 @@ internal fun relocateMetadata(task: ShadowJar) { internal fun Iterable.applyPathRelocation(value: String): String = fold(value) { string, relocator -> relocator.relocatePath(RelocatePathContext(string)) } -internal fun Iterable.applyClassRelocation(value: String): String = fold(value) { string, relocator -> relocator.relocateClass(RelocateClassContext(string)) } - @CacheableRelocator internal class KotlinRelocator(pattern: String, shadedPattern: String) : SimpleRelocator(pattern, shadedPattern, emptyList(), emptyList()) { // I hate these hacks... @@ -95,7 +95,7 @@ internal class KotlinRelocator(pattern: String, shadedPattern: String) : SimpleR private fun relocateClass(file: Path, relocators: List) { Files.newInputStream(file).use { ins -> val cr = ClassReader(ins) - val cw = RelocatingClassWriter(cr, 0, relocators) + val cw = RelocationClassWriter(cr, relocators.toSet()) val scanner = MetadataAnnotationScanner(cw, relocators) cr.accept(scanner, 0) if (scanner.isRelocated || cw.isRelocated) { diff --git a/src/main/kotlin/com/xpdustry/ksr/RelocatingClassWriter.kt b/src/main/kotlin/com/xpdustry/ksr/RelocatingClassWriter.kt deleted file mode 100644 index 8a9b75129..000000000 --- a/src/main/kotlin/com/xpdustry/ksr/RelocatingClassWriter.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of KSR, a gradle plugin for handling Kotlin metadata relocation. - * - * MIT License - * - * Copyright (c) 2025 Xpdustry - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.xpdustry.ksr - -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassWriter - -internal class RelocatingClassWriter( - reader: ClassReader, - flags: Int, - relocators: List, -) : ClassWriter(reader, flags) { - - internal var isRelocated = false - - init { - val symbolTable = symbolTableField.get(this) - - @Suppress("UNCHECKED_CAST") - val entries = entriesField.get(symbolTable) as Array - entries.forEach { entryObj -> - if (entryObj != null) { - (symbolValueField.get(entryObj) as? String)?.let { value -> - val newValue = relocators.applyPathRelocation(value) - if (value != newValue) { - symbolValueField.set(entryObj, newValue) - isRelocated = true - } - } - } - } - } - - companion object { - private val classWriterClass = ClassWriter::class.java - private val symbolTableClass = Class.forName("org.objectweb.asm.SymbolTable") // Package private. - private val symbolClass = Class.forName("org.objectweb.asm.Symbol") // Package private. - - private val symbolTableField = classWriterClass.getDeclaredField("symbolTable") - .apply { isAccessible = true } - private val entriesField = symbolTableClass.getDeclaredField("entries") - .apply { isAccessible = true } - private val symbolValueField = symbolClass.getDeclaredField("value") - .apply { isAccessible = true } - } -} From 9426a2cf57f752018d608ea4ef9d19d221bd73f8 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 21 Aug 2025 17:40:27 +0800 Subject: [PATCH 2/3] Port `remapKotlinModule` --- .../shadow/internal/RelocationClassWriter.kt | 1 - .../plugins/shadow/tasks/ShadowCopyAction.kt | 76 ++++++++-- .../com/xpdustry/ksr/KotlinRelocation.kt | 131 ------------------ .../ksr/KotlinShadowRelocatorPlugin.kt | 43 ------ .../xpdustry/ksr/MetadataAnnotationScanner.kt | 71 ---------- 5 files changed, 66 insertions(+), 256 deletions(-) delete mode 100644 src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt delete mode 100644 src/main/kotlin/com/xpdustry/ksr/KotlinShadowRelocatorPlugin.kt delete mode 100644 src/main/kotlin/com/xpdustry/ksr/MetadataAnnotationScanner.kt diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt index 384eeda1c..026a1a0b5 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocationClassWriter.kt @@ -1,7 +1,6 @@ package com.github.jengelman.gradle.plugins.shadow.internal import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext -import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import java.lang.reflect.Field import org.objectweb.asm.AnnotationVisitor diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt index 533b79c00..4834f3ddb 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt @@ -1,15 +1,22 @@ package com.github.jengelman.gradle.plugins.shadow.tasks import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter +import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter.Companion.applyClassRelocation import com.github.jengelman.gradle.plugins.shadow.internal.RelocatorRemapper import com.github.jengelman.gradle.plugins.shadow.internal.cast import com.github.jengelman.gradle.plugins.shadow.internal.zipEntry +import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext import java.io.File import java.util.GregorianCalendar import java.util.zip.ZipException +import kotlin.metadata.jvm.JvmMetadataVersion +import kotlin.metadata.jvm.KmModule +import kotlin.metadata.jvm.KmPackageParts +import kotlin.metadata.jvm.KotlinModuleMetadata +import kotlin.metadata.jvm.UnstableMetadataApi import org.apache.tools.zip.UnixStat import org.apache.tools.zip.Zip64RequiredException import org.apache.tools.zip.ZipEntry @@ -156,17 +163,29 @@ public open class ShadowCopyAction( private fun visitFile(fileDetails: FileCopyDetails) { val path = fileDetails.path - if (path.endsWith(".class")) { - if (isUnused(path)) return - if (relocators.isEmpty()) { - fileDetails.writeToZip(path) - return + when { + path.endsWith(".class") -> { + if (isUnused(path)) return + if (relocators.isEmpty()) { + fileDetails.writeToZip(path) + return + } + fileDetails.remapClass(relocators) + } + + path.endsWith(".kotlin_module") -> { + if (relocators.isEmpty()) { + fileDetails.writeToZip(path) + return + } + fileDetails.remapKotlinModule(relocators) + } + + else -> { + val mapped = RelocatorRemapper(relocators).map(path) + if (transform(fileDetails, mapped)) return + fileDetails.writeToZip(mapped) } - fileDetails.remapClass(relocators) - } else { - val mapped = RelocatorRemapper(relocators).map(path) - if (transform(fileDetails, mapped)) return - fileDetails.writeToZip(mapped) } } @@ -226,6 +245,39 @@ public open class ShadowCopyAction( } } + /** + * Applies remapping to the given kotlin module with the specified relocation path. + * The remapped module is then written to the zip file. + */ + @OptIn(UnstableMetadataApi::class) + private fun FileCopyDetails.remapKotlinModule(relocators: Set) { + val mappedPath = RelocatorRemapper(relocators).mapPath(path) + file.inputStream().use { ins -> + val metadata = KotlinModuleMetadata.read(ins.readBytes()) + val result = KmModule() + for ((pkg, parts) in metadata.kmModule.packageParts) { + result.packageParts[relocators.applyPathRelocation(pkg)] = + KmPackageParts( + parts.fileFacades.mapTo(mutableListOf()) { + relocators.applyPathRelocation(it) + }, + parts.multiFileClassParts.entries.associateTo(mutableMapOf()) { (name, facade) -> + relocators.applyClassRelocation(name) to relocators.applyPathRelocation(facade) + }, + ) + } + + val newMetadata = KotlinModuleMetadata(result, JvmMetadataVersion.LATEST_STABLE_SUPPORTED) + + val entry = zipEntry(mappedPath, preserveFileTimestamps, lastModified) { + unixMode = UnixStat.FILE_FLAG or permissions.toUnixNumeric() + } + zipOutStr.putNextEntry(entry) + zipOutStr.write(newMetadata.write()) + zipOutStr.closeEntry() + } + } + private fun transform(fileDetails: FileCopyDetails, mapped: String): Boolean { val transformer = transformers.find { it.canTransformResource(fileDetails) } ?: return false fileDetails.file.inputStream().use { inputStream -> @@ -256,6 +308,10 @@ public open class ShadowCopyAction( private val ZipOutputStream.entries: List get() = this::class.java.getDeclaredField("entries").apply { isAccessible = true }.get(this).cast() + internal fun Iterable.applyPathRelocation(value: String): String = fold(value) { string, relocator -> + relocator.relocatePath(RelocatePathContext(string)) + } + /** * A copy of [org.gradle.api.internal.file.archive.ZipEntryConstants.CONSTANT_TIME_FOR_ZIP_ENTRIES]. * diff --git a/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt b/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt deleted file mode 100644 index 84c0ece80..000000000 --- a/src/main/kotlin/com/xpdustry/ksr/KotlinRelocation.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * This file is part of KSR, a gradle plugin for handling Kotlin metadata relocation. - * - * MIT License - * - * Copyright (c) 2025 Xpdustry - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.xpdustry.ksr - -import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter -import com.github.jengelman.gradle.plugins.shadow.internal.RelocationClassWriter.Companion.applyClassRelocation -import com.github.jengelman.gradle.plugins.shadow.relocation.CacheableRelocator -import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext -import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext -import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import java.nio.file.FileSystems -import java.nio.file.Files -import java.nio.file.Path -import kotlin.io.path.name -import kotlin.metadata.jvm.JvmMetadataVersion -import kotlin.metadata.jvm.KmModule -import kotlin.metadata.jvm.KmPackageParts -import kotlin.metadata.jvm.KotlinModuleMetadata -import kotlin.metadata.jvm.UnstableMetadataApi -import org.gradle.api.Action -import org.objectweb.asm.ClassReader - -/** - * A wrapper around [ShadowJar.relocate] that will also take care of kotlin metadata. Only use it - * for kotlin libraries. Using it on normal JVM libraries will just increase compilation time. - */ -internal fun ShadowJar.kotlinRelocate( - pattern: String, - shadedPattern: String, - action: Action = Action { }, -) { - val relocator = KotlinRelocator(pattern, shadedPattern) - val intersections = relocators.get() - .filterIsInstance() - .filter { it.canRelocatePath(pattern) } - require(intersections.isEmpty()) { - "Can't relocate from $pattern to $shadedPattern as it clashes with another paths: ${intersections.joinToString()}" - } - relocate(relocator, action) -} - -internal fun relocateMetadata(task: ShadowJar) { - val relocators = task.relocators.get().filterIsInstance() - val zip = task.archiveFile.get().asFile.toPath() - FileSystems.newFileSystem(zip, null as ClassLoader?).use { fs -> - Files.walk(fs.getPath("/")).forEach { path -> - if (!Files.isRegularFile(path)) return@forEach - if (path.name.endsWith(".class")) relocateClass(path, relocators) - if (path.name.endsWith(".kotlin_module")) relocateKotlinModule(path, relocators) - } - } -} - -internal fun Iterable.applyPathRelocation(value: String): String = fold(value) { string, relocator -> relocator.relocatePath(RelocatePathContext(string)) } - -@CacheableRelocator -internal class KotlinRelocator(pattern: String, shadedPattern: String) : SimpleRelocator(pattern, shadedPattern, emptyList(), emptyList()) { - // I hate these hacks... - private val shadedPattern = shadedPattern.replace('/', '.') - private val shadedPathPattern = shadedPattern.replace('.', '/') - private val pattern = pattern.replace('/', '.') - private val pathPattern = pattern.replace('.', '/') - - // Replace all instead of first - override fun relocateClass(context: RelocateClassContext): String = context.className.replace(pattern.toRegex(), shadedPattern) - - // Replace all instead of first - override fun relocatePath(context: RelocatePathContext): String = context.path.replace(pathPattern.toRegex(), shadedPathPattern) -} - -private fun relocateClass(file: Path, relocators: List) { - Files.newInputStream(file).use { ins -> - val cr = ClassReader(ins) - val cw = RelocationClassWriter(cr, relocators.toSet()) - val scanner = MetadataAnnotationScanner(cw, relocators) - cr.accept(scanner, 0) - if (scanner.isRelocated || cw.isRelocated) { - ins.close() - Files.delete(file) - Files.write(file, cw.toByteArray()) - } - } -} - -@OptIn(UnstableMetadataApi::class) -private fun relocateKotlinModule(file: Path, relocators: List) { - Files.newInputStream(file).use { ins -> - val metadata = KotlinModuleMetadata.read(ins.readBytes()) - val result = KmModule() - for ((pkg, parts) in metadata.kmModule.packageParts) { - result.packageParts[relocators.applyPathRelocation(pkg)] = - KmPackageParts( - parts.fileFacades.mapTo(mutableListOf(), relocators::applyPathRelocation), - parts.multiFileClassParts.entries.associateTo(mutableMapOf()) { (name, facade) -> - relocators.applyClassRelocation(name) to - relocators.applyPathRelocation(facade) - }, - ) - } - ins.close() - Files.delete(file) - Files.write( - file, - KotlinModuleMetadata(result, JvmMetadataVersion.LATEST_STABLE_SUPPORTED).write(), - ) - } -} diff --git a/src/main/kotlin/com/xpdustry/ksr/KotlinShadowRelocatorPlugin.kt b/src/main/kotlin/com/xpdustry/ksr/KotlinShadowRelocatorPlugin.kt deleted file mode 100644 index b1267277e..000000000 --- a/src/main/kotlin/com/xpdustry/ksr/KotlinShadowRelocatorPlugin.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of KSR, a gradle plugin for handling Kotlin metadata relocation. - * - * MIT License - * - * Copyright (c) 2025 Xpdustry - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.xpdustry.ksr - -import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.gradle.api.Plugin -import org.gradle.api.Project - -internal class KotlinShadowRelocatorPlugin : Plugin { - override fun apply(target: Project) { - target.plugins.withType(ShadowJavaPlugin::class.java).configureEach { - target.tasks.withType(ShadowJar::class.java).configureEach { task -> - task.doLast("relocateMetadata") { - relocateMetadata(task) - } - } - } - } -} diff --git a/src/main/kotlin/com/xpdustry/ksr/MetadataAnnotationScanner.kt b/src/main/kotlin/com/xpdustry/ksr/MetadataAnnotationScanner.kt deleted file mode 100644 index cd097f2a3..000000000 --- a/src/main/kotlin/com/xpdustry/ksr/MetadataAnnotationScanner.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of KSR, a gradle plugin for handling Kotlin metadata relocation. - * - * MIT License - * - * Copyright (c) 2025 Xpdustry - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.xpdustry.ksr - -import org.objectweb.asm.AnnotationVisitor -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.Opcodes - -internal class MetadataAnnotationScanner( - private val cw: ClassWriter, - private val relocators: List, -) : ClassVisitor(Opcodes.ASM9, cw) { - internal var isRelocated = false - - override fun visitAnnotation(descriptor: String, visible: Boolean): AnnotationVisitor { - return if (descriptor == "Lkotlin/Metadata;") { - MetadataVisitor(cw.visitAnnotation(descriptor, visible)) - } else { - cw.visitAnnotation(descriptor, visible) - } - } - - inner class MetadataVisitor( - av: AnnotationVisitor, - private val thatArray: Boolean = false, - ) : AnnotationVisitor(Opcodes.ASM9, av) { - override fun visit(name: String?, value: Any) { - val newValue = when { - thatArray && value is String && value.startsWith("(") -> { - relocators.applyPathRelocation(value).also { - if (it != value) isRelocated = true - } - } - else -> value - } - av.visit(name, newValue) - } - - override fun visitArray(name: String): AnnotationVisitor { - return if (name == "d2") { - MetadataVisitor(av.visitArray(name), thatArray = true) - } else { - av.visitArray(name) - } - } - } -} From 9bd73e46942b5c0e09b6c0d883d4d31461faf835 Mon Sep 17 00:00:00 2001 From: Goooler Date: Thu, 28 Aug 2025 16:45:56 +0800 Subject: [PATCH 3/3] Cleanup `visitFile` --- .../gradle/plugins/shadow/tasks/ShadowCopyAction.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt index 4834f3ddb..30b4769ed 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt @@ -168,17 +168,17 @@ public open class ShadowCopyAction( if (isUnused(path)) return if (relocators.isEmpty()) { fileDetails.writeToZip(path) - return + } else { + fileDetails.remapClass(relocators) } - fileDetails.remapClass(relocators) } path.endsWith(".kotlin_module") -> { if (relocators.isEmpty()) { fileDetails.writeToZip(path) - return + } else { + fileDetails.remapKotlinModule(relocators) } - fileDetails.remapKotlinModule(relocators) } else -> {