From abbed2817380bf248c2bb1c09c6e804998f1afdb Mon Sep 17 00:00:00 2001 From: Tyler Wong Date: Sun, 20 Oct 2024 11:25:22 -0700 Subject: [PATCH] Fix Multiple Plugin Compatibility (#106) --- gradle.properties | 2 +- gradle/libs.versions.toml | 8 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- .../me/tylerbwong/gradle/metalava/Module.kt | 49 +++++++++++++------ .../gradle/metalava/plugin/MetalavaPlugin.kt | 6 ++- .../api/kotlin-multiplatform-api.txt | 38 ++++++++------ samples/kotlin-multiplatform/build.gradle.kts | 23 +++++++++ .../src/androidMain/AndroidManifest.xml | 2 + .../sample/SampleAndroidInternalApi.kt | 5 ++ .../metalava/sample/SampleAndroidPublicApi.kt | 7 +++ .../metalava/sample/SampleCommonPublicApi.kt | 7 +++ .../gradle/metalava/sample/SamplePublicApi.kt | 6 --- .../metalava/sample/SampleIosPublicApi.kt | 7 +++ .../gradle/metalava/sample/SamplePublicApi.kt | 6 --- .../metalava/sample/SampleJsPublicApi.kt | 7 +++ .../gradle/metalava/sample/SamplePublicApi.kt | 6 --- .../metalava/sample/SampleJvmPublicApi.kt | 7 +++ .../gradle/metalava/sample/SamplePublicApi.kt | 6 --- .../metalava/sample/SampleLinuxPublicApi.kt | 7 +++ .../gradle/metalava/sample/SamplePublicApi.kt | 6 --- 20 files changed, 139 insertions(+), 68 deletions(-) create mode 100644 samples/kotlin-multiplatform/src/androidMain/AndroidManifest.xml create mode 100644 samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidInternalApi.kt create mode 100644 samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidPublicApi.kt create mode 100644 samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleCommonPublicApi.kt delete mode 100644 samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt create mode 100644 samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleIosPublicApi.kt delete mode 100644 samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt create mode 100644 samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJsPublicApi.kt delete mode 100644 samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt create mode 100644 samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJvmPublicApi.kt delete mode 100644 samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt create mode 100644 samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SampleLinuxPublicApi.kt delete mode 100644 samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt diff --git a/gradle.properties b/gradle.properties index bcb028d..122330a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ android.useAndroidX=true kotlin.code.style=official -kotlin.js.compiler=ir +kotlin.mpp.androidGradlePluginCompatibility.nowarn=true kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true org.gradle.configureondemand=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d733f5c..4206245 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,10 +1,10 @@ [versions] -androidGradle = "8.5.1" -androidx-compose-runtime = "1.6.8" +androidGradle = "8.7.0" +androidx-compose-runtime = "1.7.3" junit = "5.11.1" -kotlin = "2.0.0" +kotlin = "2.0.20" ktlintGradle = "12.1.1" -pluginPublish = "1.2.1" +pluginPublish = "1.3.0" metalavaGradle = "0.3.5" [plugins] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0..df97d72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/Module.kt b/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/Module.kt index fd5d331..ae7ad62 100644 --- a/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/Module.kt +++ b/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/Module.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.targets import java.io.File import java.util.Locale @@ -158,25 +157,47 @@ internal sealed class Module { } } + class Composite(private val modules: List) : Module() { + override val bootClasspath: Collection + get() = modules.flatMap { it.bootClasspath } + + override fun compileClasspath(project: Project, variant: String?): FileCollection { + return modules + .map { it.compileClasspath(project, variant) } + .reduce(FileCollection::plus) + .filter { it.exists() } + } + + override fun sourceSets(project: Project, variant: String?): FileCollection { + return modules + .map { it.sourceSets(project, variant) } + .reduce(FileCollection::plus) + } + + internal inline fun extract(): T? = modules.firstOrNull { + it is T + } as? T + } + companion object { internal val Project.module: Module? get() { // Use findByName to avoid requiring consumers to have the Android Gradle plugin // in their classpath when applying this plugin to a non-Android project - val libraryExtension = extensions.findByName("android") - val kotlinExtension = extensions.findByName("kotlin") + val androidModule = extensions.findByName("android") + ?.takeIf { it is LibraryExtension } + ?.let { Android(it as LibraryExtension) } + val javaPluginExtension = extensions.findByType() - return when { - libraryExtension != null && libraryExtension is LibraryExtension -> Android( - libraryExtension, - ) - kotlinExtension != null && javaPluginExtension != null && kotlinExtension is KotlinProjectExtension -> Kotlin( - javaPluginExtension, - kotlinExtension, - ) - javaPluginExtension != null -> Java(javaPluginExtension) - else -> null - } + + val kotlinModule = extensions.findByName("kotlin") + ?.takeIf { it is KotlinProjectExtension && javaPluginExtension != null } + ?.let { Kotlin(javaPluginExtension!!, it as KotlinProjectExtension) } + + val javaModule = javaPluginExtension?.let { Java(it) } + + val modules = listOfNotNull(androidModule, kotlinModule, javaModule) + return modules.takeIf { it.isNotEmpty() }?.let { Composite(it) } } internal fun File.checkDirectory(validExtensions: Collection): Boolean { diff --git a/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/plugin/MetalavaPlugin.kt b/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/plugin/MetalavaPlugin.kt index 0c8d1f6..6a808e9 100644 --- a/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/plugin/MetalavaPlugin.kt +++ b/plugin/src/main/kotlin/me/tylerbwong/gradle/metalava/plugin/MetalavaPlugin.kt @@ -15,8 +15,10 @@ internal class MetalavaPlugin : Plugin { afterEvaluate { val currentModule = module if (currentModule != null) { - if (currentModule is Module.Android) { - currentModule.libraryVariants.forEach { + val androidModule = (currentModule as? Module.Composite) + ?.extract() + if (androidModule != null) { + androidModule.libraryVariants.forEach { createMetalavaTasks(this, extension, currentModule, it) } } else { diff --git a/samples/kotlin-multiplatform/api/kotlin-multiplatform-api.txt b/samples/kotlin-multiplatform/api/kotlin-multiplatform-api.txt index b13c3da..cf40ff1 100644 --- a/samples/kotlin-multiplatform/api/kotlin-multiplatform-api.txt +++ b/samples/kotlin-multiplatform/api/kotlin-multiplatform-api.txt @@ -1,28 +1,34 @@ // Signature format: 4.0 package me.tylerbwong.gradle.metalava.sample { - public interface SamplePublicApi { - method public String getPublicApiProperty(); - method public void publicApiFunction(); - property public abstract String publicApiProperty; + public interface Platform { + method public String getPlatform(); + property public abstract String platform; } - public interface SamplePublicApi { - method public String getPublicApiProperty(); - method public void publicApiFunction(); - property public abstract String publicApiProperty; + public final class SampleAndroidPublicApiKt { + method public static me.tylerbwong.gradle.metalava.sample.Platform getPlatform(); + property public static final me.tylerbwong.gradle.metalava.sample.Platform platform; } - public interface SamplePublicApi { - method public String getPublicApiProperty(); - method public void publicApiFunction(); - property public abstract String publicApiProperty; + public final class SampleIosPublicApiKt { + method public static me.tylerbwong.gradle.metalava.sample.Platform getPlatform(); + property public static final me.tylerbwong.gradle.metalava.sample.Platform platform; } - public interface SamplePublicApi { - method public String getPublicApiProperty(); - method public void publicApiFunction(); - property public abstract String publicApiProperty; + public final class SampleJsPublicApiKt { + method public static me.tylerbwong.gradle.metalava.sample.Platform getPlatform(); + property public static final me.tylerbwong.gradle.metalava.sample.Platform platform; + } + + public final class SampleJvmPublicApiKt { + method public static me.tylerbwong.gradle.metalava.sample.Platform getPlatform(); + property public static final me.tylerbwong.gradle.metalava.sample.Platform platform; + } + + public final class SampleLinuxPublicApiKt { + method public static me.tylerbwong.gradle.metalava.sample.Platform getPlatform(); + property public static final me.tylerbwong.gradle.metalava.sample.Platform platform; } } diff --git a/samples/kotlin-multiplatform/build.gradle.kts b/samples/kotlin-multiplatform/build.gradle.kts index fb3a727..a72e43e 100644 --- a/samples/kotlin-multiplatform/build.gradle.kts +++ b/samples/kotlin-multiplatform/build.gradle.kts @@ -1,9 +1,11 @@ plugins { kotlin("multiplatform") + id("com.android.library") id("me.tylerbwong.gradle.metalava") } kotlin { + androidTarget() iosX64() iosArm64() iosSimulatorArm64() @@ -14,6 +16,27 @@ kotlin { linuxX64() } +android { + namespace = "me.tylerbwong.gradle.metalava.sample" + compileSdk = 34 + + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + sourceSets["main"].res.srcDirs("src/androidMain/res") + sourceSets["main"].resources.srcDirs("src/commonMain/resources") + + defaultConfig { + minSdk = 21 + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlin { + jvmToolchain(17) + } +} + metalava { filename.set("api/$name-api.txt") } diff --git a/samples/kotlin-multiplatform/src/androidMain/AndroidManifest.xml b/samples/kotlin-multiplatform/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000..8072ee0 --- /dev/null +++ b/samples/kotlin-multiplatform/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidInternalApi.kt b/samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidInternalApi.kt new file mode 100644 index 0000000..97ba68f --- /dev/null +++ b/samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidInternalApi.kt @@ -0,0 +1,5 @@ +package me.tylerbwong.gradle.metalava.sample + +internal class SampleAndroidInternalApi { + val internalApiProperty: String = "" +} diff --git a/samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidPublicApi.kt b/samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidPublicApi.kt new file mode 100644 index 0000000..585ef85 --- /dev/null +++ b/samples/kotlin-multiplatform/src/androidMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleAndroidPublicApi.kt @@ -0,0 +1,7 @@ +package me.tylerbwong.gradle.metalava.sample + +internal class AndroidPlatform : Platform { + override val platform: String = "Android" +} + +actual val platform: Platform = AndroidPlatform() diff --git a/samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleCommonPublicApi.kt b/samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleCommonPublicApi.kt new file mode 100644 index 0000000..2051c8c --- /dev/null +++ b/samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleCommonPublicApi.kt @@ -0,0 +1,7 @@ +package me.tylerbwong.gradle.metalava.sample + +interface Platform { + val platform: String +} + +expect val platform: Platform diff --git a/samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt b/samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt deleted file mode 100644 index b9dc600..0000000 --- a/samples/kotlin-multiplatform/src/commonMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.tylerbwong.gradle.metalava.sample - -expect interface SamplePublicApi { - val publicApiProperty: String - fun publicApiFunction() -} diff --git a/samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleIosPublicApi.kt b/samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleIosPublicApi.kt new file mode 100644 index 0000000..56bc1ea --- /dev/null +++ b/samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleIosPublicApi.kt @@ -0,0 +1,7 @@ +package me.tylerbwong.gradle.metalava.sample + +internal class IosPlatform : Platform { + override val platform: String = "iOS" +} + +actual val platform: Platform = IosPlatform() diff --git a/samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt b/samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt deleted file mode 100644 index 4943ebb..0000000 --- a/samples/kotlin-multiplatform/src/iosMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.tylerbwong.gradle.metalava.sample - -actual interface SamplePublicApi { - actual val publicApiProperty: String - actual fun publicApiFunction() -} diff --git a/samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJsPublicApi.kt b/samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJsPublicApi.kt new file mode 100644 index 0000000..a306058 --- /dev/null +++ b/samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJsPublicApi.kt @@ -0,0 +1,7 @@ +package me.tylerbwong.gradle.metalava.sample + +internal class JsPlatform : Platform { + override val platform: String = "JS" +} + +actual val platform: Platform = JsPlatform() diff --git a/samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt b/samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt deleted file mode 100644 index 4943ebb..0000000 --- a/samples/kotlin-multiplatform/src/jsMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.tylerbwong.gradle.metalava.sample - -actual interface SamplePublicApi { - actual val publicApiProperty: String - actual fun publicApiFunction() -} diff --git a/samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJvmPublicApi.kt b/samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJvmPublicApi.kt new file mode 100644 index 0000000..f6f02cd --- /dev/null +++ b/samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SampleJvmPublicApi.kt @@ -0,0 +1,7 @@ +package me.tylerbwong.gradle.metalava.sample + +internal class JvmPlatform : Platform { + override val platform: String = "JVM" +} + +actual val platform: Platform = JvmPlatform() diff --git a/samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt b/samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt deleted file mode 100644 index 4943ebb..0000000 --- a/samples/kotlin-multiplatform/src/jvmMain/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.tylerbwong.gradle.metalava.sample - -actual interface SamplePublicApi { - actual val publicApiProperty: String - actual fun publicApiFunction() -} diff --git a/samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SampleLinuxPublicApi.kt b/samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SampleLinuxPublicApi.kt new file mode 100644 index 0000000..5f5b63b --- /dev/null +++ b/samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SampleLinuxPublicApi.kt @@ -0,0 +1,7 @@ +package me.tylerbwong.gradle.metalava.sample + +internal class LinuxPlatform : Platform { + override val platform: String = "Linux" +} + +actual val platform: Platform = LinuxPlatform() diff --git a/samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt b/samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt deleted file mode 100644 index 4943ebb..0000000 --- a/samples/kotlin-multiplatform/src/linuxX64Main/kotlin/me/tylerbwong/gradle/metalava/sample/SamplePublicApi.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.tylerbwong.gradle.metalava.sample - -actual interface SamplePublicApi { - actual val publicApiProperty: String - actual fun publicApiFunction() -}