1import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer 2import com.github.jengelman.gradle.plugins.shadow.transformers.CacheableTransformer 3import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext 4import org.gradle.api.file.FileTreeElement 5import shadow.org.apache.tools.zip.ZipOutputStream 6import shadow.org.apache.tools.zip.ZipEntry 7 8plugins { 9 id "java" 10 id "maven-publish" 11 12 id "com.github.johnrengelman.shadow" 13 id "ru.vyarus.animalsniffer" 14} 15 16description = "gRPC: Netty Shaded" 17 18sourceSets { testShadow {} } 19 20dependencies { 21 implementation project(':grpc-netty') 22 runtimeOnly libraries.netty.tcnative, 23 libraries.netty.tcnative.classes 24 runtimeOnly (libraries.netty.tcnative) { 25 artifact { 26 classifier = "linux-x86_64" 27 } 28 } 29 runtimeOnly (libraries.netty.tcnative) { 30 artifact { 31 classifier = "linux-aarch_64" 32 } 33 } 34 runtimeOnly (libraries.netty.tcnative) { 35 artifact { 36 classifier = "osx-x86_64" 37 } 38 } 39 runtimeOnly (libraries.netty.tcnative) { 40 artifact { 41 classifier = "osx-aarch_64" 42 } 43 } 44 runtimeOnly (libraries.netty.tcnative) { 45 artifact { 46 classifier = "windows-x86_64" 47 } 48 } 49 runtimeOnly (libraries.netty.transport.epoll) { 50 artifact { 51 classifier = "linux-x86_64" 52 } 53 } 54 runtimeOnly (libraries.netty.transport.epoll) { 55 artifact { 56 classifier = "linux-aarch_64" 57 } 58 } 59 testShadowImplementation files(shadowJar), 60 project(':grpc-testing-proto'), 61 project(':grpc-testing'), 62 libraries.truth 63 shadow project(':grpc-netty').configurations.runtimeClasspath.allDependencies.matching { 64 it.group != 'io.netty' 65 } 66 signature libraries.signature.java 67 signature libraries.signature.android 68} 69 70tasks.named("jar").configure { 71 // Must use a different archiveClassifier to avoid conflicting with shadowJar 72 archiveClassifier = 'original' 73} 74 75tasks.named("shadowJar").configure { 76 archiveClassifier = null 77 dependencies { 78 include(project(':grpc-netty')) 79 include(dependency('io.netty:')) 80 } 81 exclude 'META-INF/maven/**' 82 relocate 'io.grpc.netty', 'io.grpc.netty.shaded.io.grpc.netty' 83 relocate 'io.netty', 'io.grpc.netty.shaded.io.netty' 84 // We have to be careful with these replacements as they must not match any 85 // string in NativeLibraryLoader, else they cause corruption. Note that 86 // this includes concatenation of string literals and constants. 87 relocate 'META-INF/native/libnetty', 'META-INF/native/libio_grpc_netty_shaded_netty' 88 relocate 'META-INF/native/netty', 'META-INF/native/io_grpc_netty_shaded_netty' 89 transform(NettyResourceTransformer.class) 90 mergeServiceFiles() 91} 92 93publishing { 94 publications { 95 maven(MavenPublication) { 96 project.shadow.component(it) 97 98 // Empty jars are not published via withJavadocJar() and withSourcesJar() 99 artifact javadocJar 100 artifact sourcesJar 101 102 // Avoid confusing error message "class file for 103 // io.grpc.internal.AbstractServerImplBuilder not found" 104 // (https://github.com/grpc/grpc-java/issues/5881). This can be 105 // removed after https://github.com/grpc/grpc-java/issues/7211 is 106 // resolved. 107 pom.withXml { 108 asNode().dependencies.'*'.findAll() { dep -> 109 dep.artifactId.text() == 'grpc-core' 110 }.each() { core -> 111 core.scope*.value = "compile" 112 } 113 } 114 } 115 } 116} 117 118tasks.register("testShadow", Test) { 119 testClassesDirs = sourceSets.testShadow.output.classesDirs 120 classpath = sourceSets.testShadow.runtimeClasspath 121} 122tasks.named("compileTestShadowJava").configure { 123 options.compilerArgs = compileTestJava.options.compilerArgs 124 options.encoding = compileTestJava.options.encoding 125} 126 127tasks.named("test").configure { 128 dependsOn tasks.named("testShadow") 129} 130 131/** 132 * A Transformer which updates the Netty JAR META-INF/ resources to accurately 133 * reference shaded class names. 134 */ 135@CacheableTransformer 136class NettyResourceTransformer implements Transformer { 137 138 // A map of resource file paths to be modified 139 private Map<String, String> resources = [:] 140 141 @Override 142 boolean canTransformResource(FileTreeElement fileTreeElement) { 143 fileTreeElement.name.startsWith("META-INF/native-image/io.netty") 144 } 145 146 @Override 147 void transform(TransformerContext context) { 148 String updatedPath = context.path.replace("io.netty", "io.grpc.netty.shaded.io.netty") 149 String updatedContent = context.is.getText().replace("io.netty", "io.grpc.netty.shaded.io.netty") 150 resources.put(updatedPath, updatedContent) 151 } 152 153 @Override 154 boolean hasTransformedResource() { 155 resources.size() > 0 156 } 157 158 @Override 159 void modifyOutputStream(ZipOutputStream outputStream, boolean preserveFileTimestamps) { 160 for (resourceEntry in resources) { 161 ZipEntry entry = new ZipEntry(resourceEntry.key) 162 entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) 163 164 outputStream.putNextEntry(entry) 165 outputStream.write(resourceEntry.value.getBytes()) 166 outputStream.closeEntry() 167 } 168 } 169} 170