From e8774448ee9b6e84c070699a68e86e844cf77c08 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Thu, 7 Apr 2022 16:55:30 +0200 Subject: [PATCH] Allow to register specific variant implementations Such way those implementations are accessible from the common code. To avoid putting stub implementations in every variant, it is also possible to add default implementation from the common code if variant hasn't register own. As an example of usage, support for removed in Gradle 7.0 'maven' plugin was moved into 'main' variant (Gradle 6.7.1 - 6.9.3). ^KT-49227 In Progress --- .../jetbrains/kotlin/gradle/PublishingIT.kt | 42 ++++++ .../old-maven-publish/build.gradle | 23 ++++ .../src/main/kotlin/ExampleClass.kt | 11 ++ .../internal/kapt/KaptWithoutKotlincTask.kt | 4 +- .../plugin/KotlinMultiplatformPlugin.kt | 42 +----- .../kotlin/gradle/plugin/KotlinPlugin.kt | 69 +--------- .../gradle/plugin/KotlinPluginWrapper.kt | 26 ++-- .../plugin/VariantImplementationFactories.kt | 59 +++++++++ .../internal/MavenPluginConfigurator.kt | 37 ++++++ .../kotlin/gradle/plugin/mpp/KotlinUsages.kt | 4 - .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 6 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 79 ++++++++++++ .../kotlin/gradle/plugin/PluginWrappers.kt | 122 ++++++++++++++++++ .../internal/MavenPluginConfiguratorG6.kt | 53 ++++++++ 14 files changed, 457 insertions(+), 120 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/src/main/kotlin/ExampleClass.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/VariantImplementationFactories.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfigurator.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfiguratorG6.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt index ea7f3ea3b7a..520e05b9c63 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt @@ -5,9 +5,12 @@ package org.jetbrains.kotlin.gradle +import org.gradle.api.logging.configuration.WarningMode import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.testbase.* import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Path import kotlin.io.path.appendText import kotlin.io.path.readLines import kotlin.io.path.readText @@ -107,4 +110,43 @@ class PublishingIT : KGPBaseTest() { } } } + + @DisplayName("Publication with old 'maven' plugin is working") + @GradleTest + @GradleTestVersions(maxVersion = TestVersions.Gradle.G_6_9) + fun testOldMavenPublishing( + gradleVersion: GradleVersion, + @TempDir localRepoDir: Path + ) { + project( + projectName = "old-maven-publish", + gradleVersion = gradleVersion, + localRepoDir = localRepoDir, + buildOptions = defaultBuildOptions.copy( + warningMode = WarningMode.Summary // 'maven' is deprecated + ) + ) { + build("uploadArchives") { + val publishingDir = localRepoDir.resolve("org.jetbrains.kotlin.example").resolve("1.0.0") + assertDirectoryExists(publishingDir) + assertFileExists(publishingDir.resolve("org.jetbrains.kotlin.example-1.0.0.jar")) + val pomFile = publishingDir.resolve("org.jetbrains.kotlin.example-1.0.0.pom") + assertFileExists(pomFile) + assertFileContains( + pomFile, + """ + | + | + | org.jetbrains.kotlin + | kotlin-stdlib + | ${buildOptions.kotlinVersion} + | compile + | + | + """.trimMargin() + ) + } + } + } + } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/build.gradle new file mode 100644 index 00000000000..3b87adc40b8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/build.gradle @@ -0,0 +1,23 @@ +plugins { + id "org.jetbrains.kotlin.jvm" + id "maven" +} + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + api "org.jetbrains.kotlin:kotlin-stdlib" +} + +uploadArchives { + repositories { + mavenDeployer { + repository(url: "file://localhost") + pom.artifactId = "org.jetbrains.kotlin.example" + pom.version = "1.0.0" + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/src/main/kotlin/ExampleClass.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/src/main/kotlin/ExampleClass.kt new file mode 100644 index 00000000000..0b038b5a5f8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/old-maven-publish/src/main/kotlin/ExampleClass.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package testProject.publishing +class ExampleClass { + fun one() = 1 + + fun two() = 2 +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index c32094c8275..73164095ac9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_ import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.ClassLoadersCache import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.rootOrSelf import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges -import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper +import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinAndroidPluginWrapper import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast @@ -46,7 +46,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor( override fun configure(task: KaptWithoutKotlincTask) { super.configure(task) task.addJdkClassesToClasspath.value( - task.project.providers.provider { task.project.plugins.none { it is KotlinAndroidPluginWrapper } } + task.project.providers.provider { task.project.plugins.none { it is AbstractKotlinAndroidPluginWrapper } } ).disallowChanges() task.kaptJars.from(task.project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)).disallowChanges() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt index fff6e551681..c23f1c0d446 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinMultiplatformPlugin.kt @@ -40,13 +40,6 @@ abstract class KotlinPlatformPluginBase(protected val platformName: String) : Pl } } -open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { - override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) - project.applyPlugin() - } -} - const val EXPECTED_BY_CONFIG_NAME = "expectedBy" const val IMPLEMENT_CONFIG_NAME = "implement" @@ -252,39 +245,6 @@ internal fun Project.whenEvaluated(fn: Project.() -> T) { } } -open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase("android") { - override fun apply(project: Project) { - project.applyPlugin() - super.apply(project) - } - - override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = - (project.extensions.getByName("android") as BaseExtension).sourceSets - - override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) { - val androidExtension = platformProject.extensions.getByName("android") as BaseExtension - val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return - val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet - ?: return - kotlinSourceSet.kotlin.source(getKotlinSourceDirectorySetSafe(commonSourceSet)!!) - } -} - -open class KotlinPlatformJvmPlugin : KotlinPlatformImplementationPluginBase("jvm") { - override fun apply(project: Project) { - project.applyPlugin() - super.apply(project) - } -} - -open class KotlinPlatformJsPlugin : KotlinPlatformImplementationPluginBase("js") { - override fun apply(project: Project) { - @Suppress("DEPRECATION_ERROR") - project.applyPlugin() - super.apply(project) - } -} - internal val KOTLIN_12X_MPP_DEPRECATION_WARNING = "\n" + """ The 'org.jetbrains.kotlin.platform.*' plugins are deprecated and will no longer be available in Kotlin 1.4. Please migrate the project to the 'org.jetbrains.kotlin.multiplatform' plugin. @@ -293,7 +253,7 @@ internal val KOTLIN_12X_MPP_DEPRECATION_WARNING = "\n" + """ private const val KOTLIN_12X_MPP_DEPRECATION_SUPPRESS_FLAG = "kotlin.internal.mpp12x.deprecation.suppress" -private fun warnAboutKotlin12xMppDeprecation(project: Project) { +internal fun warnAboutKotlin12xMppDeprecation(project: Project) { if (project.findProperty(KOTLIN_12X_MPP_DEPRECATION_SUPPRESS_FLAG) != "true") { SingleWarningPerBuild.show(project, KOTLIN_12X_MPP_DEPRECATION_WARNING) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 80d5859d07c..24613a54a16 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -9,7 +9,6 @@ import com.android.build.gradle.* import com.android.build.gradle.BasePlugin import com.android.build.gradle.api.* import org.gradle.api.* -import org.gradle.api.artifacts.repositories.ArtifactRepository import org.gradle.api.attributes.Category import org.gradle.api.attributes.Usage import org.gradle.api.file.ConfigurableFileTree @@ -26,13 +25,13 @@ import org.gradle.api.tasks.* import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.jvm.tasks.Jar import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry -import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder +import org.jetbrains.kotlin.gradle.plugin.internal.MavenPluginConfigurator import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData @@ -45,14 +44,10 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.tooling.includeKotlinToolingMetadataInApk import org.jetbrains.kotlin.gradle.utils.* -import org.jetbrains.kotlin.utils.addToStdlib.cast import java.io.File import java.net.URL import java.util.concurrent.Callable import java.util.jar.Manifest -import kotlin.reflect.full.functions -import kotlin.reflect.full.staticProperties -import kotlin.reflect.jvm.isAccessible const val PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kotlinCompilerPluginClasspath" const val NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kotlinNativeCompilerPluginClasspath" @@ -438,64 +433,10 @@ internal abstract class AbstractKotlinPlugin( } } - if (GradleVersion.version(project.gradle.gradleVersion) < GradleVersion.version("7.0")) { - project.pluginManager.withPlugin("maven") { - project.tasks.withType(Upload::class.java).configureEach { uploadTask -> - uploadTask - .repositories - .withType( - Class.forName("org.gradle.api.artifacts.maven.MavenResolver") - .cast>() - ) - .configureEach { mavenResolver -> - val pomRewriter = PomDependenciesRewriter(project, target.kotlinComponents.single()) - val mavenPom = mavenResolver::class - .functions - .first { it.name == "getPom" } - .also { it.isAccessible = true } - .call(mavenResolver)!! - mavenPom::class - .functions - .first { func -> - // On older Gradle versions there were two 'withXml' method - one with 'Closure' and one with 'Action' - func.name == "withXml" && - func.parameters.any { - it.type.toString() == "org.gradle.api.Action!" - } - } - .call(mavenPom, Action { xml -> - if (shouldRewritePoms.get()) { - pomRewriter.rewritePomMppDependenciesToActualTargetModules(xml) - } - }) - } - } - - // Setup conf2ScopeMappings so that the API dependencies are written - // with compile scope in the POMs in case of 'java' plugin - val mavenPluginConvention = project - .convention - .getPlugin(Class.forName("org.gradle.api.plugins.MavenPluginConvention")) - - val conf2ScopeMappingContainer = mavenPluginConvention::class - .functions - .first { it.name == "getConf2ScopeMappings" } - .call(mavenPluginConvention)!! - - conf2ScopeMappingContainer::class - .functions - .first { it.name == "addMapping" } - .call( - conf2ScopeMappingContainer, - 0, - project.configurations.getByName("api"), - conf2ScopeMappingContainer::class - .staticProperties - .first { it.name == "COMPILE" } - .get() - ) - } - } + VariantImplementationFactories + .get(project.gradle)[MavenPluginConfigurator.MavenPluginConfiguratorVariantFactory::class] + .getInstance() + .applyConfiguration(project, target, shouldRewritePoms) } companion object { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index a5455708d47..b6bd9c4d8e3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.internal.KOTLIN_COMPILER_EMBEDDABLE import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP import org.jetbrains.kotlin.gradle.logging.kotlinDebug +import org.jetbrains.kotlin.gradle.plugin.internal.MavenPluginConfigurator import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20GradlePlugin @@ -50,7 +51,6 @@ import org.jetbrains.kotlin.gradle.utils.loadPropertyFromResources import org.jetbrains.kotlin.gradle.utils.runProjectConfigurationHealthCheck import org.jetbrains.kotlin.statistics.metrics.StringMetrics import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion -import javax.inject.Inject import kotlin.reflect.KClass abstract class KotlinBasePluginWrapper : Plugin { @@ -90,6 +90,8 @@ abstract class KotlinBasePluginWrapper : Plugin { } project.registerCommonizerClasspathConfigurationIfNecessary() + project.registerDefaultVariantImplementations() + KotlinGradleBuildServices.registerIfAbsent(project, kotlinPluginVersion).get() KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion) @@ -132,6 +134,14 @@ abstract class KotlinBasePluginWrapper : Plugin { project.registerBuildKotlinToolingMetadataTask() } + private fun Project.registerDefaultVariantImplementations() { + val factories = VariantImplementationFactories.get(project.gradle) + factories.putIfAbsent( + MavenPluginConfigurator.MavenPluginConfiguratorVariantFactory::class, + MavenPluginConfigurator.DefaultMavenPluginConfiguratorVariantFactory() + ) + } + private fun addKotlinCompilerConfiguration(project: Project) { project .configurations @@ -169,7 +179,7 @@ abstract class KotlinBasePluginWrapper : Plugin { ): Plugin } -open class KotlinPluginWrapper @Inject constructor( +abstract class AbstractKotlinPluginWrapper( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { override fun getPlugin(project: Project): Plugin = @@ -179,7 +189,7 @@ open class KotlinPluginWrapper @Inject constructor( get() = KotlinJvmProjectExtension::class } -open class KotlinCommonPluginWrapper @Inject constructor( +abstract class AbstractKotlinCommonPluginWrapper( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { override fun getPlugin(project: Project): Plugin = @@ -189,7 +199,7 @@ open class KotlinCommonPluginWrapper @Inject constructor( get() = KotlinCommonProjectExtension::class } -open class KotlinAndroidPluginWrapper @Inject constructor( +abstract class AbstractKotlinAndroidPluginWrapper( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { override fun getPlugin(project: Project): Plugin = @@ -203,7 +213,7 @@ open class KotlinAndroidPluginWrapper @Inject constructor( message = "Should be removed with JS platform plugin", level = DeprecationLevel.ERROR ) -open class Kotlin2JsPluginWrapper @Inject constructor( +abstract class AbstractKotlin2JsPluginWrapper( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { @@ -215,7 +225,7 @@ open class Kotlin2JsPluginWrapper @Inject constructor( get() = Kotlin2JsProjectExtension::class } -open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() { +abstract class AbstractKotlinJsPluginWrapper : KotlinBasePluginWrapper() { override fun getPlugin(project: Project): Plugin = KotlinJsPlugin(project.getKotlinPluginVersion()) @@ -246,7 +256,7 @@ open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() { override fun createTestRegistry(project: Project) = KotlinTestsRegistry(project, "test") } -open class KotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() { +abstract class AbstractKotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() { override fun getPlugin(project: Project): Plugin = KotlinMultiplatformPlugin() @@ -260,7 +270,7 @@ open class KotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() { } } -open class KotlinPm20PluginWrapper @Inject constructor( +abstract class AbstractKotlinPm20PluginWrapper( private val objectFactory: ObjectFactory ) : KotlinBasePluginWrapper() { override fun getPlugin(project: Project): Plugin = diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/VariantImplementationFactories.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/VariantImplementationFactories.kt new file mode 100644 index 00000000000..e97d652b3e4 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/VariantImplementationFactories.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin + +import org.gradle.api.invocation.Gradle +import org.gradle.api.provider.Provider +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import java.util.concurrent.ConcurrentHashMap +import kotlin.reflect.KClass + +/** + * Provides a way for Gradle plugin variants to register specific implementation factories, + * that could be used inside common code. + */ +abstract class VariantImplementationFactories : BuildService { + private val factories: MutableMap, VariantImplementationFactory> = ConcurrentHashMap() + operator fun set( + type: KClass, + factory: T + ) { + factories[type] = factory + } + + fun putIfAbsent( + type: KClass, + factory: T + ) { + factories.putIfAbsent(type, factory) + } + + @Suppress("UNCHECKED_CAST") + operator fun get(type: KClass): T { + return factories[type] as? T ?: throw IllegalArgumentException("${type.simpleName} type is not known for plugin variants") + } + + /** + * Marker interface for actual implementation factories. + */ + interface VariantImplementationFactory + + companion object { + fun getProvider( + gradle: Gradle + ): Provider { + // Use class loader hashcode in case there are multiple class loaders in the same build + return gradle.sharedServices + .registerIfAbsent( + "variant_impl_factories_${VariantImplementationFactories::class.java.classLoader.hashCode()}", + VariantImplementationFactories::class.java + ) {} + } + + fun get(gradle: Gradle): VariantImplementationFactories = getProvider(gradle).get() + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfigurator.kt new file mode 100644 index 00000000000..82452026507 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfigurator.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.internal + +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.jetbrains.kotlin.gradle.plugin.VariantImplementationFactories +import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinTarget + +/** + * Additional configuration for 'maven' Gradle plugin. + * Documentation: https://docs.gradle.org/6.0/userguide/maven_plugin.html + */ +interface MavenPluginConfigurator { + fun applyConfiguration( + project: Project, + target: AbstractKotlinTarget, + shouldRewritePoms: Provider + ) + + interface MavenPluginConfiguratorVariantFactory : VariantImplementationFactories.VariantImplementationFactory { + fun getInstance(): MavenPluginConfigurator + } + + class DefaultMavenPluginConfiguratorVariantFactory : MavenPluginConfiguratorVariantFactory { + override fun getInstance(): MavenPluginConfigurator = object : MavenPluginConfigurator { + override fun applyConfiguration( + project: Project, + target: AbstractKotlinTarget, + shouldRewritePoms: Provider + ) = Unit + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt index 94564efaebd..b0b8cd7e18c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt @@ -8,12 +8,8 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.attributes.* import org.gradle.api.attributes.Usage.* -import org.gradle.kotlin.dsl.findByType -import org.gradle.kotlin.dsl.hasPlugin -import org.jetbrains.kotlin.gradle.dsl.KotlinCommonProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformCommonPlugin import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.* import org.jetbrains.kotlin.gradle.plugin.KotlinTarget diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index f144e80cc54..a65e2a667b7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -275,7 +275,11 @@ abstract class AbstractKotlinCompile @Inject constr task.sourceSetName.set(project.provider { compilation.compilationPurpose }) task.multiPlatformEnabled.value( project.provider { - project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper || it is KotlinPm20PluginWrapper } + project.plugins.any { + it is KotlinPlatformPluginBase || + it is AbstractKotlinMultiplatformPluginWrapper || + it is AbstractKotlinPm20PluginWrapper + } } ).disallowChanges() task.taskBuildCacheableOutputDirectory.value(getKotlinBuildDir(task).map { it.dir("cacheable") }).disallowChanges() diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt new file mode 100644 index 00000000000..163df392297 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin + +import com.android.build.gradle.BaseExtension +import org.gradle.api.Named +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.api.model.ObjectFactory +import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry +import javax.inject.Inject + +open class KotlinPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlinPluginWrapper(registry) + +open class KotlinCommonPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlinCommonPluginWrapper(registry) + +open class KotlinAndroidPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlinAndroidPluginWrapper(registry) + +@Suppress("DEPRECATION_ERROR") +open class Kotlin2JsPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlin2JsPluginWrapper(registry) + +open class KotlinMultiplatformPluginWrapper : AbstractKotlinMultiplatformPluginWrapper() + +open class KotlinJsPluginWrapper : AbstractKotlinJsPluginWrapper() + +open class KotlinPm20PluginWrapper @Inject constructor( + objectFactory: ObjectFactory +) : AbstractKotlinPm20PluginWrapper(objectFactory) + +open class KotlinPlatformJvmPlugin : KotlinPlatformImplementationPluginBase("jvm") { + override fun apply(project: Project) { + project.applyPlugin() + super.apply(project) + } +} + +open class KotlinPlatformJsPlugin : KotlinPlatformImplementationPluginBase("js") { + override fun apply(project: Project) { + @Suppress("DEPRECATION_ERROR") + project.applyPlugin() + super.apply(project) + } +} + +open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase("android") { + override fun apply(project: Project) { + project.applyPlugin() + super.apply(project) + } + + override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = + (project.extensions.getByName("android") as BaseExtension).sourceSets + + override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) { + val androidExtension = platformProject.extensions.getByName("android") as BaseExtension + val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return + val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet + ?: return + kotlinSourceSet.kotlin.source(getKotlinSourceDirectorySetSafe(commonSourceSet)!!) + } +} + +open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { + override fun apply(project: Project) { + warnAboutKotlin12xMppDeprecation(project) + project.applyPlugin() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt new file mode 100644 index 00000000000..6783bc2ffc8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -0,0 +1,122 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin + +import com.android.build.gradle.BaseExtension +import org.gradle.api.Named +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.api.model.ObjectFactory +import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry +import org.jetbrains.kotlin.gradle.plugin.internal.MavenPluginConfigurator +import org.jetbrains.kotlin.gradle.plugin.internal.MavenPluginConfiguratorG6 +import javax.inject.Inject + +open class KotlinPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlinPluginWrapper(registry) { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +open class KotlinCommonPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlinCommonPluginWrapper(registry) { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +open class KotlinAndroidPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlinAndroidPluginWrapper(registry) { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +@Suppress("DEPRECATION_ERROR") +open class Kotlin2JsPluginWrapper @Inject constructor( + registry: ToolingModelBuilderRegistry +) : AbstractKotlin2JsPluginWrapper(registry) { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +open class KotlinMultiplatformPluginWrapper : AbstractKotlinMultiplatformPluginWrapper() { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +open class KotlinJsPluginWrapper : AbstractKotlinJsPluginWrapper() { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +open class KotlinPm20PluginWrapper @Inject constructor( + objectFactory: ObjectFactory +) : AbstractKotlinPm20PluginWrapper(objectFactory) { + override fun apply(project: Project) { + project.registerVariantImplementations() + super.apply(project) + } +} + +open class KotlinPlatformJvmPlugin : KotlinPlatformImplementationPluginBase("jvm") { + override fun apply(project: Project) { + project.applyPlugin() + super.apply(project) + } +} + +open class KotlinPlatformJsPlugin : KotlinPlatformImplementationPluginBase("js") { + override fun apply(project: Project) { + @Suppress("DEPRECATION_ERROR") + project.applyPlugin() + super.apply(project) + } +} + +open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase("android") { + override fun apply(project: Project) { + project.applyPlugin() + super.apply(project) + } + + override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> = + (project.extensions.getByName("android") as BaseExtension).sourceSets + + override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) { + val androidExtension = platformProject.extensions.getByName("android") as BaseExtension + val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return + val kotlinSourceSet = androidSourceSet.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet + ?: return + kotlinSourceSet.kotlin.source(getKotlinSourceDirectorySetSafe(commonSourceSet)!!) + } +} + +open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { + override fun apply(project: Project) { + warnAboutKotlin12xMppDeprecation(project) + project.applyPlugin() + } +} + +private fun Project.registerVariantImplementations() { + val factories = VariantImplementationFactories.get(gradle) + factories[MavenPluginConfigurator.MavenPluginConfiguratorVariantFactory::class] = + MavenPluginConfiguratorG6.Gradle6MavenPluginConfiguratorVariantFactory() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfiguratorG6.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfiguratorG6.kt new file mode 100644 index 00000000000..624fd4f256d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/MavenPluginConfiguratorG6.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.internal + +import org.gradle.api.Project +import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer +import org.gradle.api.artifacts.maven.MavenPom +import org.gradle.api.artifacts.maven.MavenResolver +import org.gradle.api.plugins.MavenPluginConvention +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Upload +import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.PomDependenciesRewriter + +@Suppress("DEPRECATION") +class MavenPluginConfiguratorG6 : MavenPluginConfigurator { + override fun applyConfiguration( + project: Project, + target: AbstractKotlinTarget, + shouldRewritePoms: Provider + ) { + project.pluginManager.withPlugin("maven") { + project.tasks.withType(Upload::class.java).all { uploadTask -> + uploadTask.repositories.withType(MavenResolver::class.java).all { mavenResolver -> + val pomRewriter = PomDependenciesRewriter(project, target.kotlinComponents.single()) + rewritePom(mavenResolver.pom, pomRewriter, shouldRewritePoms) + } + } + + // Setup conf2ScopeMappings so that the API dependencies are written with the compile scope in the POMs in case of 'java' plugin + project.convention.getPlugin(MavenPluginConvention::class.java) + .conf2ScopeMappings.addMapping(0, project.configurations.getByName("api"), Conf2ScopeMappingContainer.COMPILE) + } + } + + private fun rewritePom( + pom: MavenPom, + rewriter: PomDependenciesRewriter, + shouldRewritePom: Provider + ) { + pom.withXml { xml -> + if (shouldRewritePom.get()) + rewriter.rewritePomMppDependenciesToActualTargetModules(xml) + } + } + + class Gradle6MavenPluginConfiguratorVariantFactory : MavenPluginConfigurator.MavenPluginConfiguratorVariantFactory { + override fun getInstance(): MavenPluginConfigurator = MavenPluginConfiguratorG6() + } +} \ No newline at end of file