blob: 0311dc3a49b6eac4d118dca31740224d2da1b872 [file] [log] [blame]
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.jvm.tasks.Jar
import java.util.zip.ZipFile
evaluationDependsOn(":kotlin-analysis-api")
val signingKey: String? by project
val signingPassword: String? by project
val aaKotlinBaseVersion: String by project
val aaIntellijVersion: String by project
plugins {
kotlin("jvm")
id("com.github.johnrengelman.shadow")
`maven-publish`
signing
}
val packedJars by configurations.creating
dependencies {
packedJars(project(":kotlin-analysis-api", "shadow")) { isTransitive = false }
}
tasks.withType<Jar> {
archiveClassifier.set("real")
}
val prefixesToRelocate = listOf(
"com.fasterxml.",
"org.codehaus.",
"com.github.benmanes.caffeine.",
"com.google.common.",
"com.google.devtools.ksp.common.",
"com.google.errorprone.",
"com.google.gwt.",
"com.google.j2objc.",
"com.intellij.",
"com.sun.jna.",
"gnu.trove.",
"it.unimi.dsi.",
"javaslang.",
"javax.inject.",
"kotlinx.collections.immutable.",
"kotlinx.coroutines.",
"org.apache.log4j.",
"org.checkerframework.",
"org.intellij.",
"org.jetbrains.",
"org.jdom.",
"org.picocontainer.",
"one.util.",
"net.jpountz.",
"net.rubygrapefruit.",
"FirNativeForwardDeclarationGetClassCallChecker",
).map {
Pair(it, "ksp." + it)
}
tasks.withType<ShadowJar> {
archiveClassifier.set("")
// ShadowJar picks up the `compile` configuration by default and pulls stdlib in.
// Therefore, specifying another configuration instead.
configurations = listOf(packedJars)
prefixesToRelocate.forEach { (f, t) ->
relocate(f, t)
}
mergeServiceFiles()
exclude("META-INF/compiler.version")
// All bundled dependencies should be renamed.
doLast {
val violatingFiles = mutableListOf<String>()
archiveFile.get().asFile.let {
for (e in ZipFile(it).entries()) {
if (e.name.endsWith(".class") and !validPackages.contains(e.name))
violatingFiles.add(e.name)
}
}
if (violatingFiles.isNotEmpty()) {
error(
"Detected unrelocated classes that may cause conflicts: " +
violatingFiles.joinToString(System.lineSeparator())
)
}
}
}
val prefixesToRelocateStripped = prefixesToRelocate.map {
Pair(it.first.trim('.'), it.second.trim('.'))
}
// TODO: match with Trie
fun String.replaceWithKsp() =
prefixesToRelocateStripped.fold(this) { acc, (f, t) ->
acc.replace("package $f", "package $t")
.replace("import $f", "import $t")
}
val DEP_SOURCES_DIR = "$buildDir/source-jar"
val validPaths = prefixesToRelocate.map {
it.second.split('.').filter { it.isNotEmpty() }.joinToString("/")
} + listOf(
"com/google/devtools/ksp",
"META-INF",
"ksp/FirNativeForwardDeclarationGetClassCallChecker.class",
)
class Trie(paths: List<String>) {
class TrieNode(val key: String)
private val terminals = mutableSetOf<TrieNode>()
private val m = mutableMapOf<Pair<TrieNode?, String>, TrieNode>().apply {
paths.forEach { path ->
var p: TrieNode? = null
for (d in path.split("/")) {
p = getOrPut(Pair(p, d)) { TrieNode(d) }
}
terminals.add(p!!)
}
}
fun contains(s: String): Boolean {
var p: TrieNode? = null
for (d in s.split("/")) {
p = m.get(Pair(p, d))?.also {
if (it in terminals)
return true
} ?: return false
}
return true
}
}
val validPackages = Trie(validPaths)
tasks {
val copyDeps by creating(Copy::class) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
project(":kotlin-analysis-api").configurations.getByName("depSourceJars").resolve().forEach {
from(zipTree(it))
}
from(project(":common-util").sourceSets.main.get().allSource)
into("$DEP_SOURCES_DIR/ksp")
}
val sourcesJar by creating(Jar::class) {
dependsOn(copyDeps)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveClassifier.set("sources")
from(project(":kotlin-analysis-api").sourceSets.main.get().allSource)
from(DEP_SOURCES_DIR)
filter { it.replaceWithKsp() }
}
publish {
dependsOn(shadowJar)
dependsOn(sourcesJar)
dependsOn(project(":kotlin-analysis-api").tasks["dokkaJavadocJar"])
}
}
publishing {
publications {
create<MavenPublication>("shadow") {
artifactId = "symbol-processing-aa-embeddable"
artifact(project(":kotlin-analysis-api").tasks["dokkaJavadocJar"])
artifact(tasks["sourcesJar"])
artifact(tasks["shadowJar"])
pom {
name.set("com.google.devtools.ksp:symbol-processing-aa-embeddable")
description.set("KSP implementation on Kotlin Analysis API")
withXml {
fun groovy.util.Node.addDependency(
groupId: String,
artifactId: String,
version: String,
scope: String = "runtime"
) {
appendNode("dependency").apply {
appendNode("groupId", groupId)
appendNode("artifactId", artifactId)
appendNode("version", version)
appendNode("scope", scope)
}
}
asNode().appendNode("dependencies").apply {
addDependency("org.jetbrains.kotlin", "kotlin-stdlib", aaKotlinBaseVersion)
addDependency("com.google.devtools.ksp", "symbol-processing-api", version)
addDependency("com.google.devtools.ksp", "symbol-processing-common-deps", version)
}
}
}
}
}
}
signing {
isRequired = hasProperty("signingKey")
useInMemoryPgpKeys(signingKey, signingPassword)
sign(extensions.getByType<PublishingExtension>().publications)
}
abstract class WriteVersionSrcTask @Inject constructor(
@get:Input val kotlinVersion: String,
@get:OutputDirectory val outputResDir: File
) : DefaultTask() {
@TaskAction
fun generate() {
val metaInfDir = File(outputResDir, "META-INF")
metaInfDir.mkdirs()
File(metaInfDir, "ksp.compiler.version").writeText(kotlinVersion)
}
}
val kspVersionDir = File(project.buildDir, "generated/ksp-versions/META-INF")
val writeVersionSrcTask = tasks.register<WriteVersionSrcTask>(
"generateKSPVersions",
aaKotlinBaseVersion,
kspVersionDir
)
kotlin {
sourceSets {
main {
resources.srcDir(writeVersionSrcTask.map { it.outputResDir })
}
}
}