From 24debfd9b743692a6565055172c5cd9a4de6cebe Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Thu, 29 Jun 2023 14:35:40 +0200 Subject: [PATCH] [Gradle] ExternalTargetApi: Implement ExternalKotlinTargetSourcesJarUtils This utils are intended to be used external target authors exclusively and shall help to create sources.jar files using regular Kotlin Multiplatform conventions. ^KT-58109 Verification Pending --- .../api/kotlin-gradle-plugin.api | 7 ++ .../plugin/mpp/InternalKotlinCompilation.kt | 9 +- .../plugin/mpp/KotlinMultiplatformPlugin.kt | 68 +----------- .../ExternalKotlinTargetSourcesJarUtils.kt | 78 +++++++++++++ .../kotlin/gradle/plugin/mpp/mppSourcesJar.kt | 92 ++++++++++++++++ .../unitTests/ExternalKotlinTargetApiTests.kt | 27 +---- ...ExternalKotlinTargetSourcesJarUtilsTest.kt | 104 ++++++++++++++++++ .../gradle/util/externalTargetApiUtils.kt | 27 +++++ 8 files changed, 326 insertions(+), 86 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSourcesJarUtils.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppSourcesJar.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt diff --git a/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api b/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api index 2f5ded0cfaa..a7a07d963de 100644 --- a/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api +++ b/libraries/tools/kotlin-gradle-plugin/api/kotlin-gradle-plugin.api @@ -831,6 +831,13 @@ public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotli public static final fun ExternalKotlinTargetDescriptor (Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor; } +public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSourcesJarUtilsKt { + public static final fun includeSources (Lorg/gradle/jvm/tasks/Jar;Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinCompilation;)V + public static final fun publishSources (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget;Lorg/gradle/api/tasks/TaskProvider;)V + public static final fun publishSources (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget;Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinCompilation;)V + public static final fun sourcesJarTask (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinTarget;Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedExternalKotlinCompilation;)Lorg/gradle/api/tasks/TaskProvider; +} + public abstract class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier { } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/InternalKotlinCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/InternalKotlinCompilation.kt index 55cdbebe59c..4760a2a450f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/InternalKotlinCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/InternalKotlinCompilation.kt @@ -8,7 +8,9 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.await import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationConfigurationsContainer import org.jetbrains.kotlin.gradle.utils.ObservableSet import org.jetbrains.kotlin.tooling.core.HasMutableExtras @@ -25,4 +27,9 @@ internal interface InternalKotlinCompilation : Kotl internal val KotlinCompilation.internal: InternalKotlinCompilation get() = (this as? InternalKotlinCompilation) ?: throw IllegalArgumentException( "KotlinCompilation($name) ${this::class} does not implement ${InternalKotlinCompilation::class}" - ) \ No newline at end of file + ) + +internal suspend fun InternalKotlinCompilation<*>.awaitAllKotlinSourceSets(): Set { + KotlinPluginLifecycle.Stage.AfterFinaliseCompilations.await() + return allKotlinSourceSets +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index d4897190817..b660f465a08 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -7,14 +7,11 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.file.DuplicatesStrategy -import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.JavaBasePlugin -import org.gradle.api.tasks.TaskProvider -import org.gradle.jvm.tasks.Jar import org.gradle.util.GradleVersion -import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.explicitApiModeAsCompilerArg +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.* @@ -37,14 +34,12 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinWasmTargetPreset import org.jetbrains.kotlin.gradle.targets.native.createFatFrameworks import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.registerKotlinArtifactsExtension import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool -import org.jetbrains.kotlin.gradle.tasks.locateTask -import org.jetbrains.kotlin.gradle.tasks.registerTask -import org.jetbrains.kotlin.gradle.utils.* +import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility +import org.jetbrains.kotlin.gradle.utils.runProjectConfigurationHealthCheck import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget.* import org.jetbrains.kotlin.konan.target.presetName import org.jetbrains.kotlin.statistics.metrics.StringMetrics -import java.io.File class KotlinMultiplatformPlugin : Plugin { @@ -259,62 +254,7 @@ internal fun applyUserDefinedAttributes(target: AbstractKotlinTarget) { } } -internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String, artifactNameAppendix: String): TaskProvider = - sourcesJarTask( - compilation.target.project, - compilation.target.project.future { - KotlinPluginLifecycle.Stage.AfterFinaliseCompilations.await() - compilation.allKotlinSourceSets.associate { it.name to it.kotlin } - }, - componentName, - artifactNameAppendix - ) -private fun sourcesJarTask( - project: Project, - sourceSets: Future>>, - taskNamePrefix: String, - artifactNameAppendix: String, -): TaskProvider = - sourcesJarTaskNamed(lowerCamelCaseName(taskNamePrefix, "sourcesJar"), taskNamePrefix, project, sourceSets, artifactNameAppendix) - -internal fun sourcesJarTaskNamed( - taskName: String, - componentName: String, - project: Project, - sourceSets: Future>>, - artifactNameAppendix: String, - componentTypeName: String = "target", -): TaskProvider { - project.locateTask(taskName)?.let { - return it - } - - val result = project.registerTask(taskName) { sourcesJar -> - sourcesJar.archiveAppendix.set(artifactNameAppendix) - sourcesJar.archiveClassifier.set("sources") - sourcesJar.isPreserveFileTimestamps = false - sourcesJar.isReproducibleFileOrder = true - sourcesJar.group = BasePlugin.BUILD_GROUP - sourcesJar.description = "Assembles a jar archive containing the sources of $componentTypeName '$componentName'." - } - - result.configure { - project.launch { - sourceSets.await().forEach { (sourceSetName, sourceSetFiles) -> - it.from(sourceSetFiles) { copySpec -> - copySpec.into(sourceSetName) - // Duplicates are coming from `SourceSets` that `sourceSet` depends on. - // Such dependency was added by Kotlin compilation. - // TODO: rethink approach for adding dependent `SourceSets` to Kotlin compilation `SourceSet` - copySpec.duplicatesStrategy = DuplicatesStrategy.WARN - } - } - } - } - - return result -} internal fun Project.setupGeneralKotlinExtensionParameters() { project.launch { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSourcesJarUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSourcesJarUtils.kt new file mode 100644 index 00000000000..27686b7345f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetSourcesJarUtils.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2023 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.mpp.external + +import org.gradle.api.tasks.TaskProvider +import org.gradle.jvm.tasks.Jar +import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi +import org.jetbrains.kotlin.gradle.plugin.mpp.includeSources +import org.jetbrains.kotlin.gradle.plugin.mpp.internal +import org.jetbrains.kotlin.gradle.plugin.mpp.isMain +import org.jetbrains.kotlin.gradle.plugin.mpp.sourcesJarTask +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly + +/** + * + * Will add all sources (including transitive dependsOn edges) from the compilation into this jar task given + * the multiplatform convention. + * + * e.g. + * ``` + * src/commonMain/kotlin/CommonMain.kt + * src/jvmMain/kotlin/JvmMain.kt + * ``` + * + * will be packaged like + * ``` + * /commonMain/CommonMain.kt + * /jvmMain/JvmMain.kt + * ``` + * + * @since 1.9.20 + */ +@ExternalKotlinTargetApi +fun Jar.includeSources(compilation: DecoratedExternalKotlinCompilation) { + includeSources(compilation.internal) +} + +/** + * Registers, or returns if already existing, a sources jar task that contains + * all sources of the given compilation (see [includeSources]) + * + * @since 1.9.20 + */ +@ExternalKotlinTargetApi +fun DecoratedExternalKotlinTarget.sourcesJarTask(compilation: DecoratedExternalKotlinCompilation): TaskProvider { + return sourcesJarTask( + compilation, + componentName = lowerCamelCaseName(targetName, compilation.name.takeUnless { compilation.isMain() }), + artifactNameAppendix = targetName.toLowerCaseAsciiOnly() + ) +} + +/** + * Publishes the sources packaged by the given [jarTask] in this targets' publication. + * + * @since 1.9.20 + */ +@ExternalKotlinTargetApi +fun DecoratedExternalKotlinTarget.publishSources(jarTask: TaskProvider) { + delegate.sourcesElementsPublishedConfiguration.outgoing.artifact(jarTask) { artifact -> + artifact.classifier = "sources" + } +} + +/** + * Publishes the sources associated with the given [compilation] in this targets' publication. + * Will register the corresponding [sourcesJarTask] if necessary. + * + * @since 1.9.20 + */ +@ExternalKotlinTargetApi +fun DecoratedExternalKotlinTarget.publishSources(compilation: DecoratedExternalKotlinCompilation) { + publishSources(sourcesJarTask(compilation)) +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppSourcesJar.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppSourcesJar.kt new file mode 100644 index 00000000000..57ffab59257 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppSourcesJar.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2023 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.mpp + +import org.gradle.api.Project +import org.gradle.api.file.DuplicatesStrategy +import org.gradle.api.plugins.BasePlugin +import org.gradle.api.tasks.TaskProvider +import org.gradle.jvm.tasks.Jar +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.launch +import org.jetbrains.kotlin.gradle.tasks.locateTask +import org.jetbrains.kotlin.gradle.tasks.registerTask +import org.jetbrains.kotlin.gradle.utils.Future +import org.jetbrains.kotlin.gradle.utils.future +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import java.io.File + + +internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String, artifactNameAppendix: String): TaskProvider = + sourcesJarTask( + project = compilation.target.project, + sourceSets = compilation.target.project.future { + compilation.internal.awaitAllKotlinSourceSets().associate { it.name to it.kotlin } + }, + componentName = componentName, + artifactNameAppendix = artifactNameAppendix + ) + +private fun sourcesJarTask( + project: Project, + sourceSets: Future>>, + componentName: String, + artifactNameAppendix: String, +): TaskProvider = + sourcesJarTaskNamed( + taskName = lowerCamelCaseName(componentName, "sourcesJar"), + componentName = componentName, + project = project, + sourceSets = sourceSets, + artifactNameAppendix = artifactNameAppendix + ) + +internal fun sourcesJarTaskNamed( + taskName: String, + componentName: String, + project: Project, + sourceSets: Future>>, + artifactNameAppendix: String, + componentTypeName: String = "target", +): TaskProvider { + project.locateTask(taskName)?.let { + return it + } + + val result = project.registerTask(taskName) { sourcesJar -> + sourcesJar.archiveAppendix.set(artifactNameAppendix) + sourcesJar.archiveClassifier.set("sources") + sourcesJar.isPreserveFileTimestamps = false + sourcesJar.isReproducibleFileOrder = true + sourcesJar.group = BasePlugin.BUILD_GROUP + sourcesJar.description = "Assembles a jar archive containing the sources of $componentTypeName '$componentName'." + project.launch { + sourcesJar.includeSources(sourceSets.await()) + } + } + + return result +} + +internal fun Jar.includeSources(compilation: KotlinCompilation<*>) { + compilation.internal.allKotlinSourceSets.forAll { sourceSet -> + includeSources(sourceSet.name, sourceSet.kotlin) + } +} + +internal fun Jar.includeSources(sourceSets: Map>) { + sourceSets.forEach { (name, sources) -> includeSources(name, sources) } +} + +internal fun Jar.includeSources(name: String, sources: Iterable) { + from(sources) { spec -> + spec.into(name) + // Duplicates are coming from `SourceSets` that `sourceSet` depends on. + // Such dependency was added by Kotlin compilation. + // TODO: rethink approach for adding dependent `SourceSets` to Kotlin compilation `SourceSet` + spec.duplicatesStrategy = DuplicatesStrategy.WARN + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt index bb341a9d052..76ca1902d81 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt @@ -17,39 +17,24 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree import org.jetbrains.kotlin.gradle.plugin.hierarchy.KotlinSourceSetTreeClassifier import org.jetbrains.kotlin.gradle.plugin.hierarchy.orNull import org.jetbrains.kotlin.gradle.plugin.launchInStage -import org.jetbrains.kotlin.gradle.plugin.mpp.external.* import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor.CompilationFactory -import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinTargetDescriptor.TargetFactory -import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP -import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest +import org.jetbrains.kotlin.gradle.plugin.mpp.external.createCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.external.createExternalKotlinTarget +import org.jetbrains.kotlin.gradle.util.* import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.toMap import kotlin.test.* class ExternalKotlinTargetApiTests { - class FakeTarget(delegate: Delegate) : DecoratedExternalKotlinTarget(delegate) - class FakeCompilation(delegate: Delegate) : DecoratedExternalKotlinCompilation(delegate) - val project = buildProjectWithMPP() val kotlin = project.multiplatformExtension - private fun ExternalKotlinTargetDescriptorBuilder.defaults() { - targetName = "fake" - platformType = KotlinPlatformType.jvm - targetFactory = TargetFactory(::FakeTarget) - } - - private fun ExternalKotlinCompilationDescriptorBuilder.defaults() { - compilationName = "fake" - compilationFactory = CompilationFactory(::FakeCompilation) - defaultSourceSet = kotlin.sourceSets.maybeCreate("fake") - } @Test fun `test - sourceSetClassifier - default`() = buildProjectWithMPP().runLifecycleAwareTest { val target = kotlin.createExternalKotlinTarget { defaults() } - val compilation = target.createCompilation { defaults() } + val compilation = target.createCompilation { defaults(kotlin) } assertEquals(KotlinSourceSetTree("fake"), KotlinSourceSetTree.orNull(compilation)) } @@ -58,7 +43,7 @@ class ExternalKotlinTargetApiTests { fun `test - sourceSetClassifier - custom name`() = buildProjectWithMPP().runLifecycleAwareTest { val target = kotlin.createExternalKotlinTarget { defaults() } val compilation = target.createCompilation { - defaults() + defaults(kotlin) sourceSetTreeClassifierV2 = KotlinSourceSetTreeClassifier.Name("mySourceSetTree") } @@ -73,7 +58,7 @@ class ExternalKotlinTargetApiTests { val target = kotlin.createExternalKotlinTarget { defaults() } val mainCompilation = target.createCompilation { - defaults() + defaults(kotlin) sourceSetTreeClassifierV2 = KotlinSourceSetTreeClassifier.Property(myProperty) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt new file mode 100644 index 00000000000..b57da4a691c --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright 2010-2023 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. + */ + +@file:Suppress("FunctionName") + +package org.jetbrains.kotlin.gradle.unitTests + +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.internal.file.copy.SingleParentCopySpec +import org.gradle.jvm.tasks.Jar +import org.gradle.kotlin.dsl.create +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree +import org.jetbrains.kotlin.gradle.plugin.configurationResult +import org.jetbrains.kotlin.gradle.plugin.hierarchy.KotlinSourceSetTreeClassifier +import org.jetbrains.kotlin.gradle.plugin.mpp.external.* +import org.jetbrains.kotlin.gradle.util.* +import org.jetbrains.kotlin.tooling.core.withClosure +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.fail + +class ExternalKotlinTargetSourcesJarUtilsTest { + @Test + fun `test - includeSources`() = buildProjectWithMPP().runLifecycleAwareTest { + val target = multiplatformExtension.createExternalKotlinTarget { defaults() } + val compilation = target.createCompilation { + defaults(multiplatformExtension) + defaultSourceSet = multiplatformExtension.sourceSets.maybeCreate("testSourceSet") + sourceSetTreeClassifierV2 = KotlinSourceSetTreeClassifier.Value(KotlinSourceSetTree.main) + } + + val jar = tasks.create("forTest") + jar.includeSources(compilation) + configurationResult.await() + + val allSpecs = jar.rootSpec.withClosure { it.children } + + val testSourceSetSpec = allSpecs.filterIsInstance().find { it.destPath == "testSourceSet" } + ?: fail("Missing 'testSourceSet' in jar") + + assertEquals( + setOf(file("src/testSourceSet/kotlin")), + (testSourceSetSpec.sourcePaths.single() as SourceDirectorySet).srcDirs + ) + + val commonMainSpec = allSpecs.filterIsInstance().find { it.destPath == "commonMain" } + ?: fail("Missing 'commonMain' in jar") + + assertEquals( + setOf(file("src/commonMain/kotlin")), + (commonMainSpec.sourcePaths.single() as SourceDirectorySet).srcDirs + ) + } + + @Test + fun `test - sourcesJarTask`() = buildProjectWithMPP().runLifecycleAwareTest { + val target = multiplatformExtension.createExternalKotlinTarget { defaults() } + + val mainCompilation = target.createCompilation { + defaults(multiplatformExtension) + compilationName = "main" + } + + val auxCompilation = target.createCompilation { + defaults(multiplatformExtension) + compilationName = "aux" + } + + val mainJar = target.sourcesJarTask(mainCompilation) + assertEquals(mainJar, target.sourcesJarTask(mainCompilation)) + assertEquals("fakeSourcesJar", mainJar.name) + + val auxJar = target.sourcesJarTask(auxCompilation) + assertNotEquals(mainJar, auxJar) + assertEquals(auxJar, target.sourcesJarTask(auxCompilation)) + assertEquals("fakeAuxSourcesJar", auxJar.name) + } + + @Test + fun `test - publishSources`() = buildProjectWithMPP().runLifecycleAwareTest { + val target = multiplatformExtension.createExternalKotlinTarget { defaults() } + + val mainCompilation = target.createCompilation { + defaults(multiplatformExtension) + compilationName = "main" + } + + target.publishSources(mainCompilation) + configurationResult.await() + + val sourcesArtifacts = target.sourcesElementsPublishedConfiguration.outgoing.artifacts.filter { artifact -> + artifact.classifier == "sources" + } + + if (sourcesArtifacts.isEmpty()) fail("Missing 'sources' artifacts") + if (sourcesArtifacts.size > 1) fail("Expected single 'sources' artifact. Found $sourcesArtifacts") + val sourcesArtifact = sourcesArtifacts.single() + assertEquals(target.sourcesJarTask(mainCompilation).get().archiveFile.get().asFile, sourcesArtifact.file) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt new file mode 100644 index 00000000000..dfbf1b63cde --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2023 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.util + +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.external.* +import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor.CompilationFactory +import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinTargetDescriptor.TargetFactory + +class FakeCompilation(delegate: Delegate) : DecoratedExternalKotlinCompilation(delegate) +class FakeTarget(delegate: Delegate) : DecoratedExternalKotlinTarget(delegate) + +fun ExternalKotlinTargetDescriptorBuilder.defaults() { + targetName = "fake" + platformType = KotlinPlatformType.jvm + targetFactory = TargetFactory(::FakeTarget) +} + +fun ExternalKotlinCompilationDescriptorBuilder.defaults(kotlin: KotlinMultiplatformExtension) { + compilationName = "fake" + compilationFactory = CompilationFactory(::FakeCompilation) + defaultSourceSet = kotlin.sourceSets.maybeCreate("fake") +}