Add APIs to resolve multiplatform resources in variant publications
^KT-65540
This commit is contained in:
committed by
Space Team
parent
4c8febf10d
commit
2fda16f526
@@ -912,8 +912,10 @@ public abstract interface class org/jetbrains/kotlin/gradle/plugin/mpp/resources
|
||||
public static final field Companion Lorg/jetbrains/kotlin/gradle/plugin/mpp/resources/KotlinTargetResourcesPublication$Companion;
|
||||
public static final field EXTENSION_NAME Ljava/lang/String;
|
||||
public abstract fun canPublishResources (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTarget;)Z
|
||||
public abstract fun canResolveResources (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTarget;)Z
|
||||
public abstract fun publishInAndroidAssets (Lorg/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTarget;Lkotlin/jvm/functions/Function1;Lorg/gradle/api/provider/Provider;)V
|
||||
public abstract fun publishResourcesAsKotlinComponent (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTarget;Lkotlin/jvm/functions/Function1;Lorg/gradle/api/provider/Provider;)V
|
||||
public abstract fun resolveResources (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTarget;)Lorg/gradle/api/provider/Provider;
|
||||
}
|
||||
|
||||
public abstract class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
|
||||
|
||||
+4
@@ -34,6 +34,10 @@ interface KotlinTargetResourcesPublication {
|
||||
resourcePathForSourceSet: (KotlinSourceSet) -> (ResourceRoot),
|
||||
relativeResourcePlacement: Provider<File>,
|
||||
)
|
||||
|
||||
fun canResolveResources(target: KotlinTarget): Boolean
|
||||
|
||||
fun resolveResources(target: KotlinTarget): Provider<File>
|
||||
|
||||
companion object {
|
||||
const val EXTENSION_NAME = "multiplatformResourcesPublication"
|
||||
|
||||
+89
-2
@@ -6,19 +6,21 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp.resources
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic
|
||||
import org.jetbrains.kotlin.gradle.plugin.launchInStage
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.publication.KotlinAndroidTargetResourcesPublication
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.AggregateResourcesTask
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.KotlinTargetResourcesResolutionStrategy
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.ResolveResourcesFromDependenciesTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||
@@ -42,6 +44,11 @@ internal abstract class KotlinTargetResourcesPublicationImpl @Inject constructor
|
||||
KotlinAndroidTarget::class,
|
||||
)
|
||||
|
||||
private val targetsThatSupportResolution = listOf(
|
||||
KotlinJsIrTarget::class,
|
||||
KotlinNativeTarget::class,
|
||||
)
|
||||
|
||||
private val targetToResourcesMap: MutableMap<KotlinTarget, TargetResources> = mutableMapOf()
|
||||
private val androidTargetAssetsMap: MutableMap<KotlinAndroidTarget, TargetResources> = mutableMapOf()
|
||||
|
||||
@@ -117,6 +124,86 @@ internal abstract class KotlinTargetResourcesPublicationImpl @Inject constructor
|
||||
}
|
||||
}
|
||||
|
||||
override fun canResolveResources(target: KotlinTarget): Boolean {
|
||||
return targetsThatSupportResolution.any { it.isInstance(target) }
|
||||
}
|
||||
|
||||
override fun resolveResources(target: KotlinTarget): Provider<File> {
|
||||
if (!canResolveResources(target)) {
|
||||
target.project.reportDiagnostic(KotlinToolingDiagnostics.ResourceMayNotBeResolvedForTarget(target.name))
|
||||
}
|
||||
|
||||
val aggregateResourcesTaskName = target.disambiguateName("AggregateResources")
|
||||
project.locateTask<AggregateResourcesTask>(aggregateResourcesTaskName)?.let {
|
||||
return it.flatMap { it.outputDirectory.asFile }
|
||||
}
|
||||
|
||||
val resolveResourcesFromDependenciesTask = project.registerTask<ResolveResourcesFromDependenciesTask>(
|
||||
target.disambiguateName("ResolveResourcesFromDependencies")
|
||||
)
|
||||
val aggregateResourcesTask = project.registerTask<AggregateResourcesTask>(aggregateResourcesTaskName) { aggregate ->
|
||||
aggregate.resourcesFromDependenciesDirectory.set(resolveResourcesFromDependenciesTask.flatMap { it.outputDirectory })
|
||||
aggregate.outputDirectory.set(
|
||||
project.layout.buildDirectory.dir("$MULTIPLATFORM_RESOURCES_DIRECTORY/aggregated-resources/${target.targetName}")
|
||||
)
|
||||
}
|
||||
|
||||
project.launchInStage(KotlinPluginLifecycle.Stage.AfterFinaliseCompilations) {
|
||||
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
resolveResourcesFromDependencies(
|
||||
compilation = mainCompilation,
|
||||
resolveResourcesFromDependenciesTask = resolveResourcesFromDependenciesTask,
|
||||
targetName = target.targetName,
|
||||
)
|
||||
resolveResourcesFromSelf(
|
||||
compilation = mainCompilation,
|
||||
target = target,
|
||||
aggregateResourcesTask = aggregateResourcesTask,
|
||||
)
|
||||
}
|
||||
|
||||
return aggregateResourcesTask.flatMap { it.outputDirectory.asFile }
|
||||
}
|
||||
|
||||
private fun resolveResourcesFromDependencies(
|
||||
compilation: KotlinCompilation<*>,
|
||||
resolveResourcesFromDependenciesTask: TaskProvider<ResolveResourcesFromDependenciesTask>,
|
||||
targetName: String,
|
||||
) {
|
||||
resolveResourcesFromDependenciesTask.configure {
|
||||
it.filterResourcesByExtension.set(
|
||||
project.kotlinPropertiesProvider
|
||||
.mppFilterResourcesByExtension
|
||||
.map { explicitlyEnabled ->
|
||||
// Always filter resources configuration because it resolves klibs for dependency graph inheritance
|
||||
explicitlyEnabled || project.kotlinPropertiesProvider.mppResourcesResolutionStrategy == KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration
|
||||
}
|
||||
)
|
||||
it.archivesFromDependencies.from(
|
||||
project.kotlinPropertiesProvider.mppResourcesResolutionStrategy.resourceArchives(compilation)
|
||||
)
|
||||
it.outputDirectory.set(
|
||||
project.layout.buildDirectory.dir("$MULTIPLATFORM_RESOURCES_DIRECTORY/resources-from-dependencies/${targetName}")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveResourcesFromSelf(
|
||||
compilation: KotlinCompilation<*>,
|
||||
target: KotlinTarget,
|
||||
aggregateResourcesTask: TaskProvider<AggregateResourcesTask>,
|
||||
) {
|
||||
subscribeOnPublishResources(target) { resources ->
|
||||
val copyResourcesTask = compilation.assembleHierarchicalResources(
|
||||
target.disambiguateName("ResolveSelfResources"),
|
||||
resources,
|
||||
)
|
||||
aggregateResourcesTask.configure { aggregate ->
|
||||
aggregate.resourcesFromSelfDirectory.set(copyResourcesTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val MULTIPLATFORM_RESOURCES_DIRECTORY = "kotlin-multiplatform-resources"
|
||||
const val RESOURCES_CLASSIFIER = "kotlin_resources"
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2010-2024 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.resources.resolve
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.DuplicatesStrategy
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
import org.jetbrains.kotlin.incremental.deleteDirectoryContents
|
||||
import javax.inject.Inject
|
||||
|
||||
@DisableCachingByDefault
|
||||
internal abstract class AggregateResourcesTask : DefaultTask() {
|
||||
|
||||
@get:Inject
|
||||
abstract val fileSystem: FileSystemOperations
|
||||
|
||||
@get:Optional
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
@get:InputDirectory
|
||||
abstract val resourcesFromDependenciesDirectory: DirectoryProperty
|
||||
|
||||
@get:Optional
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
@get:InputDirectory
|
||||
abstract val resourcesFromSelfDirectory: DirectoryProperty
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDirectory: DirectoryProperty
|
||||
|
||||
@TaskAction
|
||||
fun copyResources() {
|
||||
outputDirectory.get().asFile.deleteDirectoryContents()
|
||||
fileSystem.copy { copy ->
|
||||
resourcesFromDependenciesDirectory.orNull?.let { copy.from(it) }
|
||||
resourcesFromSelfDirectory.orNull?.let { copy.from(it) }
|
||||
copy.into(outputDirectory)
|
||||
copy.duplicatesStrategy = DuplicatesStrategy.FAIL
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2024 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.resources.resolve
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.*
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublicationImpl
|
||||
import org.jetbrains.kotlin.incremental.deleteDirectoryContents
|
||||
import javax.inject.Inject
|
||||
|
||||
@DisableCachingByDefault
|
||||
internal abstract class ResolveResourcesFromDependenciesTask : DefaultTask() {
|
||||
|
||||
@get:Inject
|
||||
abstract val fileSystem: FileSystemOperations
|
||||
|
||||
@get:Inject
|
||||
abstract val archiveOperations: ArchiveOperations
|
||||
|
||||
@get:Input
|
||||
abstract val filterResourcesByExtension: Property<Boolean>
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFiles
|
||||
abstract val archivesFromDependencies: ConfigurableFileCollection
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDirectory: DirectoryProperty
|
||||
|
||||
@TaskAction
|
||||
fun copyResources() {
|
||||
outputDirectory.get().asFile.deleteDirectoryContents()
|
||||
fileSystem.copy { copy ->
|
||||
archivesFromDependencies
|
||||
.filter { it.isFile }
|
||||
.filter { if (filterResourcesByExtension.get()) it.name.endsWith(KotlinTargetResourcesPublicationImpl.RESOURCES_ZIP_EXTENSION) else true }
|
||||
.forEach {
|
||||
copy.from(archiveOperations.zipTree(it))
|
||||
}
|
||||
copy.into(outputDirectory)
|
||||
copy.duplicatesStrategy = DuplicatesStrategy.FAIL
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+47
-2
@@ -3,6 +3,8 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalWasmDsl::class)
|
||||
|
||||
package org.jetbrains.kotlin.gradle.unitTests
|
||||
|
||||
import com.android.build.gradle.LibraryExtension
|
||||
@@ -15,10 +17,10 @@ import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublication
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resourcesPublicationExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.jetbrains.kotlin.gradle.util.assertContainsDiagnostic
|
||||
import org.jetbrains.kotlin.gradle.util.assertNoDiagnostics
|
||||
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||
import org.jetbrains.kotlin.gradle.util.kotlin
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
@@ -119,6 +121,49 @@ class KotlinTargetResourcesPublicationImplTests {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test targets that can publish resources`() {
|
||||
buildProjectWithMPP {
|
||||
plugins.apply("com.android.library")
|
||||
enableMppResourcesPublication(true)
|
||||
kotlin {
|
||||
listOf(
|
||||
androidTarget(),
|
||||
jvm(),
|
||||
wasmJs(),
|
||||
wasmWasi(),
|
||||
linuxArm64(),
|
||||
iosArm64(),
|
||||
).forEach { target ->
|
||||
assert(
|
||||
resourcesPublicationExtension!!.canPublishResources(target),
|
||||
{ target }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test targets that can resolve resources`() {
|
||||
buildProjectWithMPP {
|
||||
enableMppResourcesPublication(true)
|
||||
kotlin {
|
||||
listOf(
|
||||
wasmJs(),
|
||||
wasmWasi(),
|
||||
linuxArm64(),
|
||||
iosArm64(),
|
||||
).forEach { target ->
|
||||
assert(
|
||||
resourcesPublicationExtension!!.canResolveResources(target),
|
||||
{ target }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun testCallbacksAfterApiCall(
|
||||
callback: ((Unit) -> Unit) -> Unit,
|
||||
apiCall: (Unit) -> Unit,
|
||||
|
||||
Reference in New Issue
Block a user