Skip to content

Commit

Permalink
Get rid of dynamic loading of the SKIE Gradle Plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
TadeasKriz committed Feb 25, 2024
1 parent 1b4d6ce commit 652f073
Show file tree
Hide file tree
Showing 63 changed files with 356 additions and 512 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import co.touchlab.skie.gradle.KotlinCompilerVersion
import co.touchlab.skie.gradle.publish.dependencyName
import co.touchlab.skie.gradle.util.enquoted
import co.touchlab.skie.gradle.util.stringListProperty
import co.touchlab.skie.gradle.version.KotlinToolingVersionComponent
import co.touchlab.skie.gradle.version.gradleApiVersionDimension
import co.touchlab.skie.gradle.version.kotlinToolingVersionDimension

Expand All @@ -13,12 +11,12 @@ plugins {
}

skiePublishing {
name = "SKIE Gradle Plugin Loader"
description = "Gradle plugin that loads the correct SKIE version based on Kotlin and Gradle versions."
name = "SKIE Gradle Plugin"
description = "Gradle plugin for configuring SKIE compiler plugin."
}

buildConfig {
val gradlePlugin = projects.gradle.gradlePlugin.dependencyProject
val gradlePlugin = projects.gradlePlugin.dependencyProject
buildConfigField("String", "SKIE_GRADLE_PLUGIN", "\"${gradlePlugin.dependencyName}\"")

val kotlinToSkieKgpVersion = project.kotlinToolingVersionDimension().components
Expand All @@ -34,6 +32,22 @@ buildConfig {
buildConfigField("co.touchlab.skie.plugin.util.StringMap", "KOTLIN_TO_SKIE_KGP_VERSION", "mapOf($kotlinToSkieKgpVersion)")

buildConfigField("String", "SKIE_VERSION", "\"${project.version}\"")


val kotlinPlugin = project.provider { projects.compiler.kotlinPlugin.dependencyProject }
buildConfigField("String", "KOTLIN_PLUGIN_GROUP", kotlinPlugin.map { it.group.toString().enquoted() })
buildConfigField("String", "KOTLIN_PLUGIN_NAME", kotlinPlugin.map { it.name.enquoted() })
buildConfigField("String", "KOTLIN_PLUGIN_VERSION", kotlinPlugin.map { it.version.toString().enquoted() })

val runtime = project.provider { projects.runtime.runtimeKotlin.dependencyProject }
buildConfigField("String", "RUNTIME_DEPENDENCY_GROUP", runtime.map { it.group.toString().enquoted() })
buildConfigField("String", "RUNTIME_DEPENDENCY_NAME", runtime.map { it.name.enquoted() })
buildConfigField("String", "RUNTIME_DEPENDENCY_VERSION", runtime.map { it.version.toString().enquoted() })

val pluginId: String by properties
buildConfigField("String", "KOTLIN_PLUGIN_ID", pluginId.enquoted())

buildConfigField("String", "MIXPANEL_PROJECT_TOKEN", "\"a4c9352b6713103c0f8621757a35b8c9\"")
}

kotlin {
Expand All @@ -48,43 +62,27 @@ kotlin {

configurations.configureEach {
attributes {
@Suppress("UnstableApiUsage")
attribute(GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, objects.named(gradleApiVersionDimension().components.min().value))
attribute(
GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE,
objects.named(gradleApiVersionDimension().components.min().value),
)
}
}

dependencies {
api(projects.gradle.gradlePluginApi)
api(projects.common.configuration.configurationDeclaration)
compileOnly("dev.gradleplugins:gradle-api:${gradleApiVersionDimension().components.min().value}")
compileOnly(libs.plugin.kotlin.gradle.api)
compileOnly(libs.plugin.kotlin.gradle)

testImplementation(kotlin("test"))
}
implementation(libs.ci.info)
implementation(libs.jgit)
implementation(libs.mixpanel)

tasks.named("compileKotlin").configure {
val gradleApiVersions = project.gradleApiVersionDimension()
val kotlinToolingVersions = project.kotlinToolingVersionDimension()

gradleApiVersions.components.forEach { gradleApiVersion ->
kotlinToolingVersions.components.forEach { kotlinToolingVersion ->
val shimConfiguration = configurations.detachedConfiguration(
projects.gradle.gradlePlugin,
).apply {
attributes {
attribute(
KotlinCompilerVersion.attribute,
objects.named(KotlinCompilerVersion::class.java, kotlinToolingVersion.value),
)
attribute(
GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE,
objects.named(GradlePluginApiVersion::class.java, gradleApiVersion.value),
)
}
}
dependsOn(shimConfiguration)
}
}
implementation(projects.common.analytics)
implementation(projects.common.util)

testImplementation(kotlin("test"))
}

gradlePlugin {
Expand All @@ -95,7 +93,7 @@ gradlePlugin {
create("co.touchlab.skie") {
id = "co.touchlab.skie"
displayName = "Swift and Kotlin, unified"
implementationClass = "co.touchlab.skie.plugin.SkieLoaderPlugin"
implementationClass = "co.touchlab.skie.plugin.SkieGradlePlugin"
version = project.version

description = "A Gradle plugin to add Swift into Kotlin/Native framework."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,49 @@
package co.touchlab.skie.plugin

import co.touchlab.skie.gradle.KotlinCompilerVersion
import co.touchlab.skie.gradle_plugin_loader.BuildConfig
import co.touchlab.skie.gradle_plugin.BuildConfig
import co.touchlab.skie.plugin.analytics.GradleAnalyticsManager
import co.touchlab.skie.plugin.configuration.CreateSkieConfigurationTask
import co.touchlab.skie.plugin.configuration.SkieExtension
import co.touchlab.skie.plugin.configuration.SkieExtension.Companion.createExtension
import co.touchlab.skie.plugin.configuration.skieExtension
import co.touchlab.skie.plugin.coroutines.addDependencyOnSkieRuntime
import co.touchlab.skie.plugin.coroutines.configureMinOsVersionIfNeeded
import co.touchlab.skie.plugin.defaultarguments.disableCachingIfNeeded
import co.touchlab.skie.plugin.dependencies.SkieCompilerPluginDependencyProvider
import co.touchlab.skie.plugin.directory.SkieDirectoriesManager
import co.touchlab.skie.plugin.fatframework.FatFrameworkConfigurator
import co.touchlab.skie.plugin.subplugin.SkieSubPluginManager
import co.touchlab.skie.plugin.switflink.SwiftLinkingConfigurator
import co.touchlab.skie.plugin.util.*
import co.touchlab.skie.util.plugin.SkiePlugin
import org.gradle.api.Named
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.plugin.GradlePluginApiVersion
import org.gradle.api.model.ObjectFactory
import org.gradle.configurationcache.extensions.serviceOf
import org.gradle.internal.classloader.HashingClassLoaderFactory
import org.gradle.internal.classpath.DefaultClassPath
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeArtifact
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.kotlinArtifactsExtension
import org.jetbrains.kotlin.konan.target.HostManager

@Suppress("unused")
abstract class SkieLoaderPlugin : Plugin<Project> {
abstract class SkieGradlePlugin : Plugin<Project> {

override fun apply(project: Project) {
// We need to register the extension here, so that Gradle knows the type of it in the build script.
with(SkieExtension) {
project.createExtension()
}

val kotlinVersion = project.getValidKotlinVersion() ?: return

project.loadSkieGradlePlugin(kotlinVersion)
project.extensions.create("skieInternal", SkieInternalExtension::class.java)

project.configureSkieGradlePlugin()

project.afterEvaluate {
project.configureRuntimeVariantFallback()
project.configureSkieCompilerPlugin(kotlinVersion)
}
}

private fun Project.getValidKotlinVersion(): String? {
Expand Down Expand Up @@ -89,65 +104,6 @@ abstract class SkieLoaderPlugin : Plugin<Project> {
private fun Project.getKotlinVersionString(): String? =
(project.kotlinGradlePluginVersionOverride ?: project.kotlinGradlePluginVersion ?: project.rootProject.kotlinGradlePluginVersion)

private fun Project.loadSkieGradlePlugin(kotlinVersion: String) {
val gradleVersion = GradleVersion.current().version
logger.info("Resolving SKIE gradle plugin for Kotlin plugin version $kotlinVersion and Gradle version $gradleVersion")

KotlinCompilerVersion.registerIn(project.dependencies, kotlinVersion)
KotlinCompilerVersion.registerIn(buildscript.dependencies, kotlinVersion)
val skieGradleConfiguration = buildscript.configurations.detachedConfiguration(
buildscript.dependencies.create(BuildConfig.SKIE_GRADLE_PLUGIN),
).apply {
this.isCanBeConsumed = false
this.isCanBeResolved = true

exclude(
mapOf(
"group" to "org.jetbrains.kotlin",
),
)

attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attribute(KotlinCompilerVersion.attribute, objects.named(kotlinVersion))
if (GradleVersion.current() >= GradleVersion.version("7.0")) {
attribute(
GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE,
objects.named(GradleVersion.current().version),
)
}
}
}

skieGradleConfiguration.resolvedConfiguration.rethrowFailure()

val classLoaderFactory = serviceOf<HashingClassLoaderFactory>()
val skieGradleClassLoader = classLoaderFactory.createChildClassLoader(
"skieGradleClassLoader",
buildscript.classLoader,
DefaultClassPath.of(skieGradleConfiguration.resolve()),
null,
)

val probablySkiePluginClass = skieGradleClassLoader.loadClass("co.touchlab.skie.plugin.SkieGradlePlugin")
if (!Plugin::class.java.isAssignableFrom(probablySkiePluginClass)) {
reportSkieLoaderError(
"""
Loaded class ${probablySkiePluginClass.name} does not implement ${Plugin::class.java.name}!
This is a bug in SKIE - please report it to the SKIE developers.
""".trimIndent(),
)
return
}

@Suppress("UNCHECKED_CAST")
val shimPlugin: Class<Plugin<Project>> = probablySkiePluginClass as Class<Plugin<Project>>
plugins.apply(shimPlugin)
}

private val Project.kotlinGradlePluginVersion: String?
get() = kotlinGradlePluginVersionFromPlugin() ?: kotlinGradlePluginVersionFromClasspathConfiguration()

Expand Down Expand Up @@ -176,4 +132,97 @@ abstract class SkieLoaderPlugin : Plugin<Project> {

private inline fun <reified T : Named> ObjectFactory.named(name: String): T =
named(T::class.java, name)

private fun Project.configureSkieGradlePlugin() {
SkieSubPluginManager.configureDependenciesForSubPlugins(project)
}

private fun Project.configureRuntimeVariantFallback() {
if (!skieInternal.runtimeVariantFallback.isPresent) {
val extraPropertiesKey = "skieRuntimeVariantFallback"
skieInternal.runtimeVariantFallback.set(
project.properties[extraPropertiesKey]?.toString().toBoolean()
)
}
}

private fun Project.configureSkieCompilerPlugin(kotlinToolingVersion: String) {
if (!isSkieEnabled) {
return
}

warnOnEmptyFrameworks()

FatFrameworkConfigurator.configureSkieForFatFrameworks(project)

kotlinMultiplatformExtension?.appleTargets?.all {
val target = this
binaries.withType<Framework>().all {
val binary = this
skieInternal.targets.add(
SkieTarget.TargetBinary(
project = project,
target = target,
binary = binary,
)
)
}
}

kotlinArtifactsExtension.artifacts.withType<KotlinNativeArtifact>().all {
skieInternal.targets.addAll(skieTargetsOf(this))
}

skieInternal.targets.all {
configureSkie(kotlinToolingVersion)
}
}

private fun SkieTarget.configureSkie(kotlinToolingVersion: String) {
SkieDirectoriesManager.configureCreateSkieBuildDirectoryTask(this)

GradleAnalyticsManager(project).configureAnalytics(this)

configureMinOsVersionIfNeeded()

CreateSkieConfigurationTask.registerTask(this)

SwiftLinkingConfigurator.configureCustomSwiftLinking(this)

disableCachingIfNeeded()

addDependencyOnSkieRuntime(kotlinToolingVersion)

SkieSubPluginManager.registerSubPlugins(this)

configureKotlinCompiler(kotlinToolingVersion)
}

private fun SkieTarget.configureKotlinCompiler(kotlinToolingVersion: String) {
addPluginArgument(
SkiePlugin.id,
SkiePlugin.Options.skieDirectories.subpluginOption(skieDirectories.get()),
)

addToCompilerClasspath(
SkieCompilerPluginDependencyProvider.getOrCreateDependencyConfiguration(project, kotlinToolingVersion)
)
}
}

internal fun Project.warnOnEmptyFrameworks() {
gradle.taskGraph.whenReady {
if (skieInternal.targets.isEmpty()) {
logger.warn("w: No Apple frameworks configured in module ${this@warnOnEmptyFrameworks.path}. Make sure you applied SKIE plugin in the correct module.")
}
}
}

private val Project.isSkieEnabled: Boolean
get() = project.skieExtension.isEnabled.get() && HostManager.hostIsMac

internal val Project.kotlinMultiplatformExtension: KotlinMultiplatformExtension?
get() = project.extensions.findByType(KotlinMultiplatformExtension::class.java)

internal val Project.skieInternal: SkieInternalExtension
get() = project.extensions.getByType(SkieInternalExtension::class.java)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package co.touchlab.skie.plugin

import co.touchlab.skie.gradle.KotlinCompilerVersion
import co.touchlab.skie.gradle_plugin.BuildConfig
import co.touchlab.skie.plugin.configuration.SkieExtension
import org.gradle.api.Named
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.plugin.GradlePluginApiVersion
import org.gradle.api.model.ObjectFactory
import org.gradle.configurationcache.extensions.serviceOf
import org.gradle.internal.classloader.HashingClassLoaderFactory
import org.gradle.internal.classpath.DefaultClassPath
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin

// @Suppress("unused")
// abstract class SkieLoaderPlugin : Plugin<Project> {
//
// override fun apply(project: Project) {
// // We need to register the extension here, so that Gradle knows the type of it in the build script.
//
//
// project.loadSkieGradlePlugin(kotlinVersion)
// }
//
//
// private fun Project.loadSkieGradlePlugin(kotlinVersion: String) {
// val gradleVersion = GradleVersion.current().version
// logger.info("Resolving SKIE gradle plugin for Kotlin plugin version $kotlinVersion and Gradle version $gradleVersion")
//
// plugins.apply(SkieGradlePlugin::class.java)
// }
//
// }
Loading

0 comments on commit 652f073

Please sign in to comment.