import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext import org.gradle.api.file.FileTreeElement import shadow.org.apache.tools.zip.ZipOutputStream import shadow.org.apache.tools.zip.ZipEntry plugins { id "java" id "maven-publish" id "com.github.johnrengelman.shadow" } description = "gRPC: Netty Shaded" sourceSets { testShadow {} } dependencies { implementation project(':grpc-netty') runtimeOnly libraries.netty_tcnative, libraries.netty_epoll testShadowImplementation files(shadowJar), project(':grpc-testing-proto'), project(':grpc-testing'), libraries.truth shadow project(':grpc-netty').configurations.runtimeClasspath.allDependencies.matching { it.group != 'io.netty' } } jar { // Must use a different classifier to avoid conflicting with shadowJar classifier = 'original' } shadowJar { classifier = null dependencies { include(project(':grpc-netty')) include(dependency('io.netty:')) } exclude 'META-INF/maven/**' relocate 'io.grpc.netty', 'io.grpc.netty.shaded.io.grpc.netty' relocate 'io.netty', 'io.grpc.netty.shaded.io.netty' // We have to be careful with these replacements as they must not match any // string in NativeLibraryLoader, else they cause corruption. Note that // this includes concatenation of string literals and constants. relocate 'META-INF/native/libnetty', 'META-INF/native/libio_grpc_netty_shaded_netty' relocate 'META-INF/native/netty', 'META-INF/native/io_grpc_netty_shaded_netty' transform(NettyResourceTransformer.class) mergeServiceFiles() } publishing { publications { maven(MavenPublication) { project.shadow.component(it) // Empty jars are not published via withJavadocJar() and withSourcesJar() artifact javadocJar artifact sourcesJar // Avoid confusing error message "class file for // io.grpc.internal.AbstractServerImplBuilder not found" // (https://github.com/grpc/grpc-java/issues/5881). This can be // removed after https://github.com/grpc/grpc-java/issues/7211 is // resolved. pom.withXml { asNode().dependencies.'*'.findAll() { dep -> dep.artifactId.text() == 'grpc-core' }.each() { core -> core.scope*.value = "compile" } } // shadow.component() is run after the main build.gradle's withXml pom.withXml { asNode().dependencies.'*'.findAll() { dep -> dep.artifactId.text() in ['grpc-api', 'grpc-core'] }.each() { core -> core.version*.value = "[" + core.version.text() + "]" } } } } } task testShadow(type: Test) { testClassesDirs = sourceSets.testShadow.output.classesDirs classpath = sourceSets.testShadow.runtimeClasspath } compileTestShadowJava.options.compilerArgs = compileTestJava.options.compilerArgs compileTestShadowJava.options.encoding = compileTestJava.options.encoding test.dependsOn testShadow /** * A Transformer which updates the Netty JAR META-INF/ resources to accurately * reference shaded class names. */ class NettyResourceTransformer implements Transformer { // A map of resource file paths to be modified private Map resources = [:] @Override boolean canTransformResource(FileTreeElement fileTreeElement) { fileTreeElement.name.startsWith("META-INF/native-image/io.netty") } @Override void transform(TransformerContext context) { String updatedPath = context.path.replace("io.netty", "io.grpc.netty.shaded.io.netty") String updatedContent = context.is.getText().replace("io.netty", "io.grpc.netty.shaded.io.netty") resources.put(updatedPath, updatedContent) } @Override boolean hasTransformedResource() { resources.size() > 0 } @Override void modifyOutputStream(ZipOutputStream outputStream, boolean preserveFileTimestamps) { for (resourceEntry in resources) { ZipEntry entry = new ZipEntry(resourceEntry.key) entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) outputStream.putNextEntry(entry) outputStream.write(resourceEntry.value.getBytes()) outputStream.closeEntry() } } }